def _delete_assignments(ids, delete_class): if delete_class: delete_class = ObjectId(delete_class) # Convert all of the IDs we were given to ObjectIDs in one go ids = [ObjectId(i) for i in ids] logger.info("Deleting assignments %s.", str(ids)) # Query the database for all the assignments we are supposed to delete assignments = list(Assignment.objects(id__in = ids)) # Query the database for all the submissions we are supposed to delete, this # will potentially be an absolutely massive list, so we do not want to # place all the results into a list immediately like we did for the # assignments. submissions = Submission.objects(assignment__in = ids) # Delete assignments directory on the filesystem for i in assignments: try: shutil.rmtree( os.path.join(config["SUBMISSION_DIRECTORY"], str(i.id)) ) except OSError as e: # We don't want to explode if the directory has been deleted for us # but it is weird so log a warning. if e.errno == errno.ENOENT: logger.warning("Assignment directory missing for %s", str(i.id)) else: raise # Actually delete the submissions from the database Submission.objects(assignment__in = ids).delete() # Delete the assignments Assignment.objects(id__in = ids).delete() if delete_class: # Unenroll all students in the class User.objects(classes = delete_class).update( pull__classes = delete_class ) # Delete the class Class.objects(id = delete_class).delete()
def _delete_assignments(ids, delete_class): if delete_class: delete_class = ObjectId(delete_class) # Convert all of the IDs we were given to ObjectIDs in one go ids = [ObjectId(i) for i in ids] logger.debug("Deleting assignments %s.", ids) # Query the database for all the assignments we are supposed to delete assignments = list(Assignment.objects(id__in = ids)) # Query the database for all the submissions we are supposed to delete, this # will potentially be an absolutely massive list, so we do not want to # place all the results into a list immediately like we did for the # assignments. submissions = Submission.objects(assignment__in = ids) # Go through all of the submissions and delete the files from the # filesystem. We will tell the database to delete all of the submissions # in one go afterwards. for i in submissions: # Delete the submission on the filesystem. try: shutil.rmtree( os.path.join(config["SUBMISSION_DIRECTORY"], str(i.id)) ) except OSError as e: logger.warn( "Failed to delete submission with id %s: %s", str(i.id), str(e) ) # Actually delete the submissions from the database Submission.objects(assignment__in = ids).delete() # Delete the assignments Assignment.objects(id__in = ids).delete() if delete_class: # Unenroll all students in the class User.objects(classes = delete_class).update( pull__classes = delete_class ) # Delete the class Class.objects(id = delete_class).delete()
def _delete_assignments(ids, delete_class): if delete_class: delete_class = ObjectId(delete_class) # Convert all of the IDs we were given to ObjectIDs in one go ids = [ObjectId(i) for i in ids] logger.debug("Deleting assignments %s.", ids) # Query the database for all the assignments we are supposed to delete assignments = list(Assignment.objects(id__in=ids)) # Query the database for all the submissions we are supposed to delete, this # will potentially be an absolutely massive list, so we do not want to # place all the results into a list immediately like we did for the # assignments. submissions = Submission.objects(assignment__in=ids) # Go through all of the submissions and delete the files from the # filesystem. We will tell the database to delete all of the submissions # in one go afterwards. for i in submissions: # Delete the submission on the filesystem. try: shutil.rmtree( os.path.join(config["SUBMISSION_DIRECTORY"], str(i.id))) except OSError as e: logger.warn("Failed to delete submission with id %s: %s", str(i.id), str(e)) # Actually delete the submissions from the database Submission.objects(assignment__in=ids).delete() # Delete the assignments Assignment.objects(id__in=ids).delete() if delete_class: # Unenroll all students in the class User.objects(classes=delete_class).update(pull__classes=delete_class) # Delete the class Class.objects(id=delete_class).delete()
def browse_assignments(): # Grab all the current user's classes classes = Class.objects(id__in = current_user.classes).only("name") # Get the current time so we don't have to do it over and over again. now = datetime.datetime.today() if "show_all" in request.args: assignments = list(Assignment.objects( Q(for_class__in = current_user.classes) & (Q(hide_until = None) | Q(hide_until__lt = now)) ).only("name", "due", "due_cutoff", "for_class")) else: assignments = list(Assignment.objects( Q(for_class__in = current_user.classes) & (Q(due__gt = now - datetime.timedelta(weeks = 1)) | Q(due_cutoff__gt = now - datetime.timedelta(weeks = 1))) & (Q(hide_until = None) | Q(hide_until__lt = now)) ).only("name", "due", "due_cutoff", "for_class")) assignments = [i for i in assignments if not i.hide_until or i.hide_until < now] # Get the number of assignments that we could have gotten if we didn't # limit based on due date. all_assignments_count = Assignment.objects( Q(for_class__in = current_user.classes) & (Q(hide_until = None) | Q(hide_until__lt = now)) ).count() submissions = list(Submission.objects( user = current_user.email, assignment__in = [i.id for i in assignments], most_recent = True )) # Add a property to all the assignments so the template can display their # respective class easier. Additionally, add a plain text version of the # due date for i in assignments: try: i.class_name = next((j.name for j in classes if j.id == i.for_class)) except StopIteration: logger.error( "Assignment with id %s references non-existant class with id " "%s." % (str(i.id, i.for_class)) ) i.class_name = "DNE" # Figure out the status messages that we want to display to the user. submitted = next((j for j in submissions if j.assignment == i.id), None) i.status = i.status_color = None if submitted: i.status = ( "You made a submission " + create_time_element(submitted.timestamp, now) ) i.status_color = "#84B354" elif now < i.due: i.status = "You have not submitted yet" i.status_color = "#877150" elif now > i.due and i.due_cutoff and now > i.due_cutoff: i.status = "You have not submitted yet, and it is too late to do so" i.status_color = "#E9A400" elif now > i.due: i.status = "You have not submitted yet!" i.status_color = "#FB4313" # Sort the assignments by due_cutoff or due date if due_cutoff is not # assigned. assignments.sort( key = lambda i: i.due_cutoff if i.due_cutoff else i.due, reverse = True ) return render_template( "assignments.html", assignments = assignments, hidden_assignments = -1 if "show_all" in request.args else all_assignments_count - len(assignments), create_time_element = create_time_element )
def browse_assignments(): # Grab all the current user's classes classes = Class.objects(id__in=current_user.classes).only("name") # Get the current time so we don't have to do it over and over again. now = datetime.datetime.today() if "show_all" in request.args: assignments = list( Assignment.objects( Q(for_class__in=current_user.classes) & (Q(hide_until=None) | Q(hide_until__lt=now))).only( "name", "due", "due_cutoff", "for_class")) else: assignments = list( Assignment.objects( Q(for_class__in=current_user.classes) & (Q(due__gt=now - datetime.timedelta(weeks=1)) | Q(due_cutoff__gt=now - datetime.timedelta(weeks=1))) & (Q(hide_until=None) | Q(hide_until__lt=now))).only( "name", "due", "due_cutoff", "for_class")) assignments = [ i for i in assignments if not i.hide_until or i.hide_until < now ] # Get the number of assignments that we could have gotten if we didn't # limit based on due date. all_assignments_count = Assignment.objects( Q(for_class__in=current_user.classes) & (Q(hide_until=None) | Q(hide_until__lt=now))).count() submissions = list( Submission.objects(assignment__in=[i.id for i in assignments], most_recent=True)) # Add a property to all the assignments so the template can display their # respective class easier. Additionally, add a plain text version of the # due date for i in assignments: try: i.class_name = next( (j.name for j in classes if j.id == i.for_class)) except StopIteration: app.logger.error("Assignment with id %s references non-existant " "class with id %s." % (str(i.id, i.for_class))) i.class_name = "DNE" # Figure out the status messages that we want to display to the user. submitted = next((j for j in submissions if j.assignment == i.id), None) i.status = i.status_color = None if submitted: i.status = ("You made a submission " + create_time_element(submitted.timestamp, now)) i.status_color = "#84B354" elif now < i.due: i.status = "You have not submitted yet" i.status_color = "#877150" elif now > i.due and i.due_cutoff and now > i.due_cutoff: i.status = "You have not submitted yet, and it is too late to do so" i.status_color = "#E9A400" elif now > i.due: i.status = "You have not submitted yet!" i.status_color = "#FB4313" # Sort the assignments by due_cutoff or due date if due_cutoff is not # assigned. assignments.sort(key=lambda i: i.due_cutoff if i.due_cutoff else i.due, reverse=True) return render_template("assignments.html", assignments=assignments, hidden_assignments=-1 if "show_all" in request.args else all_assignments_count - len(assignments), create_time_element=create_time_element)
def _create_gradebook_csv(csv_id, requester, class_id, fill=0): csv_id = ObjectId(csv_id) csv_file = temp_directory = "" # Find any expired archives and remove them deleted_files = [] for i in CSV.objects(expires__lt = datetime.datetime.today()): deleted_files.append(i.file_location) if i.file_location: try: os.remove(i.file_location) except OSError as e: logger.warning( "Could not remove expired csv file at %s: %s.", i.file_location, str(e) ) i.delete() if deleted_files: logger.info("Deleted csv files %s.", str(deleted_files)) # This is the CSV object that will be added to the database new_csv = CSV( id = csv_id, requester = requester ) temp_directory = csv_file = None try: # Create the actual csv file. csv_file = open(os.path.join(config["CSV_DIRECTORY"], str(csv_id)), "w") the_class = Class.objects.get(id = ObjectId(class_id)) # Grab all assignments in this class assns = list( Assignment.objects(for_class = the_class.id) ) print >> csv_file, "%s,%s" % \ ("Username", ",".join('"{0}"'.format(i.name) for i in assns)) # Grab all student users for this class. users = list( User.objects( account_type = "student", classes = the_class.id ) ) assn_ids = [i.id for i in assns] for user in users: # Query for user's most recent submissions in the known assignments query = { "assignment__in": assn_ids, "most_recent": True, "user": user.id } submissions = list(Submission.objects(**query)) # Initialize each assignment score to empty at first. assn_to_score = OrderedDict((i, str(fill)) for i in assn_ids) # Go through submissions, associating scores with assignment for sub in submissions: if sub.test_results: test_result = TestResult.objects.get(id = sub.test_results) if test_result.score is not None: assn_to_score[sub.assignment] = str(test_result.score) # Write gradebook results to csv file. print >> csv_file, "%s,%s" % \ (user.email, ",".join(assn_to_score.values())) csv_file.close() new_csv.file_location = os.path.join(config["CSV_DIRECTORY"], str(csv_id)) new_csv.expires = \ datetime.datetime.today() + config["TEACHER_CSV_LIFETIME"] new_csv.save(force_insert = True) except Exception as e: new_csv.file_location = None os.remove(os.path.join(config["CSV_DIRECTORY"], str(csv_id))) new_csv.error_string = str(e) new_csv.save(force_insert = True) raise