diff options
author | King | 2018-07-12 02:29:40 -0700 |
---|---|---|
committer | GitHub | 2018-07-12 02:29:40 -0700 |
commit | a850749942d163f9aedb19a1d19c4b8d7016745d (patch) | |
tree | 9b93d232ad093f595a5e62d22f5d2a6af9629602 | |
parent | e3ad85ace916354ab96b23c1359ee72a6c2a740b (diff) | |
parent | 0e2910668a8b2c79dd422cd49813e263f117b00d (diff) | |
download | online_test-a850749942d163f9aedb19a1d19c4b8d7016745d.tar.gz online_test-a850749942d163f9aedb19a1d19c4b8d7016745d.tar.bz2 online_test-a850749942d163f9aedb19a1d19c4b8d7016745d.zip |
Merge pull request #489 from adityacp/search_tags_in_design_qp
Get questions using tags during question paper setup
-rw-r--r-- | yaksh/forms.py | 1 | ||||
-rw-r--r-- | yaksh/static/yaksh/js/question_paper_creation.js | 9 | ||||
-rw-r--r-- | yaksh/templates/yaksh/ajax_question_filter.html | 57 | ||||
-rw-r--r-- | yaksh/templates/yaksh/design_questionpaper.html | 38 | ||||
-rw-r--r-- | yaksh/test_views.py | 159 | ||||
-rw-r--r-- | yaksh/views.py | 65 |
6 files changed, 288 insertions, 41 deletions
diff --git a/yaksh/forms.py b/yaksh/forms.py index 41c9176..99e8dbe 100644 --- a/yaksh/forms.py +++ b/yaksh/forms.py @@ -258,6 +258,7 @@ class QuestionFilterForm(forms.Form): self.fields['marks'] = forms.FloatField( widget=forms.Select(choices=points_options) ) + self.fields['marks'].required = False language = forms.CharField( max_length=8, widget=forms.Select(choices=languages)) question_type = forms.CharField( diff --git a/yaksh/static/yaksh/js/question_paper_creation.js b/yaksh/static/yaksh/js/question_paper_creation.js index 430ec4b..86294b3 100644 --- a/yaksh/static/yaksh/js/question_paper_creation.js +++ b/yaksh/static/yaksh/js/question_paper_creation.js @@ -61,3 +61,12 @@ $(document).ready(function(){ }); });//document +function append_tag(tag){ + var tag_name = document.getElementById("question_tags"); + if (tag_name.value != null){ + tag_name.value = tag.value+", "+tag_name.value; + } + else{ + tag_name.value = tag.value; + } +}
\ No newline at end of file diff --git a/yaksh/templates/yaksh/ajax_question_filter.html b/yaksh/templates/yaksh/ajax_question_filter.html index a63354c..ea0d0b5 100644 --- a/yaksh/templates/yaksh/ajax_question_filter.html +++ b/yaksh/templates/yaksh/ajax_question_filter.html @@ -1,16 +1,49 @@ <div id="questions"> + <script> + $(document).ready(function(){ + $("#checkall").change(function(){ + if($(this).prop("checked")) { + $("#filtered-questions input:checkbox").each(function(index, element) { + $(this).prop('checked', true); + }); + } + else { + $("#filtered-questions input:checkbox").each(function(index, element) { + $(this).prop('checked', false); + }); + } + }); + }); + </script> {% if questions %} - <h5 class="highlight"><input type="checkbox" id="checkall" class="ignore"> Select All </h5> + <h5 class="highlight"><input type="checkbox" id="checkall"> + Select All + </h5> + <ul class="inputs-list"> + <table id="questions-table" class="tablesorter table table table-striped"> + <thead> + <tr> + <th> Select </th> + <th> Summary </th> + <th> Language </th> + <th> Type </th> + <th> Marks </th> + </tr> + </thead> + <tbody> + {% for question in questions %} + <tr> + <td> + <input type="checkbox" name="question" value="{{ question.id }}"> + </td> + <td><a href="{{URL_ROOT}}/exam/manage/addquestion/{{ question.id }}">{{question.summary|capfirst}}</a></td> + <td>{{question.language|capfirst}}</td> + <td>{{question.type|capfirst}}</td> + <td>{{question.points}}</td> + </tr> + {% endfor %} + </tbody> + </table> + </ul> {% endif %} - <ul class="inputs-list"> - - {% for question in questions %} - <li> - <label> - <input type="checkbox" name="question" data-qid="{{question.id}}" value= - "{{question.id}}"> <a href="{{URL_ROOT}}/exam/manage/addquestion/{{ question.id }}">{{ question }}</a><br> - </label> - </li> - {% endfor %} - </ul> </div> diff --git a/yaksh/templates/yaksh/design_questionpaper.html b/yaksh/templates/yaksh/design_questionpaper.html index d982d27..7e6d5c0 100644 --- a/yaksh/templates/yaksh/design_questionpaper.html +++ b/yaksh/templates/yaksh/design_questionpaper.html @@ -68,8 +68,36 @@ select </div> </div> <!-- /.row --> <br><br> - + {% csrf_token %} <div class="tab-pane active" id="fixed-questions"> + <h4 style="padding-left: 20px;">Or</h4> + <!-- Search questions using tags --> + <h4 style="padding-left: 20px;">Search using Tags: </h4> + <div class="col-md-14"> + <div class="input-group"> + <span class="input-group-addon" id="basic-addon1">Search Questions </span> + <input type="text" id="question_tags" name="question_tags" class="form-control" + placeholder="Search using comma separated Tags"> + <span class="input-group-btn"> + <button class="btn btn-default" type="submit">Search</button> + </span> + <div class="col-md-6"> + <select class="form-control" id="sel1" onchange="append_tag(this);"> + {% if all_tags %} + <option value="" disabled selected>Available Tags</option> + {% for tag in all_tags %} + <option> + {{tag}} + </option> + {% endfor %} + {% else %} + <option value="" disabled selected>No Available Tags</option> + {% endif %} + </select> + </div> + </div> + </div> + <br><br> <div class="row"> <div class="col-md-6"> <div id="fixed-available-wrapper"> @@ -116,7 +144,7 @@ select </div> <!-- /.row --> <br> <div class="pull-right"> - <a class="btn" id="fixed-next">Next ></a> + <a class="btn btn-primary" id="fixed-next">Next ></a> </div> </div> <!-- /#fixed-questions --> @@ -183,10 +211,10 @@ select </div> <!-- /.row --> <br> <div class="pull-left"> - <a class="btn" id="random-prev">< Previous</a> + <a class="btn btn-primary" id="random-prev">< Previous</a> </div> <div class="pull-right"> - <a class="btn" id="random-next">Next ></a> + <a class="btn btn-primary" id="random-next">Next ></a> </div> </div> <!-- /#random-questions --> @@ -204,7 +232,7 @@ select <input class ="btn primary large" type="submit" name="save" id="save" value="Save question paper"> <br> <div class="pull-left"> - <a class="btn" id="finish-prev">< Previous</a> + <a class="btn btn-primary" id="finish-prev">< Previous</a> </div> </center> </div> <!-- /#finish --> diff --git a/yaksh/test_views.py b/yaksh/test_views.py index 8592031..24cf7d8 100644 --- a/yaksh/test_views.py +++ b/yaksh/test_views.py @@ -4373,6 +4373,24 @@ class TestQuestionPaper(TestCase): timezone='UTC' ) + self.student_plaintext_pass = 'demo' + self.student = User.objects.create_user( + username='demo_student', + password=self.student_plaintext_pass, + first_name='first_name', + last_name='last_name', + email='demo@test.com' + ) + + Profile.objects.create( + user=self.student, + roll_number=10, + institute='IIT', + department='Chemical', + position='Student', + timezone='UTC' + ) + self.user2_plaintext_pass = 'demo2' self.user2 = User.objects.create_user( username='demo_user2', @@ -4435,6 +4453,15 @@ class TestQuestionPaper(TestCase): creator=self.user ) + self.quiz_without_qp = Quiz.objects.create( + start_date_time=datetime(2014, 10, 9, 10, 8, 15, 0, tzone), + end_date_time=datetime(2015, 10, 9, 10, 8, 15, 0, tzone), + duration=30, active=True, instructions="Demo Instructions", + attempts_allowed=-1, time_between_attempts=0, + description='quiz without question paper', pass_criteria=40, + creator=self.user + ) + self.learning_unit = LearningUnit.objects.create( order=1, type="quiz", quiz=self.quiz) self.learning_module = LearningModule.objects.create( @@ -4517,6 +4544,13 @@ class TestQuestionPaper(TestCase): ) self.float_based_testcase.save() + # Question with tag + self.tagged_que = Question.objects.create( + summary="Test_tag_question", description="Test Tag", + points=1.0, language="python", type="float", user=self.teacher + ) + self.tagged_que.tags.add("test_tag") + self.questions_list = [self.question_mcq, self.question_mcc, self.question_int, self.question_str, self.question_float] @@ -4529,6 +4563,13 @@ class TestQuestionPaper(TestCase): quiz=self.quiz, total_marks=5.0, fixed_question_order=questions_order ) + self.fixed_que = Question.objects.create( + summary="Test_fixed_question", description="Test Tag", + points=1.0, language="python", type="float", user=self.teacher + ) + self.fixed_question_paper = QuestionPaper.objects.create( + quiz=self.demo_quiz, total_marks=5.0 + ) self.question_paper.fixed_questions.add(*self.questions_list) self.answerpaper = AnswerPaper.objects.create( user=self.user, question_paper=self.question_paper, @@ -4883,6 +4924,26 @@ class TestQuestionPaper(TestCase): "questionpaper_id": self.question_paper.id})) self.assertEqual(response.status_code, 404) + # Design question paper for a quiz + response = self.client.post( + reverse('yaksh:design_questionpaper', + kwargs={"quiz_id": self.quiz_without_qp.id}), + data={"marks": "1.0", "question_type": "code"}) + self.assertEqual(response.status_code, 200) + self.assertIsNotNone(response.context['questions']) + + # Student should not be able to design question paper + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass + ) + + response = self.client.get( + reverse('yaksh:designquestionpaper', + kwargs={"quiz_id": self.demo_quiz.id, + "questionpaper_id": self.question_paper.id})) + self.assertEqual(response.status_code, 404) + self.client.login( username=self.teacher.username, password=self.teacher_plaintext_pass @@ -4919,6 +4980,18 @@ class TestQuestionPaper(TestCase): self.questions_list) self.assertEqual(response.context['qpaper'], self.question_paper) + # Get questions using tags for question paper + search_tag = [tag for tag in self.tagged_que.tags.all()] + response = self.client.post( + reverse('yaksh:designquestionpaper', + kwargs={"quiz_id": self.quiz.id, + "course_id": self.course.id, + "questionpaper_id": self.question_paper.id}), + data={"question_tags": search_tag}) + + self.assertEqual(response.context["questions"][0], self.tagged_que) + + # Add random questions in question paper response = self.client.post( reverse('yaksh:designquestionpaper', kwargs={"quiz_id": self.quiz.id, @@ -4929,6 +5002,7 @@ class TestQuestionPaper(TestCase): 'marks': ['1.0'], 'question_type': ['code'], 'add-random': ['']} ) + self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'yaksh/design_questionpaper.html') random_set = response.context['random_sets'][0] @@ -4936,6 +5010,91 @@ class TestQuestionPaper(TestCase): self.assertIn(self.random_que1, added_random_ques) self.assertIn(self.random_que2, added_random_ques) + # Check if questions already exists + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + response = self.client.post( + reverse('yaksh:designquestionpaper', + kwargs={"quiz_id": self.quiz.id, + "course_id": self.course.id, + "questionpaper_id": self.question_paper.id}), + data={'marks': ['1.0'], 'question_type': ['code'], + 'add-fixed': ['']} + ) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context["questions"].count(), 0) + + # Add fixed question in question paper + response = self.client.post( + reverse('yaksh:designquestionpaper', + kwargs={"quiz_id": self.demo_quiz.id, + "course_id": self.course.id, + "questionpaper_id": self.fixed_question_paper.id}), + data={'checked_ques': [self.fixed_que.id], + 'add-fixed': ''} + ) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context['qpaper'], self.fixed_question_paper) + self.assertEqual(response.context['fixed_questions'][0], + self.fixed_que) + + # Add one more fixed question in question paper + response = self.client.post( + reverse('yaksh:designquestionpaper', + kwargs={"quiz_id": self.demo_quiz.id, + "course_id": self.course.id, + "questionpaper_id": self.fixed_question_paper.id}), + data={'checked_ques': [self.question_float.id], + 'add-fixed': ''} + ) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context['qpaper'], self.fixed_question_paper) + self.assertEqual(response.context['fixed_questions'], + [self.fixed_que, self.question_float]) + + # Remove fixed question from question paper + response = self.client.post( + reverse('yaksh:designquestionpaper', + kwargs={"quiz_id": self.demo_quiz.id, + "course_id": self.course.id, + "questionpaper_id": self.fixed_question_paper.id}), + data={'added-questions': [self.fixed_que.id], + 'remove-fixed': ''} + ) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context['qpaper'], self.fixed_question_paper) + self.assertEqual(response.context['fixed_questions'], + [self.question_float]) + + # Remove one more fixed question from question paper + response = self.client.post( + reverse('yaksh:designquestionpaper', + kwargs={"quiz_id": self.demo_quiz.id, + "course_id": self.course.id, + "questionpaper_id": self.fixed_question_paper.id}), + data={'added-questions': [self.question_float.id], + 'remove-fixed': ''} + ) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context['qpaper'], self.fixed_question_paper) + self.assertEqual(response.context['fixed_questions'], []) + + # Remove random questions from question paper + random_que_set = self.question_paper.random_questions.all().first() + response = self.client.post( + reverse('yaksh:designquestionpaper', + kwargs={"quiz_id": self.quiz.id, + "course_id": self.course.id, + "questionpaper_id": self.question_paper.id}), + data={'random_sets': random_que_set.id, + 'remove-random': ''} + ) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context['qpaper'], self.question_paper) + self.assertEqual(len(response.context['random_sets']), 0) + class TestLearningModule(TestCase): def setUp(self): diff --git a/yaksh/views.py b/yaksh/views.py index 3341aca..9116026 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -1232,16 +1232,15 @@ def ajax_questions_filter(request): question_type = request.POST.get('question_type') marks = request.POST.get('marks') language = request.POST.get('language') - - if question_type != "select": + if question_type: filter_dict['type'] = str(question_type) - if marks != "select": + if marks: filter_dict['points'] = marks - if language != "select": + if language: filter_dict['language'] = str(language) - questions = list(Question.objects.filter(**filter_dict)) + questions = Question.objects.filter(**filter_dict) return my_render_to_response( request, 'yaksh/ajax_question_filter.html', {'questions': questions} @@ -1267,19 +1266,29 @@ def _remove_already_present(questionpaper_id, questions): return questions questionpaper = QuestionPaper.objects.get(pk=questionpaper_id) questions = questions.exclude( - id__in=questionpaper.fixed_questions.values_list('id', flat=True)) + id__in=questionpaper.fixed_questions.values_list('id', flat=True)) for random_set in questionpaper.random_questions.all(): questions = questions.exclude( - id__in=random_set.questions.values_list('id', flat=True)) + id__in=random_set.questions.values_list('id', flat=True)) return questions +def _get_questions_from_tags(question_tags, user): + search_tags = [] + for tags in question_tags: + search_tags.extend(re.split('[; |, |\*|\n]', tags)) + return Question.objects.filter(tags__name__in=search_tags, + user=user).distinct() + + @login_required @email_verified def design_questionpaper(request, quiz_id, questionpaper_id=None, course_id=None): user = request.user - + que_tags = Question.objects.filter( + active=True, user=user).values_list('tags', flat=True).distinct() + all_tags = Tag.objects.filter(id__in=que_tags) if not is_moderator(user): raise Http404('You are not allowed to view this page!') if quiz_id: @@ -1309,18 +1318,24 @@ def design_questionpaper(request, quiz_id, questionpaper_id=None, question_type = request.POST.get('question_type', None) marks = request.POST.get('marks', None) state = request.POST.get('is_active', None) + tags = request.POST.get('question_tags', None) if 'add-fixed' in request.POST: question_ids = request.POST.get('checked_ques', None) - if question_paper.fixed_question_order: - ques_order = question_paper.fixed_question_order.split(",") +\ - question_ids.split(",") - questions_order = ",".join(ques_order) - else: - questions_order = question_ids - questions = Question.objects.filter(id__in=question_ids.split(',')) - question_paper.fixed_question_order = questions_order - question_paper.save() - question_paper.fixed_questions.add(*questions) + if question_ids: + if question_paper.fixed_question_order: + ques_order = ( + question_paper.fixed_question_order.split(",") + + question_ids.split(",") + ) + questions_order = ",".join(ques_order) + else: + questions_order = question_ids + questions = Question.objects.filter( + id__in=question_ids.split(',') + ) + question_paper.fixed_question_order = questions_order + question_paper.save() + question_paper.fixed_questions.add(*questions) if 'remove-fixed' in request.POST: question_ids = request.POST.getlist('added-questions', None) @@ -1356,6 +1371,11 @@ def design_questionpaper(request, quiz_id, questionpaper_id=None, if marks: questions = _get_questions(user, question_type, marks) + elif tags: + que_tags = request.POST.getlist('question_tags', None) + questions = _get_questions_from_tags(que_tags, user) + + if questions: questions = _remove_already_present(questionpaper_id, questions) question_paper.update_total_marks() @@ -1370,7 +1390,8 @@ def design_questionpaper(request, quiz_id, questionpaper_id=None, 'fixed_questions': fixed_questions, 'state': state, 'random_sets': random_sets, - 'course_id': course_id + 'course_id': course_id, + 'all_tags': all_tags } return my_render_to_response( request, 'yaksh/design_questionpaper.html', context @@ -1453,11 +1474,7 @@ def show_all_questions(request): if request.POST.get('question_tags'): question_tags = request.POST.getlist("question_tags") - search_tags = [] - for tags in question_tags: - search_tags.extend(re.split('[; |, |\*|\n]', tags)) - search_result = Question.objects.filter(tags__name__in=search_tags, - user=user).distinct() + search_result = _get_questions_from_tags(question_tags, user) context['questions'] = search_result return my_render_to_response(request, 'yaksh/showquestions.html', context) |