def get_student_reputation(req): """ Returns the student information along with the convincing rationales criterion. Parameters ---------- req : HttpRequest Request with: parameters: id: int Student pk Returns ------- Either JSONResponse Response with json data: { email : str Student email last_login : str Date of last login in isoformat popularity : float Value of the convincing rationales criterion } HttpResponse Error response """ args = get_json_params(req, args=["id"]) if isinstance(args, HttpResponse): return args (id_,), _ = args try: student = Student.objects.get(pk=id_) except Student.DoesNotExist: return response_400( req, msg=_("The student couldn't be found."), logger_msg=( "The student with pk {} couldn't be found.".format(id_) ), log=logger.warning, ) criteria = { c.name: student.evaluate_reputation(c.name) for c in ReputationType.objects.get(type="student").criteria.all() } return JsonResponse( { "email": student.student.email, "last_login": student.student.last_login.isoformat() if student.student.last_login is not None else None, "criteria": criteria, } )
def remove_gradebook_task(req, teacher): """ Removes the failed gradebook task from the running tasks. Parameters ---------- req : HttpRequest Request with: parameters: task_id: str Id of the celery task responsible for the gradebook generation sent with the first request for a gradebook teacher : Teacher Teacher instance returned by `teacher_required` (not used) Returns ------- HttpResponse Empty 200 response """ args = get_json_params(req, args=["task_id"]) if isinstance(args, HttpResponse): return args (task_id, ), _ = args try: task = RunningTask.objects.get(id=task_id) except RunningTask.DoesNotExist: return HttpResponse("") task.delete() return HttpResponse("")
def teacher_reputation(req): args = get_json_params(req, args=["id"]) if isinstance(args, HttpResponse): return args (teacher_id, ), __ = args try: teacher = Teacher.objects.get(pk=teacher_id) except (Teacher.DoesNotExist, AttributeError): return response_400( req, msg=_("This teacher doesn't exist."), logger_msg=( "Tried to obtain teacher with pk {}".format(teacher_id)), log=logger.warning, ) if teacher.reputation is None: teacher.reputation = Reputation.create(teacher) teacher.save() reputation, reputations = teacher.reputation.evaluate() data = {"reputation": reputation, "reputations": reputations} return JsonResponse(data, status=200)
def test_get_json_params__missing_arg(rf): data = {"arg1": 1} req = rf.post("/test", json.dumps(data), content_type="application/json") args = get_json_params(req, args=["arg1", "arg2"]) assert isinstance(args, HttpResponse)
def test_get_json_params__wrong_data(rf): data = {"arg1": 1, "arg2": 2} req = rf.post("/test", data) args = get_json_params(req, args=["arg1", "arg2"]) assert isinstance(args, HttpResponse)
def collection_add_assignment(request, teacher): """ creates a collection with assignments from a student group used in group detail view """ args = get_json_params(request, args=["group_pk"]) if isinstance(args, HttpResponse): return args (group_pk,), _ = args student_group = get_object_or_404(StudentGroup, pk=group_pk) title = (student_group.title + "'s curriculum")[:40] description = ( "This collection contains all assignments that have been assigned to " + student_group.title + "'s students." )[:200] collection = Collection.objects.create( discipline=teacher.disciplines.first(), owner=teacher, title=title, description=description, ) student_group_assignments = student_group.studentgroupassignment_set.all() for assignment in student_group_assignments: if assignment.assignment not in collection.assignments.all(): collection.assignments.add(assignment.assignment) return JsonResponse({"pk": collection.pk})
def student_reputation(req): args = get_json_params(req, args=["id"]) if isinstance(args, HttpResponse): return args (student_id, ), __ = args if req.user.student.pk != student_id: return response_403( req, msg=_("You don't have access to this resource."), logger_msg=( "Access to reputation of student {} from student {}.".format( student_id, req.user.student.pk)), log=logger.warning, ) try: student = Student.objects.get(pk=student_id) except Student.DoesNotExist: return response_400( req, msg=_("This student doesn't exist."), logger_msg=( "Tried to obtain student with pk {}".format(student_id)), log=logger.warning, ) if student.reputation is None: student.reputation = Reputation.create(student) student.save() reputation, reputations = student.reputation.evaluate() data = {"reputation": reputation, "reputations": reputations} return JsonResponse(data, status=200)
def collections(req, teacher): """ View that returns featured collections in the teacher's disciplines. Parameters ---------- req : HttpRequest Request with: optional parameters: n: int (default : 5) Number of questions to return teacher : Teacher Teacher instance returned by `teacher_required` Returns ------- JsonResponse Response with json data: { "collections": [ { title : str Collection title discipline : str Collection discipline n_assignments : int Number of assignments in collection n_followers : str Number of followers for the collection } ] } """ args = get_json_params(req, opt_args=["n"]) if isinstance(args, HttpResponse): return args _, (n, ) = args if n is None: n = 5 data = { "collections": [{ "title": collection.title, "description": collection.description, "discipline": collection.discipline.title, "n_assignments": collection.assignments.count(), "n_followers": collection.n_followers, } for collection in Collection.objects.filter( discipline__in=teacher.disciplines.all()).annotate( n_followers=models.Count("followers")).order_by( "-n_followers").all()[:n]] } return JsonResponse(data)
def remove_dalite_message(req, teacher): args = get_json_params(req, args=["id"]) if isinstance(args, HttpResponse): return args (id_, ), _ = args try: message = UserMessage.objects.get(pk=id_) message.showing = False message.save() except UserMessage.DoesNotExist: pass return HttpResponse("")
def get_gradebook_task_result(req, teacher): """ Returns a 200 response if the gradebook is ready. If not, will return a 202 response. Parameters ---------- req : HttpRequest Request with: parameters: task_id: str Id of the celery task responsible for the gradebook generation sent with the first request for a gradebook teacher : Teacher Teacher instance returned by `teacher_required` (not used) Returns ------- HttpResponse Either Empty 200 response (task done) Empty 202 response (accepted, still processing) Empty 500 response (error) """ args = get_json_params(req, args=["task_id"]) if isinstance(args, HttpResponse): return args (task_id, ), _ = args result = AsyncResult(task_id) try: if result.ready(): return HttpResponse("", status=200) else: return HttpResponse("", status=202) except AttributeError: return response_500( req, msg="", logger_msg="Error computing gradebook for teacher {}".format( teacher.user.username) + " and task {}.".format(task_id), log=logger.warning, use_template=False, )
def test_get_json_params(rf): data = {"arg1": 1, "arg2": 2, "opt_arg1": 3, "opt_arg2": 4} req = rf.post("/test", json.dumps(data), content_type="application/json") args = get_json_params( req, args=["arg1", "arg2"], opt_args=["opt_arg1", "opt_arg2", "opt_arg3"], ) assert not isinstance(args, HttpResponse) args, opt_args = args assert data["arg1"] == args[0] assert data["arg2"] == args[1] assert data["opt_arg1"] == opt_args[0] assert data["opt_arg2"] == opt_args[1] assert opt_args[2] is None
def reputation(req): args = get_json_params(req, args=["reputation_type"]) if isinstance(args, HttpResponse): return args (reputation_type, ), __ = args if reputation_type == "teacher": return teacher_reputation(req) if reputation_type == "student": return student_reputation(req) else: return response_400( req, msg=_("This isn't a supported reputation type."), logger_msg=("The sent data used reputation type {} ".format( reputation_type) + "which isn't supported."), log=logger.warning, )
def unsubscribe_from_thread(req, teacher): """ Unsubscribes the `teacher` from a thread (won't appear in the messages). Parameters ---------- req : HttpRequest Request with: parameters: id: int Thread primary key teacher : Teacher Teacher instance returned by `teacher_required` Returns ------- HttpResponse Error response or empty 200 response """ args = get_json_params(req, args=["id"]) if isinstance(args, HttpResponse): return args (id_, ), _ = args try: thread = ForumThread.objects.get(pk=id_) except ForumThread.DoesNotExist: return response_400( req, msg=translate("The thread couldn't be found."), logger_msg=( "The thread with pk {} couldn't be found.".format(id_)), log=logger.warning, ) thread.subscriptions.filter(user=teacher.user).delete() return HttpResponse("")
def flag_question(req, teacher): args = get_json_params(req, args=["id", "reason"]) if isinstance(args, HttpResponse): return args (question_id, reason), _ = args try: question = Question.objects.get(id=question_id) except Question.DoesNotExist: return response_400( req, msg=translate("The question couldn't be found."), logger_msg=("The question with pk {} couldn't be found.".format( question_id)), log=logger.warning, ) try: flag_reason = QuestionFlagReason.objects.get(title=reason) except Question.DoesNotExist: return response_400( req, msg=translate("The flag reason couldn't be found."), logger_msg=( "The question flag reason with title {} ".format(reason) + "couldn't be found."), log=logger.warning, ) flag = QuestionFlag.objects.create(question=question, user=teacher.user, flag=True) flag.flag_reason.add(flag_reason) logger.info("Question flagged!") return HttpResponse("")
def mark_message_read(req, teacher): """ Unsubscribes the `teacher` from a thread (won't appear in the messages). Parameters ---------- req : HttpRequest Request with: optional parameters: id: int Thread primary key teacher : Teacher Teacher instance returned by `teacher_required` Returns ------- HttpResponse Error response or empty 200 response """ args = get_json_params(req, opt_args=["id"]) if isinstance(args, HttpResponse): return args _, (id_, ) = args notification_type = ContentType.objects.get(app_label="pinax_forums", model="ThreadSubscription") if id_ is None: TeacherNotification.objects.filter( teacher=teacher, notification_type=notification_type).delete() else: TeacherNotification.objects.filter(teacher=teacher, notification_type=notification_type, object_id=id_).delete() return HttpResponse("")
def evaluate_rationale(req, teacher): """ Add the `teacher`'s evaluation for a rationale. Parameters ---------- req : HttpRequest Request with: parameters: id: int Primary key of the rationale score: int Given score teacher : Teacher Teacher instance returned by `teacher_required` Returns ------- HttpResponse Error response or empty 200 response """ if req.META["CONTENT_TYPE"] == "application/json": args = get_json_params(req, args=["id", "score"], opt_args=["redirect"]) if isinstance(args, HttpResponse): return args (id_, score), (redirect_, ) = args if redirect_ is None: redirect_ = True else: id_ = req.POST.get("id", None) score = req.POST.get("score", None) redirect_ = True if id_ is None or score is None: return response_400( req, msg=translate("Missing parameters."), logger_msg=("Score and/or ID are missing from request."), log=logger.warning, ) score = int(score) if score not in range(0, 4): return response_400( req, msg=translate("The score wasn't in a valid range."), logger_msg=("The score wasn't valid; was {}.".format(score)), log=logger.warning, ) try: answer = Answer.objects.get(id=id_) except Answer.DoesNotExist: return response_400( req, msg=translate("Unkown answer id sent."), logger_msg=("No answer could be found for pk {}.".format(id_)), log=logger.warning, ) if AnswerAnnotation.objects.filter(answer=answer, annotator=teacher.user).exists(): annotation = AnswerAnnotation.objects.get(answer=answer, annotator=teacher.user) annotation.score = score annotation.save() else: AnswerAnnotation.objects.create(answer=answer, annotator=teacher.user, score=score) if redirect_: return redirect(reverse("teacher-dashboard--rationales")) else: return HttpResponse("")
def download_gradebook(req, teacher, results=None): """ Download the wanted gradebook. Parameters ---------- req : HttpRequest Request with: parameters: task_id: str Id of the celery task responsible for the gradebook generation sent with the first request for a gradebook teacher : Teacher Teacher instance returned by `teacher_required` (not used) results : Optional[Dict[str, Any]] Either If group gradebook { group: str Title of the group assignments: List[str] Assignment identifier school_id_needed: bool If a school id is needed results: [{ school_id: Optional[str] School id if needed email: str Student email assignments: [{ n_completed: Optional[int] Number of completed questions n_correct: Optional[int] Number of correct questions }] }] } If assignment gradebook { group: str Title of the group assignment: str Title of the assignment questions: List[str] Question title school_id_needed: bool If a school id is needed results: [{ school_id: Optional[str] School id if needed email: str Student email questions: List[Optional[float]] Grade for each question }] } Returns ------- StreamingHttpResponse csv file with the gradebook results """ if results is None: args = get_json_params(req, args=["task_id"]) if isinstance(args, HttpResponse): return args (task_id, ), _ = args result = AsyncResult(task_id) try: if not result.ready(): return response_400( req, msg="The gradebook isn't ready.", logger_msg="Not completed gradebook {}".format(task_id) + " accessed by teacher {}".format(teacher.user.username), ) except AttributeError: return response_500( req, msg="There is no gradebook corresponding to this url. " "Please ask for a new one.", logger_msg="Celery error getting gradebook" " for teacher {}".format(teacher.user.username) + " and task {}.".format(task_id), log=logger.warning, use_template=False, ) results = result.result if RunningTask.objects.filter(id=task_id): RunningTask.objects.get(id=task_id).delete() if "assignment" in results: filename = "myDALITE_gradebook_{}_{}.csv".format( results["group"], results["assignment"]) else: filename = "myDALITE_gradebook_{}.csv".format(results["group"]) gradebook_gen = convert_gradebook_to_csv(results) data = chain(iter((filename + "\n", )), gradebook_gen) resp = StreamingHttpResponse(data, content_type="text/csv") return resp
def request_gradebook(req, teacher): """ Request the generation of a gradebook. An response containing the task id is returned so the client can poll the server for the result until it's ready. Parameters ---------- req : HttpRequest Request with: parameters group_id: int Primary key of the group for which the gradebook is wanted optional parameters: assignment_id: int (default : None) Primary key of the assignment for which the gradebook is wanted teacher : Teacher Teacher instance returned by `teacher_required` Returns ------- Either JsonResponse with json data Response 201 (created) with json data if computation run asynchronously { task_id: str Id corresponding to the celery task for use in polling } Response 200 with json data if computation run synchronously Either If group gradebook wanted { assignments: List[str] Assignment identifier school_id_needed: bool If a school id is needed results: [{ school_id: Optional[str] School id if needed email: str Student email assignments: [{ n_completed: int Number of completed questions n_correct: int Number of correct questions }] }] } If assignment gradebook wanted { questions: List[str] Question title school_id_needed: bool If a school id is needed results: [{ school_id: Optional[str] School id if needed email: str Student email questions: List[float] Grade for each question }] } HttpResponse Error response """ args = get_json_params(req, args=["group_id"], opt_args=["assignment_id"]) if isinstance(args, HttpResponse): return args (group_pk, ), (assignment_pk, ) = args try: group = StudentGroup.objects.get(pk=group_pk) except StudentGroup.DoesNotExist: return response_400( req, msg=translate("The group doesn't exist."), logger_msg=("Access to {} with an invalid group {}.".format( req.path, group_pk)), log=logger.warning, ) if teacher not in group.teacher.all(): return response_403( req, msg=translate( "You don't have access to this resource. You must be " "registered as a teacher for the group."), logger_msg=( "Unauthorized access to group {} from teacher {}.".format( group.pk, teacher.pk)), log=logger.warning, ) if assignment_pk is not None: try: assignment = StudentGroupAssignment.objects.get(pk=assignment_pk) except StudentGroupAssignment.DoesNotExist: return response_400( req, msg=translate("The group or assignment don't exist."), logger_msg=( "Access to {} with an invalid assignment {}.".format( req.path, assignment_pk)), log=logger.warning, ) result = compute_gradebook_async(group_pk, assignment_pk) if assignment_pk is None: description = format_html("gradebook for group <strong>{}</strong>", group.name) else: description = "gradebook for assignment {} and group {}".format( assignment.assignment.identifier, group.name) if isinstance(result, AsyncResult): task = RunningTask.objects.create(id=result.id, description=description, teacher=teacher) data = { "id": task.id, "description": task.description, "completed": False, "datetime": task.datetime.strftime("%Y-%m-%d %H:%M:%S.%f"), } return JsonResponse(data, status=201) else: return download_gradebook(req, results=result)