diff options
author | prathamesh | 2020-09-08 02:49:24 +0530 |
---|---|---|
committer | prathamesh | 2020-09-08 02:49:24 +0530 |
commit | 44b64f9ad0f0618d15ee99026a33df14937d3ef4 (patch) | |
tree | 97b40b2f4f4dc04cc81c42e965331477d6bc2c46 /yaksh | |
parent | 9569e3ef6bbaeb8b36ad78c272006a538e044894 (diff) | |
download | online_test-44b64f9ad0f0618d15ee99026a33df14937d3ef4.tar.gz online_test-44b64f9ad0f0618d15ee99026a33df14937d3ef4.tar.bz2 online_test-44b64f9ad0f0618d15ee99026a33df14937d3ef4.zip |
Provide additional attempt to a selected student or extend time.
Diffstat (limited to 'yaksh')
-rw-r--r-- | yaksh/models.py | 127 | ||||
-rw-r--r-- | yaksh/templates/yaksh/micromanaged.html | 22 | ||||
-rw-r--r-- | yaksh/templates/yaksh/micromonitor.html | 9 | ||||
-rw-r--r-- | yaksh/templates/yaksh/monitor.html | 31 | ||||
-rw-r--r-- | yaksh/templates/yaksh/quit.html | 4 | ||||
-rw-r--r-- | yaksh/templates/yaksh/quizzes_user.html | 2 | ||||
-rw-r--r-- | yaksh/templatetags/custom_filters.py | 20 | ||||
-rw-r--r-- | yaksh/test_models.py | 141 | ||||
-rw-r--r-- | yaksh/urls.py | 9 | ||||
-rw-r--r-- | yaksh/views.py | 135 |
10 files changed, 491 insertions, 9 deletions
diff --git a/yaksh/models.py b/yaksh/models.py index 1094bb0..84cad1e 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -1045,6 +1045,14 @@ class Course(models.Model): def get_learning_modules(self): return self.learning_module.order_by("order") + def get_learning_module(self, quiz): + modules = self.get_learning_modules() + for module in modules: + for unit in module.get_learning_units(): + if unit.quiz == quiz: + break + return module + def get_unit_completion_status(self, module, user, unit): course_module = self.learning_module.get(id=module.id) learning_unit = course_module.learning_unit.get(id=unit.id) @@ -1776,7 +1784,7 @@ class QuestionPaper(models.Model): all_questions = questions return all_questions - def make_answerpaper(self, user, ip, attempt_num, course_id): + def make_answerpaper(self, user, ip, attempt_num, course_id, special=False): """Creates an answer paper for the user to attempt the quiz""" try: ans_paper = AnswerPaper.objects.get(user=user, @@ -1795,6 +1803,7 @@ class QuestionPaper(models.Model): ans_paper.end_time = ans_paper.start_time + \ timedelta(minutes=self.quiz.duration) ans_paper.question_paper = self + ans_paper.is_special = special ans_paper.save() questions = self._get_questions_for_answerpaper() ans_paper.questions.add(*questions) @@ -2139,6 +2148,10 @@ class AnswerPaper(models.Model): # set question order questions_order = models.TextField(blank=True, default='') + extra_time = models.FloatField('Additional time in mins', default=0.0) + + is_special = models.BooleanField(default=False) + objects = AnswerPaperManager() class Meta: @@ -2221,11 +2234,16 @@ class AnswerPaper(models.Model): questions = list(self.questions.all()) return questions + def set_extra_time(self, time=0): + self.extra_time = time + self.save() + def time_left(self): """Return the time remaining for the user in seconds.""" secs = self._get_total_seconds() + extra_time = self.extra_time * 60 total = self.question_paper.quiz.duration*60.0 - remain = max(total - secs, 0) + remain = max(total - (secs - extra_time), 0) return int(remain) def time_left_on_question(self, question): @@ -2710,3 +2728,108 @@ class Comment(ForumBase): def __str__(self): return 'Comment by {0}: {1}'.format(self.creator.username, self.post_field.title) + + +class MicroManager(models.Model): + manager = models.ForeignKey(User, on_delete=models.CASCADE, + related_name='micromanaging', null=True) + student = models.ForeignKey(User, on_delete=models.CASCADE, + related_name='micromanaged') + course = models.ForeignKey(Course, on_delete=models.CASCADE) + quiz = models.ForeignKey(Quiz, on_delete=models.CASCADE, null=True) + special_attempt = models.BooleanField(default=False) + attempts_permitted = models.IntegerField(default=0) + permitted_time = models.DateTimeField(default=timezone.now) + attempts_utilised = models.IntegerField(default=0) + wait_time = models.IntegerField('Days to wait before special attempt', + default=0) + attempt_valid_for = models.IntegerField('Validity days', default=90) + + class Meta: + unique_together = ('student', 'course', 'quiz') + + def set_wait_time(self, days=0): + self.wait_time = days + self.save() + + def increment_attempts_permitted(self): + self.attempts_permitted += 1 + self.save() + + def update_permitted_time(self, permit_time=None): + time_now = timezone.now() + self.permitted_time = time_now if not permit_time else permit_time + self.save() + + def has_student_attempts_exhausted(self): + if self.quiz.attempts_allowed == -1: + return False + question_paper = self.quiz.questionpaper_set.first() + attempts = AnswerPaper.objects.get_total_attempt( + question_paper, self.student, course_id=self.course.id + ) + last_attempt = AnswerPaper.objects.get_user_last_attempt( + question_paper, self.student, self.course.id + ) + if last_attempt: + if last_attempt.is_attempt_inprogress(): + return False + return attempts >= self.quiz.attempts_allowed + + def is_last_attempt_inprogress(self): + question_paper = self.quiz.questionpaper_set.first() + last_attempt = AnswerPaper.objects.get_user_last_attempt( + question_paper, self.student, self.course.id + ) + if last_attempt: + return last_attempt.is_attempt_inprogress() + return False + + def has_quiz_time_exhausted(self): + return not self.quiz.active or self.quiz.is_expired() + + def is_course_exhausted(self): + return not self.course.active or not self.course.is_active_enrollment() + + def is_special_attempt_required(self): + return (self.has_student_attempts_exhausted() or + self.has_quiz_time_exhausted() or self.is_course_exhausted()) + + def allow_special_attempt(self, wait_time=0): + if (self.is_special_attempt_required() and + not self.is_last_attempt_inprogress()): + self.special_attempt = True + if self.attempts_utilised >= self.attempts_permitted: + self.increment_attempts_permitted() + self.update_permitted_time() + self.set_wait_time(days=wait_time) + self.save() + + def has_special_attempt(self): + return (self.special_attempt and + (self.attempts_utilised < self.attempts_permitted)) + + def is_attempt_time_valid(self): + permit_time = self.permitted_time + wait_time = permit_time + timezone.timedelta(days=self.wait_time) + valid_time = permit_time + timezone.timedelta( + days=self.attempt_valid_for) + return wait_time <= timezone.now() <= valid_time + + def can_student_attempt(self): + return self.has_special_attempt() and self.is_attempt_time_valid() + + def get_attempt_number(self): + return self.quiz.attempts_allowed + self.attempts_utilised + 1 + + def increment_attempts_utilised(self): + self.attempts_utilised += 1 + self.save() + + def revoke_special_attempt(self): + self.special_attempt = False + self.save() + + def __str__(self): + return 'MicroManager for {0} - {1}'.format(self.student.username, + self.course.name) diff --git a/yaksh/templates/yaksh/micromanaged.html b/yaksh/templates/yaksh/micromanaged.html new file mode 100644 index 0000000..336feec --- /dev/null +++ b/yaksh/templates/yaksh/micromanaged.html @@ -0,0 +1,22 @@ +{% if micromanagers %} +<hr> +<div class="row"> + {% for micromanager in micromanagers %} + {% if micromanager.attempts_permitted > 0 %} + <div class="col-md-8"> + <p> You have been given a special attempt to the {{ micromanager.quiz.description }} by the course creator</p> + </div> + <div class="col-md-3"> + {% if micromanager.can_student_attempt %} + <a class="btn btn-success" href="{% url 'yaksh:special_start' micromanager.id %}"> + Start Special Attempt + </a> + {% else %} + <span class="badge badge-secondary">Exhausted</span> + {% endif %} + </div> + {% endif %} + {% endfor %} +{% endif %} +</div> + diff --git a/yaksh/templates/yaksh/micromonitor.html b/yaksh/templates/yaksh/micromonitor.html new file mode 100644 index 0000000..cc059aa --- /dev/null +++ b/yaksh/templates/yaksh/micromonitor.html @@ -0,0 +1,9 @@ +{% if micromanager %} + {% if micromanager.can_student_attempt %} + <a class="btn btn-danger" href="{% url 'yaksh:revoke_special_attempt' micromanager.id %}">Revoke</a> + {% else %} + <a class="btn btn-success" href="{% url 'yaksh:allow_special_attempt' user_id course_id quiz_id %}">Allow </a> + {% endif %} +{% else %} + <a class="btn btn-success" href="{% url 'yaksh:allow_special_attempt' user_id course_id quiz_id %}">Allow </a> +{% endif %} diff --git a/yaksh/templates/yaksh/monitor.html b/yaksh/templates/yaksh/monitor.html index ef7b033..183ba99 100644 --- a/yaksh/templates/yaksh/monitor.html +++ b/yaksh/templates/yaksh/monitor.html @@ -74,6 +74,18 @@ $(document).ready(function() </div> </div> <br> + <br> + {% if messages %} + {% for message in messages %} + <div class="alert alert-dismissible alert-{{ message.tags }}"> + <button type="button" class="close" data-dismiss="alert"> + <i class="fa fa-close"></i> + </button> + <strong>{{ message }}</strong> + </div> + {% endfor %} + {% endif %} + <br> <div class="row"> <div class="col-md-4"> <a href="{% url 'yaksh:show_statistics' papers.0.question_paper.id course.id %}" class="btn btn-primary"> @@ -102,8 +114,9 @@ $(document).ready(function() <th> Institute <i class="fa fa-sort"></i> </th> <th> Marks <i class="fa fa-sort"></i> </th> <th> Attempts <i class="fa fa-sort"></i> </th> - <th> Time <i class="fa fa-sort"></i> </th> + <th> Time Left <i class="fa fa-sort"></i> </th> <th> Status <i class="fa fa-sort"></i> </th> + <th> Special Attempt <i class="fa fa-sort"></i> </th> </tr> </thead> <tbody> @@ -118,7 +131,20 @@ $(document).ready(function() <td> {{ paper.marks_obtained }} </td> <td> {{ paper.answers.count }} </td> <td id="time_left{{forloop.counter0}}"> {{ paper.time_left }} </td> - <td id="status{{forloop.counter0}}">{{ paper.status }}</td> + <td> {% if paper.is_attempt_inprogress %} + <form method="post" action="{% url 'yaksh:extend_time' paper.id %}"> + {% csrf_token %} + <div class="form-group"> + <label for="extra_time"> Time in mins </label> + <input type="number" class="form-control" id="extra_time" name="extra_time" required> + </div> + <button type="submit" class="btn btn-primary">Extend Time</button> + </form> + {% else %} + <span class="badge badge-secondary"> Completed </span> + {% endif %} + </td> + <td>{% specail_attempt_monitor paper.user.id course.id quiz.id %}</td> </tr> {% endfor %} </tbody> @@ -126,7 +152,6 @@ $(document).ready(function() <!-- CSV Modal --> <div class="modal fade" id="csvModal" role="dialog"> <div class="modal-dialog"> - <!-- Modal content--> <div class="modal-content"> <div class="modal-header"> diff --git a/yaksh/templates/yaksh/quit.html b/yaksh/templates/yaksh/quit.html index ccb0893..a801ea8 100644 --- a/yaksh/templates/yaksh/quit.html +++ b/yaksh/templates/yaksh/quit.html @@ -56,7 +56,11 @@ {% csrf_token %} <center> <button class="btn btn-outline-success btn-lg" type="submit" name="yes">Yes</button> + {% if paper.is_special %} + <a class="btn btn-outline-danger btn-lg" name="no" href="{% url 'yaksh:skip_question' paper.questions.first.id paper.attempt_number module_id paper.question_paper.id course_id %}">No</a> + {% else %} <a class="btn btn-outline-danger btn-lg" name="no" href="{% url 'yaksh:start_quiz' paper.attempt_number module_id paper.question_paper.id course_id %}">No</a> + {% endif %} </center> </form> {% endblock content %} diff --git a/yaksh/templates/yaksh/quizzes_user.html b/yaksh/templates/yaksh/quizzes_user.html index a9f5a43..e28cb69 100644 --- a/yaksh/templates/yaksh/quizzes_user.html +++ b/yaksh/templates/yaksh/quizzes_user.html @@ -1,4 +1,5 @@ {% extends "user.html" %} +{% load custom_filters %} {% block title %} Student Dashboard {% endblock %} {% block script %} @@ -104,6 +105,7 @@ {% endif %} </div> </div> + {% show_special_attempt user.id course.data.id %} </div> <div id="collapse{{course.data.id}}" class="collapse hide" data-parent="#accordion"> <div class="card-body"> diff --git a/yaksh/templatetags/custom_filters.py b/yaksh/templatetags/custom_filters.py index cdbf4d0..2a01787 100644 --- a/yaksh/templatetags/custom_filters.py +++ b/yaksh/templatetags/custom_filters.py @@ -10,6 +10,7 @@ except ImportError: from pygments import highlight from pygments.lexers import get_lexer_by_name from pygments.formatters import HtmlFormatter +from yaksh.models import User, Course, Quiz register = template.Library() @@ -145,3 +146,22 @@ def to_float(text): @register.filter(name="to_str") def to_str(text): return text.decode("utf-8") + + +@register.inclusion_tag('yaksh/micromanaged.html') +def show_special_attempt(user_id, course_id): + user = User.objects.get(pk=user_id) + micromanagers = user.micromanaged.filter(course_id=course_id) + context = {'micromanagers': micromanagers} + return context + + +@register.inclusion_tag('yaksh/micromonitor.html') +def specail_attempt_monitor(user_id, course_id, quiz_id): + user = User.objects.get(pk=user_id) + micromanagers = user.micromanaged.filter(course_id=course_id, + quiz_id=quiz_id) + context = {'user_id': user_id, 'course_id': course_id, 'quiz_id': quiz_id} + if micromanagers.exists(): + context['micromanager'] = micromanagers.first() + return context diff --git a/yaksh/test_models.py b/yaksh/test_models.py index a77c8bf..e24a38e 100644 --- a/yaksh/test_models.py +++ b/yaksh/test_models.py @@ -5,7 +5,7 @@ from yaksh.models import User, Profile, Question, Quiz, QuestionPaper,\ QuestionSet, AnswerPaper, Answer, Course, StandardTestCase,\ StdIOBasedTestCase, FileUpload, McqTestCase, AssignmentUpload,\ LearningModule, LearningUnit, Lesson, LessonFile, CourseStatus, \ - create_group, legend_display_types, Post, Comment + create_group, legend_display_types, Post, Comment, MicroManager from yaksh.code_server import ( ServerPool, get_result as get_result_from_code_server ) @@ -103,7 +103,8 @@ def setUpModule(): course.save() LessonFile.objects.create(lesson=lesson) CourseStatus.objects.create(course=course, user=course_user) - + MicroManager.objects.create(manager=user, course=course, quiz=quiz, + student=course_user) def tearDownModule(): User.objects.all().delete() @@ -116,6 +117,7 @@ def tearDownModule(): LearningUnit.objects.all().delete() LearningModule.objects.all().delete() AnswerPaper.objects.all().delete() + MicroManager.objects.all().delete() Group.objects.all().delete() @@ -129,6 +131,141 @@ class GlobalMethodsTestCases(unittest.TestCase): ############################################################################### +class MicroManagerTestCase(unittest.TestCase): + def setUp(self): + self.micromanager = MicroManager.objects.first() + self.course = self.micromanager.course + quiz = self.micromanager.quiz + self.questionpaper = QuestionPaper.objects.create(quiz=quiz) + question = Question.objects.get(summary='Q1') + self.questionpaper.fixed_questions.add(question) + self.questionpaper.update_total_marks() + self.student = User.objects.get(username='course_user') + + def tearDown(self): + self.questionpaper.delete() + + def test_micromanager(self): + # Given + user = User.objects.get(username='creator') + course = Course.objects.get(name='Python Course', creator=user) + quiz = Quiz.objects.get(description='demo quiz 1') + student = User.objects.get(username='course_user') + + # When + micromanager = MicroManager.objects.first() + + # Then + self.assertIsNotNone(micromanager) + self.assertEqual(micromanager.manager, user) + self.assertEqual(micromanager.student, student) + self.assertEqual(micromanager.course, course) + self.assertEqual(micromanager.quiz, quiz) + self.assertFalse(micromanager.special_attempt) + self.assertEqual(micromanager.attempts_permitted, 0) + self.assertEqual(micromanager.attempts_utilised, 0) + self.assertEqual(micromanager.wait_time, 0) + self.assertEqual(micromanager.attempt_valid_for, 90) + self.assertEqual(user.micromanaging.first(), micromanager) + self.assertEqual(student.micromanaged.first(), micromanager) + + def test_set_wait_time(self): + # Given + micromanager = self.micromanager + + # When + micromanager.set_wait_time(days=2) + + # Then + self.assertEqual(micromanager.wait_time, 2) + + def self_increment_attempts_permitted(self): + # Given + micromanager = self.micromanager + + # When + micromanager.increment_attempts_permitted() + + # Then + self.assertEqual(micromanager.attempts_permitted, 1) + + def test_update_permitted_time(self): + # Given + micromanager = self.micromanager + permit_time = timezone.now() + + # When + micromanager.update_permitted_time(permit_time) + + # Then + self.assertEqual(micromanager.permitted_time, permit_time) + + def test_has_student_attempts_exhausted(self): + # Given + micromanager = self.micromanager + + # Then + self.assertFalse(micromanager.has_student_attempts_exhausted()) + + def test_has_quiz_time_exhausted(self): + # Given + micromanager = self.micromanager + + # Then + self.assertFalse(micromanager.has_quiz_time_exhausted()) + + def test_is_special_attempt_required(self): + # Given + micromanager = self.micromanager + attempt = 1 + ip = '127.0.0.1' + + # Then + self.assertFalse(micromanager.is_special_attempt_required()) + + # When + answerpaper = self.questionpaper.make_answerpaper(self.student, ip, + attempt, + self.course.id) + answerpaper.update_marks(state='completed') + + # Then + self.assertTrue(micromanager.is_special_attempt_required()) + + answerpaper.delete() + + def test_allow_special_attempt(self): + # Given + micromanager = self.micromanager + + # When + micromanager.allow_special_attempt() + + # Then + self.assertFalse(micromanager.special_attempt) + + def test_has_special_attempt(self): + # Given + micromanager = self.micromanager + + # Then + self.assertFalse(micromanager.has_special_attempt()) + + def test_is_attempt_time_valid(self): + # Given + micromanager = self.micromanager + + # Then + self.assertTrue(micromanager.is_attempt_time_valid()) + + def test_can_student_attempt(self): + # Given + micromanager = self.micromanager + + # Then + self.assertFalse(micromanager.can_student_attempt()) + + class LessonTestCases(unittest.TestCase): def setUp(self): self.lesson = Lesson.objects.get(name='L1') diff --git a/yaksh/urls.py b/yaksh/urls.py index 0639b25..13e46fc 100644 --- a/yaksh/urls.py +++ b/yaksh/urls.py @@ -237,4 +237,13 @@ urlpatterns = [ views.mark_notification, name="mark_notification"), path('mark/notifications', views.mark_notification, name="mark_notification"), + url(r'^manage/micromanager/allow_special_attempt/(?P<user_id>\d+)/' + '(?P<course_id>\d+)/(?P<quiz_id>\d+)/$', + views.allow_special_attempt, name='allow_special_attempt'), + url(r'^micromanager/special_start/(?P<micromanager_id>\d+)/$', + views.special_start, name='special_start'), + url(r'^manage/micromanager/special_revoke/(?P<micromanager_id>\d+)/$', + views.revoke_special_attempt, name='revoke_special_attempt'), + url(r'^manage/extend_time/(?P<paper_id>\d+)/$', + views.extend_time, name='extend_time'), ] diff --git a/yaksh/views.py b/yaksh/views.py index 8413889..01f5e4e 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -37,7 +37,8 @@ from yaksh.models import ( QuestionPaper, QuestionSet, Quiz, Question, StandardTestCase, StdIOBasedTestCase, StringTestCase, TestCase, User, get_model_class, FIXTURES_DIR_PATH, MOD_GROUP_NAME, Lesson, LessonFile, - LearningUnit, LearningModule, CourseStatus, question_types, Post, Comment + LearningUnit, LearningModule, CourseStatus, question_types, Post, Comment, + MicroManager ) from yaksh.forms import ( UserRegisterForm, UserLoginForm, QuizForm, QuestionForm, @@ -483,6 +484,46 @@ def user_login(request): @login_required @email_verified +def special_start(request, micromanager_id=None): + user = request.user + micromanager = get_object_or_404(MicroManager, pk=micromanager_id, + student=user) + course = micromanager.course + quiz = micromanager.quiz + module = course.get_learning_module(quiz) + quest_paper = get_object_or_404(QuestionPaper, quiz=quiz) + + if not course.is_enrolled(user): + msg = 'You are not enrolled in {0} course'.format(course.name) + return quizlist_user(request, msg=msg) + + if not micromanager.can_student_attempt(): + msg = 'Your special attempts are exhausted for {0}'.format( + quiz.description) + return quizlist_user(request, msg=msg) + + last_attempt = AnswerPaper.objects.get_user_last_attempt( + quest_paper, user, course.id) + + if last_attempt: + if last_attempt.is_attempt_inprogress(): + return show_question( + request, last_attempt.current_question(), last_attempt, + course_id=course.id, module_id=module.id, + previous_question=last_attempt.current_question() + ) + + attempt_num = micromanager.get_attempt_number() + ip = request.META['REMOTE_ADDR'] + new_paper = quest_paper.make_answerpaper(user, ip, attempt_num, course.id, + special=True) + micromanager.increment_attempts_utilised() + return show_question(request, new_paper.current_question(), new_paper, + course_id=course.id, module_id=module.id) + + +@login_required +@email_verified def start(request, questionpaper_id=None, attempt_num=None, course_id=None, module_id=None): """Check the user cedentials and if any quiz is available, @@ -643,7 +684,7 @@ def show_question(request, question, paper, error_message=None, request, msg, paper.attempt_number, paper.question_paper.id, course_id=course_id, module_id=module_id ) - if not quiz.active: + if not quiz.active and not paper.is_special: reason = 'The quiz has been deactivated!' return complete( request, reason, paper.attempt_number, paper.question_paper.id, @@ -3449,3 +3490,93 @@ def hide_comment(request, course_id, uuid): comment.active = False comment.save() return redirect('yaksh:post_comments', course_id, post_uid) + + +@login_required +@email_verified +def allow_special_attempt(request, user_id, course_id, quiz_id): + user = request.user + + if not is_moderator(user): + raise Http404('You are not allowed to view this page') + + course = get_object_or_404(Course, pk=course_id) + if not course.is_creator(user) and not course.is_teacher(user): + raise Http404('This course does not belong to you') + + quiz = get_object_or_404(Quiz, pk=quiz_id) + student = get_object_or_404(User, pk=user_id) + + if not course.is_enrolled(student): + raise Http404('The student is not enrolled for this course') + + micromanager, created = MicroManager.objects.get_or_create( + course=course, student=student, quiz=quiz + ) + micromanager.manager = user + micromanager.save() + + if (not micromanager.is_special_attempt_required() or + micromanager.is_last_attempt_inprogress()): + name = student.get_full_name() + msg = '{} can attempt normally. No special attempt required!'.format( + name) + elif micromanager.can_student_attempt(): + msg = '{} already has a special attempt!'.format( + student.get_full_name()) + else: + micromanager.allow_special_attempt() + msg = 'A special attempt is provided to {}!'.format( + student.get_full_name()) + + messages.info(request, msg) + return my_redirect('/exam/manage/monitor/{0}/{1}/'.format(quiz_id, + course_id)) + + +@login_required +@email_verified +def revoke_special_attempt(request, micromanager_id): + user = request.user + + if not is_moderator(user): + raise Http404('You are not allowed to view this page') + + micromanager = get_object_or_404(MicroManager, pk=micromanager_id) + course = micromanager.course + if not course.is_creator(user) and not course.is_teacher(user): + raise Http404('This course does not belong to you') + micromanager.revoke_special_attempt() + msg = 'Revoked special attempt for {}'.format( + micromanager.student.get_full_name()) + messages.info(request, msg) + return my_redirect('/exam/manage/monitor/{0}/{1}/'.format( + micromanager.quiz.id, course.id)) + + +@login_required +@email_verified +def extend_time(request, paper_id): + user = request.user + + if not is_moderator(user): + raise Http404('You are not allowed to view this page') + + anspaper = get_object_or_404(AnswerPaper, pk=paper_id) + course = anspaper.course + if not course.is_creator(user) and not course.is_teacher(user): + raise Http404('This course does not belong to you') + + if request.method == "POST": + extra_time = request.POST.get('extra_time', None) + if extra_time is None: + msg = 'Please provide time' + else: + anspaper.set_extra_time(extra_time) + msg = 'Extra {0} minutes given to {1}'.format( + extra_time, anspaper.user.get_full_name()) + else: + msg = 'Bad Request' + messages.info(request, msg) + return my_redirect('/exam/manage/monitor/{0}/{1}/'.format( + anspaper.question_paper.quiz.id, course.id)) |