From b259e65bbadc62a9368238e778af5c205b32f5f6 Mon Sep 17 00:00:00 2001 From: maheshgudi Date: Mon, 8 Aug 2016 16:07:25 +0530 Subject: made UI changes to courses page and teacher can add another teacher --- yaksh/templates/yaksh/addteacher.html | 11 +++++- yaksh/templates/yaksh/courses.html | 74 ++++++++++++++++++++++++++++++++--- yaksh/urls.py | 1 - yaksh/views.py | 35 +++++++---------- 4 files changed, 93 insertions(+), 28 deletions(-) (limited to 'yaksh') diff --git a/yaksh/templates/yaksh/addteacher.html b/yaksh/templates/yaksh/addteacher.html index 7e04f71..2ab107b 100644 --- a/yaksh/templates/yaksh/addteacher.html +++ b/yaksh/templates/yaksh/addteacher.html @@ -18,6 +18,13 @@

+ +{% if message %} +
+ Sorry! {{message}} +
+{% endif %} +
{% csrf_token %} {% if success == True %} @@ -57,7 +64,9 @@ {% if status == True %}
-
Teacher(s) Added

+
+ Congrats! Following Teachers have been added: +
{% if teachers_added %} {% for teacher in teachers_added %}
diff --git a/yaksh/templates/yaksh/courses.html b/yaksh/templates/yaksh/courses.html index 06c848c..1c68472 100644 --- a/yaksh/templates/yaksh/courses.html +++ b/yaksh/templates/yaksh/courses.html @@ -9,15 +9,12 @@ {% endblock %} {% block manage %} -View Allotted Courses
+ {% if not courses %}

No new Courses added

{% else %}

Course(s) Added

{% for course in courses %} - {% if user != course.creator %} -

{{course.creator.get_full_name}} added you to this course

- {% endif %}
@@ -79,7 +76,74 @@


{% endfor %} + {% endif %} + +{% if allotted_courses %} +

Course(s) Allotted

+ + {% for course in allotted_courses %} +
+
+
+
+

+ Course + {% if course.active %} + Active + {% else %} + Closed + {% endif %} +

+ {{ course.name }} +

+
+
+
Course Creator
+ {{course.creator}} +
Teacher(s) Added to {{ course }}
+ {% if course.get_teachers %} +
+ + {% csrf_token %} + {% for teacher in course.get_teachers %} +
+
+
+  {{ teacher.get_full_name }} +
+
+
+ {% endfor %} + +
+ {% else %} +
No Teacher(s) Added
+ {% endif %} + +
+
+
+ +
+

Quiz(zes)

+ {% if course.get_quizzes %} + {% for quiz in course.get_quizzes %} + {{ quiz.description }}
+ {% endfor %} + {% else %} +

No quiz

+ {% endif %} +
+
+
+
+

+ {% endfor %} +{% endif %} + {% if courses or allotted_courses %} -{% endif %} +{% endif %} {% endblock %} diff --git a/yaksh/urls.py b/yaksh/urls.py index cd97dd4..d14ed1d 100644 --- a/yaksh/urls.py +++ b/yaksh/urls.py @@ -97,7 +97,6 @@ urlpatterns += [ views.reject, {'was_enrolled': True}), url(r'^manage/searchteacher/(?P\d+)/$', views.search_teacher), url(r'^manage/addteacher/(?P\d+)/$', views.add_teacher, name='add_teacher'), - url(r'^manage/allotted_course/$', views.allotted_courses), url(r'^manage/remove_teachers/(?P\d+)/$', views.remove_teachers, name='remove_teacher'), url(r'^manage/download_questions/$', views.show_all_questions), url(r'^manage/upload_questions/$', views.show_all_questions), diff --git a/yaksh/views.py b/yaksh/views.py index e1ec44e..a2f6f9a 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -664,8 +664,10 @@ def courses(request): if not is_moderator(user): raise Http404('You are not allowed to view this page') courses = Course.objects.filter(creator=user, is_trial=False) - return my_render_to_response('yaksh/courses.html', {'courses': courses}, - context_instance=ci) + allotted_courses = Course.objects.filter(teachers=user, is_trial=False) + context = {'courses': courses, "allotted_courses": allotted_courses} + return my_render_to_response('yaksh/courses.html', context, + context_instance=ci) @login_required @@ -1164,7 +1166,7 @@ def search_teacher(request, course_id): raise Http404('You are not allowed to view this page!') context = {} - course = get_object_or_404(Course, creator=user, pk=course_id) + course = get_object_or_404(Course, Q(creator=user)|Q(teachers=user), pk=course_id) context['course'] = course if request.method == 'POST': @@ -1196,16 +1198,20 @@ def add_teacher(request, course_id): raise Http404('You are not allowed to view this page!') context = {} - course = get_object_or_404(Course, creator=user, pk=course_id) + course = get_object_or_404(Course, Q(creator=user)|Q(teachers=user), pk=course_id) context['course'] = course if request.method == 'POST': teacher_ids = request.POST.getlist('check') teachers = User.objects.filter(id__in=teacher_ids) - add_to_group(teachers) - course.add_teachers(*teachers) - context['status'] = True - context['teachers_added'] = teachers + if not course.creator in teachers: + add_to_group(teachers) + course.add_teachers(*teachers) + context['status'] = True + context['teachers_added'] = teachers + else: + context["message"] = "You cannot add course creator as teacher." + return my_render_to_response('yaksh/addteacher.html', context, context_instance=ci) else: @@ -1213,19 +1219,6 @@ def add_teacher(request, course_id): context_instance=ci) -@login_required -def allotted_courses(request): - """ show courses allotted to a user """ - - user = request.user - ci = RequestContext(request) - if not is_moderator(user): - raise Http404('You are not allowed to view this page!') - - courses = Course.objects.filter(teachers=user) - return my_render_to_response('yaksh/courses.html', {'courses': courses}, - context_instance=ci) - @login_required def remove_teachers(request, course_id): -- cgit From 29c50ad458de008b0672d0f2b1c64278a963850c Mon Sep 17 00:00:00 2001 From: maheshgudi Date: Tue, 9 Aug 2016 11:32:19 +0530 Subject: changed search_teacher function to exclude course creator --- yaksh/templates/yaksh/addteacher.html | 11 +---------- yaksh/templates/yaksh/courses.html | 4 ++-- yaksh/views.py | 21 ++++++++------------- 3 files changed, 11 insertions(+), 25 deletions(-) (limited to 'yaksh') diff --git a/yaksh/templates/yaksh/addteacher.html b/yaksh/templates/yaksh/addteacher.html index 2ab107b..6722a52 100644 --- a/yaksh/templates/yaksh/addteacher.html +++ b/yaksh/templates/yaksh/addteacher.html @@ -19,12 +19,6 @@


-{% if message %} -
- Sorry! {{message}} -
-{% endif %} -
{% csrf_token %} {% if success == True %} @@ -63,10 +57,7 @@
{% if status == True %}
-
-
- Congrats! Following Teachers have been added: -
+
{% if teachers_added %} {% for teacher in teachers_added %}
diff --git a/yaksh/templates/yaksh/courses.html b/yaksh/templates/yaksh/courses.html index 1c68472..5e2266c 100644 --- a/yaksh/templates/yaksh/courses.html +++ b/yaksh/templates/yaksh/courses.html @@ -11,9 +11,9 @@ {% block manage %} {% if not courses %} -

No new Courses added

+

No new Courses created

{% else %} -

Course(s) Added

+

Course(s) Created

{% for course in courses %}
diff --git a/yaksh/views.py b/yaksh/views.py index a2f6f9a..c1dde5f 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -1177,7 +1177,8 @@ def search_teacher(request, course_id): else: teachers = User.objects.filter(Q(username__icontains=u_name)| Q(first_name__icontains=u_name)|Q(last_name__icontains=u_name)| - Q(email__icontains=u_name)).exclude(Q(id=user.id)|Q(is_superuser=1)) + Q(email__icontains=u_name)).exclude(Q(id=user.id)|Q(is_superuser=1)| + Q(id=course.creator.id)) context['success'] = True context['teachers'] = teachers return my_render_to_response('yaksh/addteacher.html', context, @@ -1204,18 +1205,12 @@ def add_teacher(request, course_id): if request.method == 'POST': teacher_ids = request.POST.getlist('check') teachers = User.objects.filter(id__in=teacher_ids) - if not course.creator in teachers: - add_to_group(teachers) - course.add_teachers(*teachers) - context['status'] = True - context['teachers_added'] = teachers - else: - context["message"] = "You cannot add course creator as teacher." + add_to_group(teachers) + course.add_teachers(*teachers) + context['status'] = True + context['teachers_added'] = teachers - return my_render_to_response('yaksh/addteacher.html', context, - context_instance=ci) - else: - return my_render_to_response('yaksh/addteacher.html', context, + return my_render_to_response('yaksh/addteacher.html', context, context_instance=ci) @@ -1228,7 +1223,7 @@ def remove_teachers(request, course_id): if not is_moderator(user): raise Http404('You are not allowed to view this page!') - course = get_object_or_404(Course, creator=user, pk=course_id) + course = get_object_or_404(Course, Q(creator=user)|Q(teachers=user), pk=course_id) if request.method == "POST": teacher_ids = request.POST.getlist('remove') teachers = User.objects.filter(id__in=teacher_ids) -- cgit From d9f6a93ea8d4ddf9f139649567bd680e3f101556 Mon Sep 17 00:00:00 2001 From: maheshgudi Date: Tue, 9 Aug 2016 18:12:25 +0530 Subject: modified add search and remove_teachers functions --- yaksh/views.py | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'yaksh') diff --git a/yaksh/views.py b/yaksh/views.py index c1dde5f..4944691 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -1171,21 +1171,16 @@ def search_teacher(request, course_id): if request.method == 'POST': u_name = request.POST.get('uname') - if len(u_name) == 0: - return my_render_to_response('yaksh/addteacher.html', context, - context_instance=ci) - else: + if not len(u_name) == 0: teachers = User.objects.filter(Q(username__icontains=u_name)| Q(first_name__icontains=u_name)|Q(last_name__icontains=u_name)| Q(email__icontains=u_name)).exclude(Q(id=user.id)|Q(is_superuser=1)| Q(id=course.creator.id)) context['success'] = True context['teachers'] = teachers - return my_render_to_response('yaksh/addteacher.html', context, - context_instance=ci) - else: - return my_render_to_response('yaksh/addteacher.html', context, - context_instance=ci) + + return my_render_to_response('yaksh/addteacher.html', context, + context_instance=ci) @login_required @@ -1199,8 +1194,9 @@ def add_teacher(request, course_id): raise Http404('You are not allowed to view this page!') context = {} - course = get_object_or_404(Course, Q(creator=user)|Q(teachers=user), pk=course_id) - context['course'] = course + course = get_object_or_404(Course, pk=course_id) + if user == course.creator or user in course.teachers.all(): + context['course'] = course if request.method == 'POST': teacher_ids = request.POST.getlist('check') @@ -1220,10 +1216,10 @@ def remove_teachers(request, course_id): """ remove user from a course """ user = request.user - if not is_moderator(user): + course = get_object_or_404(Course, pk=course_id) + if not is_moderator(user) and (user == course.creator or user in course.teachers.all()): raise Http404('You are not allowed to view this page!') - course = get_object_or_404(Course, Q(creator=user)|Q(teachers=user), pk=course_id) if request.method == "POST": teacher_ids = request.POST.getlist('remove') teachers = User.objects.filter(id__in=teacher_ids) -- cgit From 80e3a68ddfcc15fc88442d7af53d804653c4d2a4 Mon Sep 17 00:00:00 2001 From: maheshgudi Date: Tue, 9 Aug 2016 18:13:22 +0530 Subject: added Course and question paper classes in admin.py --- yaksh/admin.py | 4 ++++ yaksh/models.py | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'yaksh') diff --git a/yaksh/admin.py b/yaksh/admin.py index 2ce3ac4..b25c0af 100644 --- a/yaksh/admin.py +++ b/yaksh/admin.py @@ -1,10 +1,14 @@ from yaksh.models import Question, Quiz from yaksh.models import TestCase, StandardTestCase, StdoutBasedTestCase, Course +from yaksh.models import Question, Quiz, Course, QuestionPaper +from yaksh.models import TestCase, StandardTestCase, StdoutBasedTestCase from django.contrib import admin admin.site.register(Question) admin.site.register(TestCase) admin.site.register(StandardTestCase) admin.site.register(StdoutBasedTestCase) +admin.site.register(Course) admin.site.register(Quiz) admin.site.register(Course) +admin.site.register(QuestionPaper) diff --git a/yaksh/models.py b/yaksh/models.py index 73d4b27..898662c 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -570,7 +570,9 @@ class QuestionPaper(models.Model): if self.quiz.has_prerequisite(): prerequisite = self._get_prequisite_paper() return prerequisite._is_questionpaper_passed(user) - + + def __unicode__(self): + return "Question Paper for " + self.quiz.description ############################################################################### class QuestionSet(models.Model): -- cgit From 5d49a64d11d6a6868c74bf9a22bb7cc0fa7b8c6b Mon Sep 17 00:00:00 2001 From: maheshgudi Date: Mon, 29 Aug 2016 13:53:41 +0530 Subject: changed template; modified search_teacher, add_teacher and remove_teachers view functions --- yaksh/templates/yaksh/courses.html | 4 +++- yaksh/views.py | 9 +++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'yaksh') diff --git a/yaksh/templates/yaksh/courses.html b/yaksh/templates/yaksh/courses.html index 5e2266c..42f49d1 100644 --- a/yaksh/templates/yaksh/courses.html +++ b/yaksh/templates/yaksh/courses.html @@ -141,9 +141,11 @@


{% endfor %} +{% else %} +

No new Courses allotted

{% endif %} + {% if courses or allotted_courses %} - {% endif %} {% endblock %} diff --git a/yaksh/views.py b/yaksh/views.py index 4944691..16454b2 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -1166,9 +1166,12 @@ def search_teacher(request, course_id): raise Http404('You are not allowed to view this page!') context = {} - course = get_object_or_404(Course, Q(creator=user)|Q(teachers=user), pk=course_id) + course = get_object_or_404(Course, pk=course_id) context['course'] = course + if user != course.creator and user not in course.teachers.all(): + raise Http404('You are not allowed to view this page!') + if request.method == 'POST': u_name = request.POST.get('uname') if not len(u_name) == 0: @@ -1197,6 +1200,8 @@ def add_teacher(request, course_id): course = get_object_or_404(Course, pk=course_id) if user == course.creator or user in course.teachers.all(): context['course'] = course + else: + raise Http404('You are not allowed to view this page!') if request.method == 'POST': teacher_ids = request.POST.getlist('check') @@ -1217,7 +1222,7 @@ def remove_teachers(request, course_id): user = request.user course = get_object_or_404(Course, pk=course_id) - if not is_moderator(user) and (user == course.creator or user in course.teachers.all()): + if not is_moderator(user) and (user != course.creator and user not in course.teachers.all()): raise Http404('You are not allowed to view this page!') if request.method == "POST": -- cgit From b8c58435aef3b9c30ae8952f353648d70d228eec Mon Sep 17 00:00:00 2001 From: maheshgudi Date: Mon, 29 Aug 2016 14:11:13 +0530 Subject: minor changes in admin --- yaksh/admin.py | 1 - 1 file changed, 1 deletion(-) (limited to 'yaksh') diff --git a/yaksh/admin.py b/yaksh/admin.py index b25c0af..4ef2f3d 100644 --- a/yaksh/admin.py +++ b/yaksh/admin.py @@ -10,5 +10,4 @@ admin.site.register(StandardTestCase) admin.site.register(StdoutBasedTestCase) admin.site.register(Course) admin.site.register(Quiz) -admin.site.register(Course) admin.site.register(QuestionPaper) -- cgit From 95a910aee400c7706ae8f14a94eb3c9ea9289c91 Mon Sep 17 00:00:00 2001 From: prathamesh Date: Mon, 29 Aug 2016 15:08:04 +0530 Subject: Views sometimes use cent percent CPU, fixed After correct submission(POST) of code question, same question is shown for 2 seconds with a message "Correct Output". After 2 seconds, the same correctly answered question is resubmitted(GET) to the server.Since the question is already answered, it skips the question using the skip method of answerpaper. In skip method we have used cycle itertool, which loops in a cyclic manner, never ending. So it is terminated when we get a question match in an unanswered questions list with the submitted question. But the question is already answered so we never get a match and loop runs infinitely. So used list instead of cycle. Also, after correct answer, the user is to always get first question in the answered list of question instead of next question after the answered one. So changed the completed_question method of answerpaper. --- yaksh/models.py | 23 ++++++++----- yaksh/test_models.py | 93 ++++++++++++++++++++++++++++++++++++++++++++-------- yaksh/views.py | 10 +++--- 3 files changed, 100 insertions(+), 26 deletions(-) (limited to 'yaksh') diff --git a/yaksh/models.py b/yaksh/models.py index 73d4b27..6f11c09 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -784,21 +784,28 @@ class AnswerPaper(models.Model): Adds the completed question to the list of answered questions and returns the next question. """ + next_question = self.next_question(question_id) self.questions_answered.add(question_id) self.questions_unanswered.remove(question_id) + if next_question.id == int(question_id): + return None + return next_question - return self.current_question() - - def skip(self, question_id): + def next_question(self, question_id): """ Skips the current question and returns the next sequentially available question. """ - questions = self.questions_unanswered.all() - question_cycle = cycle(questions) - for question in question_cycle: - if question.id==int(question_id): - return question_cycle.next() + unanswered_questions = self.questions_unanswered.all() + questions = list(unanswered_questions.values_list('id', flat=True)) + if len(questions) == 0: + return None + try: + index = questions.index(int(question_id)) + next_id = questions[index+1] + except (ValueError, IndexError): + next_id = questions[0] + return unanswered_questions.get(id=next_id) def time_left(self): """Return the time remaining for the user in seconds.""" diff --git a/yaksh/test_models.py b/yaksh/test_models.py index 8bd2dda..c0721f3 100644 --- a/yaksh/test_models.py +++ b/yaksh/test_models.py @@ -424,7 +424,7 @@ class AnswerPaperTestCases(unittest.TestCase): self.answerpaper.save() # answers for the Answer Paper self.answer_right = Answer(question=Question.objects.get(id=1), - answer="Demo answer", + answer="Demo answer", correct=True, marks=1 ) self.answer_wrong = Answer(question=Question.objects.get(id=2), @@ -458,20 +458,85 @@ class AnswerPaperTestCases(unittest.TestCase): # Test completed_question() method of Answer Paper question = self.answerpaper.completed_question(1) self.assertEqual(self.answerpaper.questions_left(), 2) - # Test skip() method of Answer Paper + + # Test next_question() method of Answer Paper current_question = self.answerpaper.current_question() self.assertEqual(current_question.id, 2) - next_question_id = self.answerpaper.skip(current_question.id) + + # When + next_question_id = self.answerpaper.next_question(current_question.id) + + # Then self.assertTrue(next_question_id is not None) self.assertEqual(next_question_id.id, 3) + + # Given, here question is already answered + current_question_id = 1 + + # When + next_question_id = self.answerpaper.next_question(current_question_id) + + # Then + self.assertTrue(next_question_id is not None) + self.assertEqual(next_question_id.id, 2) + + # Given, wrong question id + current_question_id = 12 + + # When + next_question_id = self.answerpaper.next_question(current_question_id) + + # Then + self.assertTrue(next_question_id is not None) + self.assertEqual(next_question_id.id, 2) + + # Given, last question in the list + current_question_id = 3 + + # When + next_question_id = self.answerpaper.next_question(current_question_id) + + # Then + self.assertTrue(next_question_id is not None) + self.assertEqual(next_question_id.id, 2) + + # Test get_questions_answered() method + # When questions_answered = self.answerpaper.get_questions_answered() + + # Then self.assertEqual(questions_answered.count(), 1) self.assertSequenceEqual(questions_answered, [self.questions[0]]) + + # When questions_unanswered = self.answerpaper.get_questions_unanswered() + + # Then self.assertEqual(questions_unanswered.count(), 2) self.assertSequenceEqual(questions_unanswered, [self.questions[1], self.questions[2]]) + # Test completed_question and next_question + # When all questions are answered + current_question = self.answerpaper.completed_question(2) + + # Then + self.assertEqual(self.answerpaper.questions_left(), 1) + self.assertEqual(current_question.id, 3) + + # When + current_question = self.answerpaper.completed_question(3) + + # Then + self.assertEqual(self.answerpaper.questions_left(), 0) + self.assertTrue(current_question is None) + + # When + next_question_id = self.answerpaper.next_question(current_question_id) + + # Then + self.assertTrue(next_question_id is None) + def test_update_marks(self): """ Test update_marks method of AnswerPaper""" self.answerpaper.update_marks('inprogress') @@ -584,7 +649,7 @@ class CourseTestCases(unittest.TestCase): def test_add_teachers(self): """ Test to add teachers to a course""" self.course.add_teachers(self.student1, self.student2) - self.assertSequenceEqual(self.course.get_teachers(), + self.assertSequenceEqual(self.course.get_teachers(), [self.student1, self.student2]) def test_remove_teachers(self): @@ -616,23 +681,23 @@ class CourseTestCases(unittest.TestCase): class TestCaseTestCases(unittest.TestCase): def setUp(self): self.user = User.objects.get(pk=1) - self.question1 = Question(summary='Demo question 1', + self.question1 = Question(summary='Demo question 1', language='Python', - type='Code', + type='Code', active=True, - description='Write a function', + description='Write a function', points=1.0, - test_case_type="standardtestcase", + test_case_type="standardtestcase", user=self.user, snippet='def myfunc()' ) - self.question2 = Question(summary='Demo question 2', + self.question2 = Question(summary='Demo question 2', language='Python', - type='Code', + type='Code', active=True, - description='Write to standard output', + description='Write to standard output', points=1.0, - test_case_type="stdoutbasedtestcase", + test_case_type="stdoutbasedtestcase", user=self.user, snippet='def myfunc()' ) @@ -658,13 +723,13 @@ class TestCaseTestCases(unittest.TestCase): def test_assertion_testcase(self): """ Test question """ self.assertEqual(self.assertion_testcase.question, self.question1) - self.assertEqual(self.assertion_testcase.test_case, + self.assertEqual(self.assertion_testcase.test_case, 'assert myfunc(12, 13) == 15') def test_stdout_based_testcase(self): """ Test question """ self.assertEqual(self.stdout_based_testcase.question, self.question2) - self.assertEqual(self.stdout_based_testcase.expected_output, + self.assertEqual(self.stdout_based_testcase.expected_output, 'Hello World' ) diff --git a/yaksh/views.py b/yaksh/views.py index e1ec44e..2ee964f 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -460,10 +460,12 @@ def skip(request, q_id, next_q=None, attempt_num=None, questionpaper_id=None): correct=False, skipped=True) new_answer.save() paper.answers.add(new_answer) - if next_q is None: - next_q = paper.skip(q_id) if paper.skip(q_id) else question - else: + if next_q is not None: next_q = get_object_or_404(Question, pk=next_q) + if next_q not in paper.questions_unanswered.all(): + return show_question(request, question, paper) + else: + next_q = paper.next_question(q_id) return show_question(request, next_q, paper) @@ -475,7 +477,7 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None): question_paper=questionpaper_id) question = get_object_or_404(Question, pk=q_id) if question in paper.questions_answered.all(): - next_q = paper.skip(q_id) + next_q = paper.next_question(q_id) return show_question(request, next_q, paper) if request.method == 'POST': -- cgit From 45cfca69a8af52fb838de48706ed5e4ddc1b1042 Mon Sep 17 00:00:00 2001 From: prathamesh Date: Mon, 29 Aug 2016 17:37:23 +0530 Subject: Answer saved again after correctly submitted, fixed. Removed javascript that makes user wait for 2 seconds when the code question is correct. All the other html elements are accessible by user during the wait. This also caused the duplicate save during the wait, as they can skip at that point and the answer is saved again. Added a check that if question is already answered then do not save it. This also resolves the monitor(use data) page problem of showing marks obtained zero even when it is correct. Removed skipped answers from the monitor page. --- yaksh/templates/yaksh/question.html | 21 +++++++-------------- yaksh/templates/yaksh/user_data.html | 10 +++++++--- yaksh/views.py | 23 +++++++++++------------ 3 files changed, 25 insertions(+), 29 deletions(-) (limited to 'yaksh') diff --git a/yaksh/templates/yaksh/question.html b/yaksh/templates/yaksh/question.html index 73d851a..9a0f899 100644 --- a/yaksh/templates/yaksh/question.html +++ b/yaksh/templates/yaksh/question.html @@ -85,19 +85,6 @@ function call_skip(url) form.action = url form.submit(); } - {% if error_message == 'Correct Output'%} - {% if paper.questions_left %} - window.setTimeout(function() - { - location.href="{{ URL_ROOT }}/exam/{{ paper.current_question.id }}/check/{{ paper.attempt_number }}/{{ paper.question_paper.id }}/" - }, 2000); - {% else %} - window.setTimeout(function() - { - location.href="{{ URL_ROOT }}/exam/{{ question.id }}/check/{{ paper.attempt_number }}/{{ paper.question_paper.id }}/" - }, 2000); - {% endif %} - {% endif %} {% endblock script %} @@ -165,11 +152,17 @@ function call_skip(url) {% if question.type == "mcq" %} + {% if error_message %} +

{{ error_message }}

+ {% endif %} {% for test_case in test_cases %} {{ test_case.options }}
{% endfor %} {% endif %} {% if question.type == "mcc" %} + {% if error_message %} +

{{ error_message }}

+ {% endif %} {% for test_case in test_cases %} {{ test_case.options }}
@@ -188,7 +181,7 @@ function call_skip(url) {% endif %} - {% if question.type == "mcq" or question.type == "mcc "%} + {% if question.type == "mcq" or question.type == "mcc"%}
   {% elif question.type == "upload" %}
   diff --git a/yaksh/templates/yaksh/user_data.html b/yaksh/templates/yaksh/user_data.html index 04544f9..2e7db50 100644 --- a/yaksh/templates/yaksh/user_data.html +++ b/yaksh/templates/yaksh/user_data.html @@ -56,11 +56,15 @@ User IP address: {{ paper.user_ip }}

Student answer: {{ answers.0 }}

{% else %}{# non-mcq questions #} -
 
-{% for answer in answers %}################################################################################
+{% for answer in answers %}
+{% if not answer.skipped %}
+
+###############################################################################
 {{ answer.answer.strip }}
 # Autocheck: {{ answer.error }}
-{% endfor %}
+
+{% endif %} +{% endfor %} {% endif %} {% with answers|last as answer %}

Marks: {{answer.marks}}

diff --git a/yaksh/views.py b/yaksh/views.py index 2ee964f..fd47ca5 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -454,6 +454,10 @@ def skip(request, q_id, next_q=None, attempt_num=None, questionpaper_id=None): paper = get_object_or_404(AnswerPaper, user=request.user, attempt_number=attempt_num, question_paper=questionpaper_id) question = get_object_or_404(Question, pk=q_id) + if question in paper.questions_answered.all(): + next_q = paper.next_question(q_id) + return show_question(request, next_q, paper) + if request.method == 'POST' and question.type == 'code': user_code = request.POST.get('answer') new_answer = Answer(question=question, answer=user_code, @@ -506,7 +510,9 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None): correct=False) new_answer.save() paper.answers.add(new_answer) - + if not user_answer: + msg = "Please submit a valid option or code" + return show_question(request, question, paper, msg) # If we were not skipped, we were asked to check. For any non-mcq # questions, we obtain the results via XML-RPC with the code executed # safely in a separate process (the code_server.py) running as nobody. @@ -527,17 +533,8 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None): new_answer.save() return show_question(request, question, paper, result.get('error')) else: - # Display the same question if user_answer is None - if not user_answer: - msg = "Please submit a valid option or code" - return show_question(request, question, paper, msg) - elif question.type == 'code' and user_answer: - msg = "Correct Output" - paper.completed_question(question.id) - return show_question(request, question, paper, msg) - else: - next_q = paper.completed_question(question.id) - return show_question(request, next_q, paper) + next_q = paper.completed_question(question.id) + return show_question(request, next_q, paper) else: return show_question(request, question, paper) @@ -560,11 +557,13 @@ def validate_answer(user, user_answer, question, json_data=None): expected_answer = question.get_test_case(correct=True).options if user_answer.strip() == expected_answer.strip(): correct = True + result['error'] = 'Correct answer' elif question.type == 'mcc': expected_answers = [] for opt in question.get_test_cases(correct=True): expected_answers.append(opt.options) if set(user_answer) == set(expected_answers): + result['error'] = 'Correct answer' correct = True elif question.type == 'code': user_dir = get_user_dir(user) -- cgit From b4b77ab955e4e75895cc781f023eaf00baa5a72e Mon Sep 17 00:00:00 2001 From: ankitjavalkar Date: Mon, 1 Aug 2016 15:31:20 +0530 Subject: Add docker deployment to documentation --- yaksh/documentation/installation.rst | 50 +++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) (limited to 'yaksh') diff --git a/yaksh/documentation/installation.rst b/yaksh/documentation/installation.rst index 4acee61..51efea7 100644 --- a/yaksh/documentation/installation.rst +++ b/yaksh/documentation/installation.rst @@ -64,4 +64,52 @@ This starts the code server **And entering the following admin credentials** * Username: admin - * Password: admin \ No newline at end of file + * Password: admin + +Running The Code Server +----------------------- + +**Local Instance**: + +In a new terminal run the command:: + + sudo python /path/to/code_server.py + +Keep this instance running in the background + +**Using Docker**: + +1. Install docker + +2. Create a Docker Image using the Docker file: + + * Go to the directory where the project is located:: + + cd /path/to/online_test + + * Build a docker image using the Dockerfile:: + + sudo docker build --tag=yaksh_code_server:v1 . + +3. Start a Docker container:: + + docker run -d -p 8001:8001 -p 53579:53579 -v /path/to/online_test/yaksh/output:/src/yaksh/output yaksh_code_server:v1 + +**Note**: + * The default ports on which the code server runs and the pool port on which the former ports are available is specified in online_test/yaksh/settings.py. The code server also supports multiple ports + + * The server port is 8001 by default, this can be changed in the settings:: + + SERVER_PORTS = 8001 + + * Multiple ports can be specified as:: + + SERVER_PORTS = [8001, 8002, 8003, 8004, 8005] # Or use range(8001, 8040) for larger number of ports + + * The default pool port is 53579 by default, this can be changed in the settings:: + + SERVER_POOL_PORT = 53579 + + * The docker command to start a docker container when using multiple ports is:: + + docker run -d -p 8001-8039:8001-8039 -p 53579:53579 yaksh_code_server:v1 -- cgit