diff options
author | prathamesh | 2017-12-05 19:38:21 +0530 |
---|---|---|
committer | prathamesh | 2017-12-05 19:38:21 +0530 |
commit | d33e622b8790d81c80eea2305ab7a2989c21b156 (patch) | |
tree | 9dc3d84df3f955a200f7182ed9d0067e8c138f5f | |
parent | 06cc3dc5d3671ca24fc412b6078906a582b83e98 (diff) | |
parent | d2eb978e3ca51914b16655403bd74cc84d4eab28 (diff) | |
download | online_test-d33e622b8790d81c80eea2305ab7a2989c21b156.tar.gz online_test-d33e622b8790d81c80eea2305ab7a2989c21b156.tar.bz2 online_test-d33e622b8790d81c80eea2305ab7a2989c21b156.zip |
Merge branch 'yaksh_video_lessons' of https://github.com/FOSSEE/online_test into yaksh_video_lessons
-rw-r--r-- | yaksh/evaluator_tests/test_simple_question_types.py | 6 | ||||
-rw-r--r-- | yaksh/live_server_tests/load_test.py | 4 | ||||
-rw-r--r-- | yaksh/live_server_tests/selenium_test.py | 9 | ||||
-rw-r--r-- | yaksh/models.py | 10 | ||||
-rw-r--r-- | yaksh/static/yaksh/css/exam.css | 2 | ||||
-rw-r--r-- | yaksh/static/yaksh/js/requesthandler.js | 25 | ||||
-rw-r--r-- | yaksh/templates/base.html | 2 | ||||
-rw-r--r-- | yaksh/templates/exam.html | 96 | ||||
-rw-r--r-- | yaksh/templates/yaksh/complete.html | 2 | ||||
-rw-r--r-- | yaksh/templates/yaksh/error_template.html | 91 | ||||
-rw-r--r-- | yaksh/templates/yaksh/question.html | 28 | ||||
-rw-r--r-- | yaksh/templates/yaksh/quit.html | 2 | ||||
-rw-r--r-- | yaksh/templates/yaksh/quizzes_user.html | 4 | ||||
-rw-r--r-- | yaksh/templates/yaksh/show_video.html | 7 | ||||
-rw-r--r-- | yaksh/test_views.py | 888 | ||||
-rw-r--r-- | yaksh/urls.py | 7 | ||||
-rw-r--r-- | yaksh/views.py | 72 |
17 files changed, 984 insertions, 271 deletions
diff --git a/yaksh/evaluator_tests/test_simple_question_types.py b/yaksh/evaluator_tests/test_simple_question_types.py index c0b81d6..b86a9d8 100644 --- a/yaksh/evaluator_tests/test_simple_question_types.py +++ b/yaksh/evaluator_tests/test_simple_question_types.py @@ -26,8 +26,7 @@ def setUpModule(): tzinfo=pytz.utc), duration=30, active=True, attempts_allowed=1, time_between_attempts=0, description='demo quiz 100', - pass_criteria=0,language='Python', - prerequisite=None,course=course, + pass_criteria=0, instructions="Demo Instructions" ) question_paper = QuestionPaper.objects.create(quiz=quiz, @@ -38,7 +37,8 @@ def setUpModule(): question_paper=question_paper, end_time=timezone.now() +timedelta(minutes=5), - attempt_number=1 + attempt_number=1, + course=course ) def tearDownModule(): diff --git a/yaksh/live_server_tests/load_test.py b/yaksh/live_server_tests/load_test.py index 5ab1cc2..c3eb6e6 100644 --- a/yaksh/live_server_tests/load_test.py +++ b/yaksh/live_server_tests/load_test.py @@ -73,5 +73,7 @@ class YakshSeleniumTests(StaticLiveServerTestCase): def test_load(self): url = '%s%s' % (self.live_server_url, '/exam/login/') quiz_name = "Yaksh Demo quiz" - selenium_test = SeleniumTest(url=url, quiz_name=quiz_name) + module_name = "demo module" + selenium_test = SeleniumTest(url=url, quiz_name=quiz_name, + module_name=module_name) selenium_test.run_load_test(url=url, username='demo_student', password='demo_student') diff --git a/yaksh/live_server_tests/selenium_test.py b/yaksh/live_server_tests/selenium_test.py index 31efcac..160ad02 100644 --- a/yaksh/live_server_tests/selenium_test.py +++ b/yaksh/live_server_tests/selenium_test.py @@ -26,9 +26,10 @@ class SeleniumTestError(Exception): pass class SeleniumTest(): - def __init__(self, url, quiz_name): + def __init__(self, url, quiz_name, module_name): self.driver = webdriver.Firefox() self.quiz_name = quiz_name + self.module_name = module_name self.url = url def run_load_test(self, url, username, password): @@ -119,6 +120,8 @@ class SeleniumTest(): self.submit_answer(question_label, answer, loop_count) def open_quiz(self): + # open module link + self.driver.find_element_by_link_text(self.module_name).click() # open quiz link quiz_link_elem = self.driver.find_element_by_link_text(self.quiz_name).click() @@ -171,7 +174,9 @@ if __name__ == '__main__': opts = parser.parse_args() quiz_name = "Demo quiz" - selenium_test = SeleniumTest(url=opts.url, quiz_name=quiz_name) + module_name = "demo module" + selenium_test = SeleniumTest(url=opts.url, quiz_name=quiz_name, + module_name=module_name) pool = multiprocessing.Pool(opts.number) pool.map(wrap_run_load_test, user_gen(opts.url, range(opts.start, opts.start + opts.number))) pool.close() diff --git a/yaksh/models.py b/yaksh/models.py index 463434b..c65e9ef 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -143,13 +143,17 @@ class CourseManager(models.Manager): ############################################################################# class Lesson(models.Model): + # Lesson name name = models.CharField(max_length=255) + + # Markdown text of lesson content description = models.TextField() + + # Markdown text should be in html format html_data = models.TextField(null=True, blank=True) - creator = models.ForeignKey(User) - def get_files(self): - return LessonFile.objects.filter(lesson=self) + # Creator of the lesson + creator = models.ForeignKey(User) def __str__(self): return "{0}".format(self.name) diff --git a/yaksh/static/yaksh/css/exam.css b/yaksh/static/yaksh/css/exam.css index ec48a14..7d10629 100644 --- a/yaksh/static/yaksh/css/exam.css +++ b/yaksh/static/yaksh/css/exam.css @@ -4,4 +4,4 @@ table td, table th { border: black solid 1px !important; } #stdio, #assertion { table-layout: fixed -}
\ No newline at end of file +} diff --git a/yaksh/static/yaksh/js/requesthandler.js b/yaksh/static/yaksh/js/requesthandler.js index 9749676..0663a55 100644 --- a/yaksh/static/yaksh/js/requesthandler.js +++ b/yaksh/static/yaksh/js/requesthandler.js @@ -53,16 +53,35 @@ function response_handler(method_type, content_type, data, uid){ } else if(content_type.indexOf("application/json") !== -1) { res = JSON.parse(data); request_status = res.status; - if(method_type === "POST") { - uid = res.uid; + if (request_status){ + if(method_type === "POST") { + uid = res.uid; + } + check_state(request_status, uid); + } + else{ + unlock_screen(); + if ($("#notification")){ + $("#notification").toggle(); + } + + var error_output = document.getElementById("error_panel"); + error_output.innerHTML = res.error; + focus_on_error(error_output); } - check_state(request_status, uid); } else { reset_values(); unlock_screen(); } } +function focus_on_error(ele){ + if (ele) { + ele.scrollIntoView(true); + window.scrollBy(0, -15); + } + } + function ajax_check_code(url, method_type, data_type, data, uid) { $.ajax({ method: method_type, diff --git a/yaksh/templates/base.html b/yaksh/templates/base.html index 007d9b8..e7c4a99 100644 --- a/yaksh/templates/base.html +++ b/yaksh/templates/base.html @@ -52,6 +52,7 @@ {% block content %} {% endblock %} </div> + </div> <footer class="footer" id="footer_div"> <div class="logged_user_info" align="center"> {% block info %} @@ -61,7 +62,6 @@ <p align="center">Developed by FOSSEE group, IIT Bombay</p> </div> </footer> - </div> </body> </html> diff --git a/yaksh/templates/exam.html b/yaksh/templates/exam.html index ce3bf44..d0812a4 100644 --- a/yaksh/templates/exam.html +++ b/yaksh/templates/exam.html @@ -33,15 +33,6 @@ </nav><!-- /.navbar --> {% endblock %} {% block content %} - <script> - $(document).ready(function() { - var ele = document.getElementById('error_panel') - if (ele) { - ele.scrollIntoView(true); - window.scrollBy(0, -15); - } - }); - </script> <div class="container-fluid"> <div class="col-sm-3 col-md-2 sidebar"> <p> Question Navigator </p> @@ -78,96 +69,11 @@ {% endblock %} </div> <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> - <div class="row"> <div class="row"> {% block main %} {% endblock %} </div> - <br/> - {% if question.type == 'code' or question.type == 'upload' %} - {% if error_message %} - <div class="row" id="error_panel"> - {% for error in error_message %} - <div class="panel panel-danger"> - <div class="panel-heading">Error No. {{ forloop.counter }}</div> - <div class="panel-body"> - <div class="well well-sm"> - {% if not error.type %} - <pre><code> {{error|safe}} </code></pre> - {% elif error.type == 'assertion' %} - {% if error.test_case %} - <strong> We tried your code with the following test case:</strong><br/></br> - <pre><code><strong style="color:#d9534f">{{error.test_case}}</strong></code></pre> - {% endif %} - <p> <b>The following error took place: </b></p> - <table class="table table-bordered" width="100%" id='assertion'> - <col width="30%"> - <tr class = "active"> - <td><b>Exception Name: </b></td> - <td><span style="color: #d9534f">{{error.exception}}</span></td> - </tr> - <tr> - <td><b>Exception Message: </b></td><td>{{error.message}}</td> - </tr> - <tr> - {% if error.traceback %} - <td><b>Full Traceback: </b></td> - <td><pre>{{error.traceback}}</pre></td> - {% endif %} - </tr> - </table> - {% elif error.type == 'stdio' %} - {% if error.given_input %} - <table class="table table-bordered"> - <col width="30%"> - <tr class = "active"> - <td> For given Input value(s):</td> - <td>{{error.given_input}}</td> - </tr> - </table> - {% endif %} - <table class="table table-bordered" width="100%" id="stdio"> - <col width="10%"> - <col width="40%"> - <col width="40%"> - <col width="10%"> - <tr class="info"> - <th><center>Line No.</center></th> - <th><center>Expected Output</center></th> - <th><center>User output</center></th> - <th><center>Status</center></th> - </tr> - {% for expected,user in error.expected_output|zip:error.user_output %} - <td> {{forloop.counter}} </td> - <td>{{expected|default:""}} </td> - <td>{{user|default:""}}</td> - {% if forloop.counter0 in error.error_line_numbers or not expected or not user %} - <td><span class ="glyphicon glyphicon-remove text-warning"/></td> - {% else %} - <td><span class ="glyphicon glyphicon-ok text-success"/></td> - {% endif %} - </tr> - {% endfor %} - </table> - <table width="100%" class='table table-bordered'> - <col width="10"> - <tr class = "danger"> - <td><b>Error:</b></td> - <td>{{error.error_msg}}</td> - </tr> - </table> - - {% endif %} </div> - </div> - </div> - {% endfor %} - - </div> - {% endif %} - {% endif %} - </div> </div> - </div> -</div> + {% endblock %} diff --git a/yaksh/templates/yaksh/complete.html b/yaksh/templates/yaksh/complete.html index c99b8f0..6c0d878 100644 --- a/yaksh/templates/yaksh/complete.html +++ b/yaksh/templates/yaksh/complete.html @@ -5,7 +5,7 @@ {% csrf_token %} {% if paper.questions_answered.all or paper.questions_unanswered.all %} <center><table class="table table-bordered" > - <caption> <center><h2>Submission Status</h2> </center></caption> + <caption> <center><h3>Submission Status</h3> </center></caption> <thead> <tr> <th> Question</th> diff --git a/yaksh/templates/yaksh/error_template.html b/yaksh/templates/yaksh/error_template.html new file mode 100644 index 0000000..61657ae --- /dev/null +++ b/yaksh/templates/yaksh/error_template.html @@ -0,0 +1,91 @@ +{% block css%} + <link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/dashboard.css" type="text/css" /> +{% endblock %} + +{% load custom_filters %} + +{% if error_message %} + {% for error in error_message %} + + <div class="panel panel-danger"> + <div class="panel-heading">Error No. {{ forloop.counter }}</div> + <div class="panel-body"> + <div class="well well-sm"> + {% if not error.type %} + <pre><code> {{error|safe}} </code></pre> + + {% elif error.type == 'assertion' %} + + {% if error.test_case %} + <strong> We tried your code with the following test case:</strong> + <br/></br> + <pre><code><strong style="color:#d9534f"> + {{error.test_case}} + </strong></code></pre> + {% endif %} + <p> <b>The following error took place: </b></p> + <table class="table table-bordered" width="100%" id='assertion'> + <col width="30%"> + <tr class = "active"> + <td><b>Exception Name: </b></td> + <td><span style="color: #d9534f">{{error.exception}}</span></td> + </tr> + <tr> + <td><b>Exception Message: </b></td><td>{{error.message}}</td> + </tr> + <tr> + {% if error.traceback %} + <td><b>Full Traceback: </b></td> + <td><pre>{{error.traceback}}</pre></td> + {% endif %} + </tr> + </table> + + {% elif error.type == 'stdio' %} + + {% if error.given_input %} + <table class="table table-bordered"> + <col width="30%"> + <tr class = "active"> + <td> For given Input value(s):</td> + <td>{{error.given_input}}</td> + </tr> + </table> + {% endif %} + + <table class="table table-bordered" width="100%" id="stdio"> + <col width="10%"> + <col width="40%"> + <col width="40%"> + <col width="10%"> + <tr class="info"> + <th><center>Line No.</center></th> + <th><center>Expected Output</center></th> + <th><center>User output</center></th> + <th><center>Status</center></th> + </tr> + {% for expected,user in error.expected_output|zip:error.user_output %} + <td> {{forloop.counter}} </td> + <td>{{expected|default:""}} </td> + <td>{{user|default:""}}</td> + {% if forloop.counter0 in error.error_line_numbers or not expected or not user %} + <td><span class ="glyphicon glyphicon-remove text-warning"/></td> + {% else %} + <td><span class ="glyphicon glyphicon-ok text-success"/></td> + {% endif %} + </tr> + {% endfor %} + </table> + <table width="100%" class='table table-bordered'> + <col width="10"> + <tr class = "danger"> + <td><b>Error:</b></td> + <td>{{error.error_msg}}</td> + </tr> + </table> + {% endif %} + </div> + </div> + </div> + {% endfor %} +{% endif %}
\ No newline at end of file diff --git a/yaksh/templates/yaksh/question.html b/yaksh/templates/yaksh/question.html index 12f5da6..674fafc 100644 --- a/yaksh/templates/yaksh/question.html +++ b/yaksh/templates/yaksh/question.html @@ -106,15 +106,15 @@ module_id = "{{module.id}}" {% get_unit_status course module unit user as status %} {% if unit.quiz.id == paper.question_paper.quiz.id %} - <span class="glyphicon glyphicon-pencil" data-toggle="tooltip" title="Current Unit"></span> + <span class="glyphicon glyphicon-pencil" data-toggle="tooltip" title="Currently on"></span> {% endif %} {% if unit.learning_type == "quiz" %} - <a href="{{ URL_ROOT }}/exam/start/{{unit.quiz.questionpaper_set.get.id}}/{{learning_module.id}}/{{course.id}}"> + <a href="{{ URL_ROOT }}/exam/start/{{unit.quiz.questionpaper_set.get.id}}/{{module.id}}/{{course.id}}"> {{ unit.quiz.description }} </a> {% else %} - <a href="{{ URL_ROOT }}/exam/show_video/{{unit.lesson.id}}/{{learning_module.id}}/{{course.id}}"> + <a href="{{ URL_ROOT }}/exam/show_lesson/{{unit.lesson.id}}/{{module.id}}/{{course.id}}"> {{ unit.lesson.name }} </a> {% endif %} @@ -200,19 +200,19 @@ module_id = "{{module.id}}" {% if question.type == "integer" %} Enter Integer:<br/> - <input name="answer" type="number" id="integer" value={{ last_attempt|safe }} /> + <input autofocus name="answer" type="number" id="integer" value={{ last_attempt|safe }} /> <br/><br/> {% endif %} {% if question.type == "string" %} Enter Text:<br/> - <textarea name="answer" id="string">{{ last_attempt|safe }}</textarea> + <textarea autofocus name="answer" id="string">{{ last_attempt|safe }}</textarea> <br/><br/> {% endif %} {% if question.type == "float" %} Enter Decimal Value :<br/> - <input name="answer" type="number" step="any" id="float" value={{ last_attempt|safe }} /> + <input autofocus name="answer" type="number" step="any" id="float" value={{ last_attempt|safe }} /> <br/><br/> {% endif %} @@ -242,7 +242,7 @@ module_id = "{{module.id}}" <a href="#answer" class="pull-right" onclick="reset_editor()" name="reset" id="reset">Undo Changes <span class="glyphicon glyphicon-refresh"></span></a> </div> </div> - <textarea name="answer" id="answer"></textarea> + <textarea autofocus name="answer" id="answer"></textarea> <br> {% endif %} <div class="from-group"> @@ -262,12 +262,16 @@ module_id = "{{module.id}}" {% if question in paper.get_questions_unanswered %} <button class="btn btn-primary" onclick="call_skip('{{ URL_ROOT }}/exam/{{ question.id }}/skip/{{ paper.attempt_number }}/{{ module.id }}/{{ paper.question_paper.id }}/{{course.id}}/')" name="skip" id="skip">Attempt Later <span class="glyphicon glyphicon-arrow-right"></span></button> {% endif %} - </div> - </div> - </div> - + {% endif %} + </div> </form> - {% endif %} + </div> + </div> + </div> + <br/> + {% if question.type == 'code' or question.type == 'upload' %} + <div class="row" id="error_panel"></div> + {% endif %} <!-- Modal --> <div class="modal fade " id="upload_alert" > diff --git a/yaksh/templates/yaksh/quit.html b/yaksh/templates/yaksh/quit.html index b168724..b38c21e 100644 --- a/yaksh/templates/yaksh/quit.html +++ b/yaksh/templates/yaksh/quit.html @@ -3,7 +3,7 @@ {% block pagetitle %} Yaksh Online Test {% endblock %} {% block content %} <center><table class="table table-bordered" > - <caption> Submission Status </caption> + <caption> <center><h3>Submission Status</h3> </center> </caption> <thead> <tr> <th> Question</th> diff --git a/yaksh/templates/yaksh/quizzes_user.html b/yaksh/templates/yaksh/quizzes_user.html index 3c4b985..26e550d 100644 --- a/yaksh/templates/yaksh/quizzes_user.html +++ b/yaksh/templates/yaksh/quizzes_user.html @@ -97,8 +97,8 @@ No Courses to display </td> <td> {% if unit.learning_type == "quiz" %} - {% if quiz.view_answerpaper %} - <a href="{{ URL_ROOT }}/exam/view_answerpaper/{{ quiz.questionpaper_set.get.id }}/"><i class="fa fa-eye" aria-hidden="true"></i> Can View </a> + {% if unit.quiz.view_answerpaper %} + <a href="{{ URL_ROOT }}/exam/view_answerpaper/{{ unit.quiz.questionpaper_set.get.id }}/{{course.id}}"><i class="fa fa-eye" aria-hidden="true"></i> Can View </a> {% else %} <a><i class="fa fa-eye-slash" aria-hidden="true"></i> Cannot view now </a> {% endif %} diff --git a/yaksh/templates/yaksh/show_video.html b/yaksh/templates/yaksh/show_video.html index ffb0c68..ff79808 100644 --- a/yaksh/templates/yaksh/show_video.html +++ b/yaksh/templates/yaksh/show_video.html @@ -23,7 +23,7 @@ {{ unit.quiz.description }} </a> {% else %} - <a href="{{ URL_ROOT }}/exam/show_video/{{unit.lesson.id}}/{{learning_module.id}}/{{course.id}}"> + <a href="{{ URL_ROOT }}/exam/show_lesson/{{unit.lesson.id}}/{{learning_module.id}}/{{course.id}}"> {{ unit.lesson.name }} </a> {% endif %} @@ -42,9 +42,11 @@ {% block main %} {% if msg %} <center> -<div class="alert alert-warning">{{msg}}</div> +<div class="col-md-12 col-md-offset-1 main"> +<div class="alert alert-warning">{{msg}}</div></div> </center> {% endif %} +<div class="col-md-12 col-md-offset-1 main"> {% if state == "module" %} <div class="panel panel-default"> <div class="panel-body"> @@ -71,4 +73,5 @@ </a> </div> {% endif %} +</div> {% endblock %}
\ No newline at end of file diff --git a/yaksh/test_views.py b/yaksh/test_views.py index 2dddcef..a5bd25e 100644 --- a/yaksh/test_views.py +++ b/yaksh/test_views.py @@ -9,6 +9,7 @@ except ImportError: import zipfile import shutil from textwrap import dedent +from markdown import Markdown from django.contrib.auth.models import Group from django.contrib.auth import authenticate @@ -23,7 +24,8 @@ from django.core.files.uploadedfile import SimpleUploadedFile from yaksh.models import User, Profile, Question, Quiz, QuestionPaper,\ QuestionSet, AnswerPaper, Answer, Course, StandardTestCase,\ AssignmentUpload, FileUpload, McqTestCase, IntegerTestCase, StringTestCase,\ - FloatTestCase, FIXTURES_DIR_PATH + FloatTestCase, FIXTURES_DIR_PATH, LearningModule, LearningUnit, Lesson,\ + LessonFile from yaksh.decorators import user_has_profile @@ -492,8 +494,15 @@ class TestMonitor(TestCase): duration=30, active=True, instructions="Demo Instructions", attempts_allowed=-1, time_between_attempts=0, description='demo quiz', pass_criteria=40, - language='Python', course=self.course + creator=self.user ) + self.learning_unit = LearningUnit.objects.create( + order=1, learning_type="quiz", quiz=self.quiz) + self.learning_module = LearningModule.objects.create( + order=1, name="test module", description="test", + creator=self.user, check_prerequisite=False) + self.learning_module.learning_unit.add(self.learning_unit.id) + self.course.learning_module.add(self.learning_module) self.question = Question.objects.create( summary="Test_question", description="Add two numbers", @@ -514,7 +523,7 @@ class TestMonitor(TestCase): start_time=datetime(2014, 10, 9, 10, 8, 15, 0, tzone), end_time=datetime(2014, 10, 9, 10, 15, 15, 0, tzone), user_ip="127.0.0.1", status="completed", passed=True, - percent=1, marks_obtained=1 + percent=1, marks_obtained=1, course=self.course ) self.answerpaper.answers.add(self.new_answer) self.answerpaper.questions_answered.add(self.question) @@ -529,6 +538,8 @@ class TestMonitor(TestCase): self.question.delete() self.question_paper.delete() self.new_answer.delete() + self.learning_module.delete() + self.learning_unit.delete() def test_monitor_denies_student(self): """ @@ -568,7 +579,8 @@ class TestMonitor(TestCase): password=self.user_plaintext_pass ) response = self.client.get(reverse('yaksh:monitor', - kwargs={'quiz_id': self.quiz.id}), + kwargs={'quiz_id': self.quiz.id, + 'course_id': self.course.id}), follow=True ) @@ -588,7 +600,8 @@ class TestMonitor(TestCase): ) response = self.client.get(reverse('yaksh:user_data', kwargs={'user_id':self.student.id, - 'questionpaper_id': self.question_paper.id}), + 'questionpaper_id': self.question_paper.id, + 'course_id': self.course.id}), follow=True ) self.assertEqual(response.status_code, 200) @@ -655,8 +668,15 @@ class TestGradeUser(TestCase): duration=30, active=True, instructions="Demo Instructions", attempts_allowed=-1, time_between_attempts=0, description='demo quiz', pass_criteria=40, - language='Python', course=self.course + creator=self.user ) + self.learning_unit = LearningUnit.objects.create( + order=1, learning_type="quiz", quiz=self.quiz) + self.learning_module = LearningModule.objects.create( + order=1, name="test module", description="test", + creator=self.user, check_prerequisite=False) + self.learning_module.learning_unit.add(self.learning_unit.id) + self.course.learning_module.add(self.learning_module) self.question = Question.objects.create( summary="Test_question", description="Add two numbers", @@ -677,7 +697,7 @@ class TestGradeUser(TestCase): start_time=datetime(2014, 10, 9, 10, 8, 15, 0, tzone), end_time=datetime(2014, 10, 9, 10, 15, 15, 0, tzone), user_ip="127.0.0.1", status="completed", passed=True, - marks_obtained=0.5 + marks_obtained=0.5, course=self.course ) self.answerpaper.answers.add(self.new_answer) self.answerpaper.questions_answered.add(self.question) @@ -693,6 +713,8 @@ class TestGradeUser(TestCase): self.question.delete() self.question_paper.delete() self.new_answer.delete() + self.learning_module.delete() + self.learning_unit.delete() def test_grade_user_denies_student(self): """ @@ -731,7 +753,8 @@ class TestGradeUser(TestCase): password=self.user_plaintext_pass ) response = self.client.get(reverse('yaksh:grade_user', - kwargs={"quiz_id": self.quiz.id}), + kwargs={"quiz_id": self.quiz.id, + 'course_id': self.course.id}), follow=True ) self.assertEqual(response.status_code, 200) @@ -751,6 +774,7 @@ class TestGradeUser(TestCase): ) response = self.client.get(reverse('yaksh:grade_user', kwargs={"quiz_id": self.quiz.id, + "course_id": self.course.id, "user_id": self.student.id}), follow=True ) @@ -771,6 +795,7 @@ class TestGradeUser(TestCase): ) self.client.get(reverse('yaksh:grade_user', kwargs={"quiz_id": self.quiz.id, + "course_id": self.course.id, "user_id": self.student.id}), follow=True ) @@ -778,6 +803,7 @@ class TestGradeUser(TestCase): response = self.client.post(reverse('yaksh:grade_user', kwargs={"quiz_id": self.quiz.id, "user_id": self.student.id, + "course_id": self.course.id, "attempt_number": self.answerpaper.attempt_number}), data={question_marks: 1.0} ) @@ -848,9 +874,15 @@ class TestDownloadAssignment(TestCase): 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='demo_quiz', pass_criteria=40, - language='Python', course=self.course + description='demo_quiz', pass_criteria=40 ) + self.learning_unit = LearningUnit.objects.create( + order=1, learning_type="quiz", quiz=self.quiz) + self.learning_module = LearningModule.objects.create( + order=1, name="test module", description="test", + creator=self.user, check_prerequisite=False) + self.learning_module.learning_unit.add(self.learning_unit.id) + self.course.learning_module.add(self.learning_module) self.question = Question.objects.create( summary="Test_question", description="Assignment Upload", @@ -886,6 +918,8 @@ class TestDownloadAssignment(TestCase): self.assignment2.delete() self.quiz.delete() self.course.delete() + self.learning_module.delete() + self.learning_unit.delete() dir_name = self.quiz.description.replace(" ", "_") file_path = os.sep.join((settings.MEDIA_ROOT, dir_name)) if os.path.exists(file_path): @@ -999,24 +1033,13 @@ class TestAddQuiz(TestCase): self.course = Course.objects.create(name="Python Course", enrollment="Enroll Request", creator=self.user) - self.pre_req_quiz = Quiz.objects.create( - start_date_time=datetime(2014, 2, 1, 5, 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='pre requisite quiz', pass_criteria=40, - language='Python', prerequisite=None, - course=self.course - ) - self.quiz = 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='demo quiz', pass_criteria=40, - language='Python', prerequisite=self.pre_req_quiz, - course=self.course + creator=self.user ) def tearDown(self): @@ -1024,18 +1047,16 @@ class TestAddQuiz(TestCase): self.user.delete() self.student.delete() self.quiz.delete() - self.pre_req_quiz.delete() self.course.delete() def test_add_quiz_denies_anonymous(self): """ If not logged in redirect to login page """ - response = self.client.get(reverse('yaksh:add_quiz', - kwargs={'course_id': self.course.id}), + response = self.client.get(reverse('yaksh:add_quiz'), follow=True ) - redirect_destination = '/exam/login/?next=/exam/manage/addquiz/{0}/'.format(self.course.id) + redirect_destination = '/exam/login/?next=/exam/manage/addquiz/' self.assertRedirects(response, redirect_destination) def test_add_quiz_denies_non_moderator(self): @@ -1047,8 +1068,7 @@ class TestAddQuiz(TestCase): password=self.student_plaintext_pass ) course_id = self.course.id - response = self.client.get(reverse('yaksh:add_quiz', - kwargs={'course_id': self.course.id}), + response = self.client.get(reverse('yaksh:add_quiz'), follow=True ) self.assertEqual(response.status_code, 404) @@ -1061,8 +1081,7 @@ class TestAddQuiz(TestCase): username=self.user.username, password=self.user_plaintext_pass ) - response = self.client.get(reverse('yaksh:add_quiz', - kwargs={'course_id': self.course.id}) + response = self.client.get(reverse('yaksh:add_quiz') ) self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'yaksh/add_quiz.html') @@ -1078,7 +1097,7 @@ class TestAddQuiz(TestCase): ) tzone = pytz.timezone('UTC') response = self.client.post(reverse('yaksh:edit_quiz', - kwargs={'course_id':self.course.id, 'quiz_id': self.quiz.id}), + kwargs={'quiz_id': self.quiz.id}), data={ 'start_date_time': '2016-01-10 09:00:15', 'end_date_time': '2016-01-15 09:00:15', @@ -1088,10 +1107,8 @@ class TestAddQuiz(TestCase): 'time_between_attempts': 1, 'description': 'updated demo quiz', 'pass_criteria': 40, - 'language': 'java', 'instructions': "Demo Instructions", - 'prerequisite': self.pre_req_quiz.id, - 'course': self.course.id + 'weightage': 1.0 } ) @@ -1108,12 +1125,9 @@ class TestAddQuiz(TestCase): self.assertEqual(updated_quiz.time_between_attempts, 1) self.assertEqual(updated_quiz.description, 'updated demo quiz') self.assertEqual(updated_quiz.pass_criteria, 40) - self.assertEqual(updated_quiz.language, 'java') - self.assertEqual(updated_quiz.prerequisite, self.pre_req_quiz) - self.assertEqual(updated_quiz.course, self.course) self.assertEqual(response.status_code, 302) - self.assertRedirects(response, '/exam/manage/courses/') + self.assertRedirects(response, '/exam/manage/courses/all_quizzes/') def test_add_quiz_post_new_quiz(self): """ @@ -1125,8 +1139,7 @@ class TestAddQuiz(TestCase): ) tzone = pytz.timezone('UTC') - response = self.client.post(reverse('yaksh:add_quiz', - kwargs={"course_id": self.course.id}), + response = self.client.post(reverse('yaksh:add_quiz'), data={ 'start_date_time': '2016-01-10 09:00:15', 'end_date_time': '2016-01-15 09:00:15', @@ -1136,10 +1149,8 @@ class TestAddQuiz(TestCase): 'time_between_attempts': 2, 'description': 'new demo quiz', 'pass_criteria': 50, - 'language': 'python', 'instructions': "Demo Instructions", - 'prerequisite': self.pre_req_quiz.id, - 'course': self.course.id + 'weightage': 1.0 } ) quiz_list = Quiz.objects.all().order_by('-id') @@ -1156,12 +1167,9 @@ class TestAddQuiz(TestCase): self.assertEqual(new_quiz.time_between_attempts, 2) self.assertEqual(new_quiz.description, 'new demo quiz') self.assertEqual(new_quiz.pass_criteria, 50) - self.assertEqual(new_quiz.language, 'python') - self.assertEqual(new_quiz.prerequisite, self.pre_req_quiz) - self.assertEqual(new_quiz.course, self.course) self.assertEqual(response.status_code, 302) - self.assertRedirects(response, '/exam/manage/courses/') + self.assertRedirects(response, '/exam/manage/courses/all_quizzes/') class TestAddTeacher(TestCase): @@ -1212,8 +1220,7 @@ class TestAddTeacher(TestCase): duration=30, active=True, attempts_allowed=-1, time_between_attempts=0, description='pre requisite quiz', pass_criteria=40, - language='Python', prerequisite=None, - course=self.course + creator=self.user ) self.quiz = Quiz.objects.create( @@ -1222,8 +1229,7 @@ class TestAddTeacher(TestCase): duration=30, active=True, attempts_allowed=-1, time_between_attempts=0, description='demo quiz', pass_criteria=40, - language='Python', prerequisite=self.pre_req_quiz, - course=self.course + creator=self.user ) def tearDown(self): @@ -1372,8 +1378,7 @@ class TestRemoveTeacher(TestCase): duration=30, active=True, attempts_allowed=-1, time_between_attempts=0, description='pre requisite quiz', pass_criteria=40, - language='Python', prerequisite=None, - course=self.course + creator=self.user ) self.quiz = Quiz.objects.create( @@ -1382,8 +1387,7 @@ class TestRemoveTeacher(TestCase): duration=30, active=True, attempts_allowed=-1, time_between_attempts=0, description='demo quiz', pass_criteria=40, - language='Python', prerequisite=self.pre_req_quiz, - course=self.course + creator=self.user ) def tearDown(self): self.client.logout() @@ -1521,13 +1525,31 @@ class TestCourses(TestCase): email='demo_student@test.com' ) + self.teacher_plaintext_pass = 'teacher' + self.teacher = User.objects.create_user( + username='teacher', + password=self.teacher_plaintext_pass, + first_name='teacher_first_name', + last_name='teacher_last_name', + email='demo_teacher@test.com' + ) + # Add to moderator group self.mod_group.user_set.add(self.user1) self.mod_group.user_set.add(self.user2) + self.mod_group.user_set.add(self.teacher) + + # Create a learning module to add to course + self.learning_module = LearningModule.objects.create( + order=0, name="test module", description="module", + check_prerequisite=False, creator=self.teacher) self.user1_course = Course.objects.create(name="Python Course", enrollment="Enroll Request", creator=self.user1) + # Add teacher to user1 course + self.user1_course.teachers.add(self.teacher) + self.user2_course = Course.objects.create(name="Java Course", enrollment="Enroll Request", creator=self.user2) @@ -1538,8 +1560,8 @@ class TestCourses(TestCase): self.student.delete() self.user1_course.delete() self.user2_course.delete() - - + self.teacher.delete() + self.learning_module.delete() def test_courses_denies_anonymous(self): """ @@ -1583,6 +1605,64 @@ class TestCourses(TestCase): self.assertIn(self.user1_course, response.context['courses']) self.assertNotIn(self.user2_course, response.context['courses']) + def test_teacher_can_design_course(self): + """ Check if teacher can design the course i.e add learning modules """ + self.client.login( + username=self.teacher.username, + password=self.teacher_plaintext_pass + ) + response = self.client.post( + reverse('yaksh:design_course', + kwargs={"course_id": self.user1_course.id}), + data={"Add": "Add", + "module_list": [str(self.learning_module.id)] + }) + + # Test add learning module + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/design_course_session.html') + added_learning_module = self.user1_course.learning_module.all().first() + self.assertEqual(self.learning_module, added_learning_module) + self.assertEqual(added_learning_module.order, 1) + + # Test change order of learning module + response = self.client.post( + reverse('yaksh:design_course', + kwargs={"course_id": self.user1_course.id}), + data={"Change": "Change", "ordered_list": ",".join( + [str(self.learning_module.id)+":"+"0"] + )} + ) + updated_learning_module = LearningModule.objects.get( + id=self.learning_module.id) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/design_course_session.html') + self.assertEqual(updated_learning_module.order, 0) + + # Test change check prerequisite + response = self.client.post( + reverse('yaksh:design_course', + kwargs={"course_id": self.user1_course.id}), + data={"Change_prerequisite": "Change_prerequisite", + "check_prereq": [str(self.learning_module.id)] + }) + updated_learning_module = LearningModule.objects.get( + id=self.learning_module.id) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/design_course_session.html') + self.assertTrue(updated_learning_module.check_prerequisite) + + # Test to remove learning module from course + response = self.client.post( + reverse('yaksh:design_course', + kwargs={"course_id": self.user1_course.id}), + data={"Remove": "Remove", + "delete_list": [str(self.learning_module.id)] + }) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/design_course_session.html') + self.assertFalse(self.user1_course.learning_module.all().exists()) + class TestAddCourse(TestCase): def setUp(self): @@ -1632,8 +1712,7 @@ class TestAddCourse(TestCase): duration=30, active=True, attempts_allowed=-1, time_between_attempts=0, description='pre requisite quiz', pass_criteria=40, - language='Python', prerequisite=None, - course=self.course + creator=self.user ) self.quiz = Quiz.objects.create( @@ -1642,8 +1721,7 @@ class TestAddCourse(TestCase): duration=30, active=True, attempts_allowed=-1, time_between_attempts=0, description='demo quiz', pass_criteria=40, - language='Python', prerequisite=self.pre_req_quiz, - course=self.course + creator=self.user ) def tearDown(self): @@ -1714,7 +1792,8 @@ class TestAddCourse(TestCase): self.assertEqual(new_course.enrollment, 'open') self.assertEqual(new_course.active, True) self.assertEqual(response.status_code, 302) - self.assertRedirects(response, '/exam/manage/') + self.assertRedirects(response, '/exam/manage/courses', + target_status_code=301) class TestCourseDetail(TestCase): @@ -2082,12 +2161,11 @@ class TestCourseDetail(TestCase): response = self.client.post(reverse('yaksh:toggle_course_status', kwargs={'course_id': self.user1_course.id}) ) - self.assertEqual(response.status_code, 200) + self.assertEqual(response.status_code, 302) course = Course.objects.get(name="Python Course") self.assertFalse(course.active) - self.assertEqual(self.user1_course, response.context['course']) - self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, 'yaksh/course_detail.html') + self.assertRedirects(response, '/exam/manage/courses', + target_status_code=301) def test_send_mail_to_course_students(self): """ Check if bulk mail is sent to multiple students enrolled in a course @@ -2281,8 +2359,8 @@ class TestViewAnswerPaper(TestCase): self.question = Question.objects.create(summary='Dummy', points=1, type='code', user=self.user1) - self.quiz = Quiz.objects.create(time_between_attempts=0, course=self.course, - description='demo quiz', language='Python') + self.quiz = Quiz.objects.create(time_between_attempts=0, + description='demo quiz') self.user3 = User.objects.get(username="demo_user3") self.question_paper = QuestionPaper.objects.create(quiz=self.quiz, total_marks=1.0) @@ -2292,7 +2370,8 @@ class TestViewAnswerPaper(TestCase): self.ans_paper = AnswerPaper.objects.create(user=self.user3, attempt_number=1, question_paper=self.question_paper, start_time=timezone.now(), user_ip='101.0.0.1', - end_time=timezone.now()+timezone.timedelta(minutes=20)) + end_time=timezone.now()+timezone.timedelta(minutes=20), + course=self.course) def tearDown(self): User.objects.all().delete() @@ -2305,11 +2384,13 @@ class TestViewAnswerPaper(TestCase): def test_anonymous_user(self): # Given, user not logged in redirect_destination = ('/exam/login/?next=/exam' - '/view_answerpaper/{0}/'.format(self.question_paper.id)) + '/view_answerpaper/{0}/{1}'.format( + self.question_paper.id, self.course.id)) # When response = self.client.get(reverse('yaksh:view_answerpaper', - kwargs={'questionpaper_id': self.question_paper.id} + kwargs={'questionpaper_id': self.question_paper.id, + 'course_id': self.course.id} ), follow=True ) @@ -2331,7 +2412,8 @@ class TestViewAnswerPaper(TestCase): # When response = self.client.get(reverse('yaksh:view_answerpaper', - kwargs={'questionpaper_id': self.question_paper.id} + kwargs={'questionpaper_id': self.question_paper.id, + 'course_id': self.course.id} ), follow=True ) @@ -2354,7 +2436,8 @@ class TestViewAnswerPaper(TestCase): # When response = self.client.get(reverse('yaksh:view_answerpaper', - kwargs={'questionpaper_id': self.question_paper.id} + kwargs={'questionpaper_id': self.question_paper.id, + 'course_id': self.course.id} ), follow=True ) @@ -2368,7 +2451,8 @@ class TestViewAnswerPaper(TestCase): # When, wrong question paper id response = self.client.get(reverse('yaksh:view_answerpaper', - kwargs={'questionpaper_id': 190} + kwargs={'questionpaper_id': 190, + 'course_id': self.course.id} ), follow=True ) @@ -2391,7 +2475,8 @@ class TestViewAnswerPaper(TestCase): # When response = self.client.get(reverse('yaksh:view_answerpaper', - kwargs={'questionpaper_id': self.question_paper.id} + kwargs={'questionpaper_id': self.question_paper.id, + 'course_id': self.course.id} ), follow=True ) @@ -2565,8 +2650,8 @@ class TestGrader(TestCase): self.question = Question.objects.create(summary='Dummy', points=1, type='code', user=self.user1) - self.quiz = Quiz.objects.create(time_between_attempts=0, course=self.course, - description='demo quiz', language='Python') + self.quiz = Quiz.objects.create(time_between_attempts=0, + description='demo quiz') self.question_paper = QuestionPaper.objects.create(quiz=self.quiz, total_marks=1.0) @@ -2576,7 +2661,8 @@ class TestGrader(TestCase): self.answerpaper = AnswerPaper.objects.create(user=self.user2, attempt_number=1, question_paper=self.question_paper, start_time=timezone.now(), user_ip='101.0.0.1', - end_time=timezone.now()+timezone.timedelta(minutes=20)) + end_time=timezone.now()+timezone.timedelta(minutes=20), + course=self.course) def tearDown(self): User.objects.all().delete() @@ -2832,7 +2918,7 @@ class TestModeratorDashboard(TestCase): duration=30, active=True, instructions="Demo Instructions", attempts_allowed=-1, time_between_attempts=0, description='demo quiz', pass_criteria=40, - language='Python', course=self.course + creator=self.user ) self.question = Question.objects.create( @@ -2856,20 +2942,22 @@ class TestModeratorDashboard(TestCase): start_time=datetime(2014, 10, 9, 10, 8, 15, 0, tzone), end_time=datetime(2014, 10, 9, 10, 15, 15, 0, tzone), user_ip="127.0.0.1", status="completed", passed=True, - marks_obtained=0.5 + marks_obtained=0.5, course=self.course ) self.answerpaper.answers.add(self.new_answer) self.answerpaper.questions_answered.add(self.question) self.answerpaper.questions.add(self.question) # moderator trial answerpaper + self.trial_course = Course.objects.create(name="Trial Course", + enrollment="Enroll Request", creator=self.user, is_trial=True) self.trial_quiz = 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='trial quiz', pass_criteria=40, - language='Python', course=self.course, is_trial=True + is_trial=True ) self.trial_question_paper = QuestionPaper.objects.create( @@ -2887,7 +2975,7 @@ class TestModeratorDashboard(TestCase): start_time=datetime(2014, 10, 9, 10, 8, 15, 0, tzone), end_time=datetime(2014, 10, 9, 10, 15, 15, 0, tzone), user_ip="127.0.0.1", status="completed", passed=True, - marks_obtained=0.5 + marks_obtained=0.5, course=self.trial_course ) self.trial_answerpaper.answers.add(self.new_answer1) self.trial_answerpaper.questions_answered.add(self.question) @@ -2913,7 +3001,6 @@ class TestModeratorDashboard(TestCase): follow=True ) self.assertEqual(response.status_code, 200) - self.assertRedirects(response, '/exam/quizzes/') def test_moderator_dashboard_get_for_user_without_profile(self): """ @@ -2954,12 +3041,7 @@ class TestModeratorDashboard(TestCase): self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, "yaksh/moderator_dashboard.html") self.assertEqual(response.context['trial_paper'][0], self.trial_answerpaper) - paper, answer_papers, users_passed, users_failed =\ - response.context['users_per_paper'][0] - self.assertEqual(paper, self.question_paper) - self.assertEqual(answer_papers[0], self.answerpaper) - self.assertEqual(users_passed, 1) - self.assertEqual(users_failed, 0) + self.assertEqual(response.context['courses'][0], self.course) def test_moderator_dashboard_delete_trial_papers(self): """ @@ -2982,7 +3064,7 @@ class TestModeratorDashboard(TestCase): description=self.trial_question_paper.quiz.description ) updated_course = Course.objects.filter( - name=self.trial_question_paper.quiz.course.name) + name=self.trial_course.name) self.assertSequenceEqual(updated_answerpaper, []) self.assertSequenceEqual(updated_quiz, []) self.assertSequenceEqual(updated_course, []) @@ -3103,7 +3185,7 @@ class TestDownloadcsv(TestCase): duration=30, active=True, instructions="Demo Instructions", attempts_allowed=-1, time_between_attempts=0, description='demo quiz', pass_criteria=40, - language='Python', course=self.course + creator=self.user ) self.question = Question.objects.create( @@ -3127,7 +3209,7 @@ class TestDownloadcsv(TestCase): start_time=datetime(2014, 10, 9, 10, 8, 15, 0, tzone), end_time=datetime(2014, 10, 9, 10, 15, 15, 0, tzone), user_ip="127.0.0.1", status="completed", passed=True, - marks_obtained=0.5 + marks_obtained=0.5, course=self.course ) self.answerpaper.answers.add(self.new_answer) self.answerpaper.questions_answered.add(self.question) @@ -3405,7 +3487,11 @@ class TestShowQuestions(TestCase): trial_que_paper = QuestionPaper.objects.get( quiz__description="trial_questions" ) - redirection_url = "/exam/start/1/{}".format(trial_que_paper.id) + trial_course = Course.objects.get(name="trial_course") + trial_module = trial_course.learning_module.all()[0] + redirection_url = "/exam/start/1/{0}/{1}/{2}".format( + trial_module.id, trial_que_paper.id, trial_course.id + ) self.assertEqual(response.status_code, 302) self.assertRedirects(response, redirection_url, target_status_code=301) @@ -3484,7 +3570,7 @@ class TestShowStatistics(TestCase): duration=30, active=True, instructions="Demo Instructions", attempts_allowed=-1, time_between_attempts=0, description='demo quiz', pass_criteria=40, - language='Python', course=self.course + creator=self.user ) self.question = Question.objects.create( @@ -3506,7 +3592,7 @@ class TestShowStatistics(TestCase): start_time=datetime(2014, 10, 9, 10, 8, 15, 0, tzone), end_time=datetime(2014, 10, 9, 10, 15, 15, 0, tzone), user_ip="127.0.0.1", status="completed", passed=True, - percent=1, marks_obtained=1 + percent=1, marks_obtained=1, course=self.course ) self.answerpaper.answers.add(self.new_answer) self.answerpaper.questions_answered.add(self.question) @@ -3532,7 +3618,8 @@ class TestShowStatistics(TestCase): password=self.student_plaintext_pass ) response = self.client.get(reverse('yaksh:show_statistics', - kwargs={"questionpaper_id": self.question_paper.id}), + kwargs={"questionpaper_id": self.question_paper.id, + "course_id": self.course.id}), follow=True ) self.assertEqual(response.status_code, 404) @@ -3546,7 +3633,8 @@ class TestShowStatistics(TestCase): password=self.user_plaintext_pass ) response = self.client.get(reverse('yaksh:show_statistics', - kwargs={'questionpaper_id': self.question_paper.id}), + kwargs={'questionpaper_id': self.question_paper.id, + "course_id": self.course.id}), follow=True ) self.assertEqual(response.status_code, 200) @@ -3567,7 +3655,8 @@ class TestShowStatistics(TestCase): ) response = self.client.get(reverse('yaksh:show_statistics', kwargs={'questionpaper_id': self.question_paper.id, - 'attempt_number': self.answerpaper.attempt_number}), + 'attempt_number': self.answerpaper.attempt_number, + "course_id": self.course.id}), follow=True ) self.assertEqual(response.status_code, 200) @@ -3616,9 +3705,17 @@ class TestQuestionPaper(TestCase): duration=30, active=True, instructions="Demo Instructions", attempts_allowed=-1, time_between_attempts=0, description='demo quiz', pass_criteria=40, - language='Python', course=self.course + creator=self.user ) + self.learning_unit = LearningUnit.objects.create( + order=1, learning_type="quiz", quiz=self.quiz) + self.learning_module = LearningModule.objects.create( + order=1, name="test module", description="module", + check_prerequisite=False, creator=self.user) + self.learning_module.learning_unit.add(self.learning_unit.id) + self.course.learning_module.add(self.learning_module) + # Mcq Question self.question_mcq = Question.objects.create( summary="Test_mcq_question", description="Test MCQ", @@ -3706,7 +3803,7 @@ class TestQuestionPaper(TestCase): start_time=datetime(2014, 10, 9, 10, 8, 15, 0, tzone), end_time=datetime(2014, 10, 9, 10, 15, 15, 0, tzone), user_ip="127.0.0.1", status="inprogress", passed=False, - percent=0, marks_obtained=0 + percent=0, marks_obtained=0, course=self.course ) self.answerpaper.questions.add(*questions_list) @@ -3720,6 +3817,8 @@ class TestQuestionPaper(TestCase): self.question_mcc.delete() self.question_int.delete() self.question_paper.delete() + self.learning_module.delete() + self.learning_unit.delete() def test_mcq_attempt_right_after_wrong(self): """ Case:- Check if answerpaper and answer marks are updated after @@ -3738,7 +3837,9 @@ class TestQuestionPaper(TestCase): self.client.post( reverse('yaksh:check', kwargs={"q_id": self.question_mcq.id, "attempt_num": 1, - "questionpaper_id": self.question_paper.id}), + "questionpaper_id": self.question_paper.id, + "course_id": self.course.id, + "module_id": self.learning_module.id}), data={"answer": wrong_user_answer} ) @@ -3753,7 +3854,9 @@ class TestQuestionPaper(TestCase): self.client.post( reverse('yaksh:check', kwargs={"q_id": self.question_mcq.id, "attempt_num": 1, - "questionpaper_id": self.question_paper.id}), + "questionpaper_id": self.question_paper.id, + "course_id": self.course.id, + "module_id": self.learning_module.id}), data={"answer": right_user_answer} ) @@ -3778,7 +3881,9 @@ class TestQuestionPaper(TestCase): self.client.post( reverse('yaksh:check', kwargs={"q_id": self.question_mcq.id, "attempt_num": 1, - "questionpaper_id": self.question_paper.id}), + "questionpaper_id": self.question_paper.id, + "course_id": self.course.id, + "module_id": self.learning_module.id}), data={"answer": right_user_answer} ) @@ -3793,7 +3898,9 @@ class TestQuestionPaper(TestCase): self.client.post( reverse('yaksh:check', kwargs={"q_id": self.question_mcq.id, "attempt_num": 1, - "questionpaper_id": self.question_paper.id}), + "questionpaper_id": self.question_paper.id, + "course_id": self.course.id, + "module_id": self.learning_module.id}), data={"answer": wrong_user_answer} ) @@ -3818,7 +3925,9 @@ class TestQuestionPaper(TestCase): self.client.post( reverse('yaksh:check', kwargs={"q_id": self.question_mcc.id, "attempt_num": 1, - "questionpaper_id": self.question_paper.id}), + "questionpaper_id": self.question_paper.id, + "course_id": self.course.id, + "module_id": self.learning_module.id}), data={"answer": right_user_answer} ) @@ -3833,7 +3942,9 @@ class TestQuestionPaper(TestCase): self.client.post( reverse('yaksh:check', kwargs={"q_id": self.question_mcc.id, "attempt_num": 1, - "questionpaper_id": self.question_paper.id}), + "questionpaper_id": self.question_paper.id, + "course_id": self.course.id, + "module_id": self.learning_module.id}), data={"answer": wrong_user_answer} ) @@ -3858,7 +3969,9 @@ class TestQuestionPaper(TestCase): self.client.post( reverse('yaksh:check', kwargs={"q_id": self.question_int.id, "attempt_num": 1, - "questionpaper_id": self.question_paper.id}), + "questionpaper_id": self.question_paper.id, + "course_id": self.course.id, + "module_id": self.learning_module.id}), data={"answer": right_user_answer} ) @@ -3873,7 +3986,9 @@ class TestQuestionPaper(TestCase): self.client.post( reverse('yaksh:check', kwargs={"q_id": self.question_int.id, "attempt_num": 1, - "questionpaper_id": self.question_paper.id}), + "questionpaper_id": self.question_paper.id, + "course_id": self.course.id, + "module_id": self.learning_module.id}), data={"answer": wrong_user_answer} ) @@ -3898,7 +4013,9 @@ class TestQuestionPaper(TestCase): self.client.post( reverse('yaksh:check', kwargs={"q_id": self.question_str.id, "attempt_num": 1, - "questionpaper_id": self.question_paper.id}), + "questionpaper_id": self.question_paper.id, + "course_id": self.course.id, + "module_id": self.learning_module.id}), data={"answer": right_user_answer} ) @@ -3913,7 +4030,9 @@ class TestQuestionPaper(TestCase): self.client.post( reverse('yaksh:check', kwargs={"q_id": self.question_str.id, "attempt_num": 1, - "questionpaper_id": self.question_paper.id}), + "questionpaper_id": self.question_paper.id, + "course_id": self.course.id, + "module_id": self.learning_module.id}), data={"answer": wrong_user_answer} ) @@ -3938,7 +4057,9 @@ class TestQuestionPaper(TestCase): self.client.post( reverse('yaksh:check', kwargs={"q_id": self.question_float.id, "attempt_num": 1, - "questionpaper_id": self.question_paper.id}), + "questionpaper_id": self.question_paper.id, + "course_id": self.course.id, + "module_id": self.learning_module.id}), data={"answer": right_user_answer} ) @@ -3953,10 +4074,553 @@ class TestQuestionPaper(TestCase): self.client.post( reverse('yaksh:check', kwargs={"q_id": self.question_float.id, "attempt_num": 1, - "questionpaper_id": self.question_paper.id}), + "questionpaper_id": self.question_paper.id, + "course_id": self.course.id, + "module_id": self.learning_module.id}), data={"answer": wrong_user_answer} ) # Then wrong_answer_paper = AnswerPaper.objects.get(id=self.answerpaper.id) self.assertEqual(wrong_answer_paper.marks_obtained, 0) + + +class TestLearningModule(TestCase): + def setUp(self): + self.client = Client() + + self.mod_group = Group.objects.create(name='moderator') + tzone = pytz.timezone('UTC') + # Create Moderator with profile + self.user_plaintext_pass = 'demo' + self.user = User.objects.create_user( + username='demo_user', + password=self.user_plaintext_pass, + first_name='first_name', + last_name='last_name', + email='demo@test.com' + ) + + Profile.objects.create( + user=self.user, + roll_number=10, + institute='IIT', + department='Chemical', + position='Moderator', + timezone='UTC' + ) + + # Create a student + self.student_plaintext_pass = 'demo_student' + self.student = User.objects.create_user( + username='demo_student', + password=self.student_plaintext_pass, + first_name='first_name', + last_name='last_name', + email='demo@student.com' + ) + + # Create a teacher to add to the course + self.teacher_plaintext_pass = 'demo_teacher' + self.teacher = User.objects.create_user( + username='demo_teacher', + password=self.teacher_plaintext_pass, + first_name='first_name', + last_name='last_name', + email='demo@student.com' + ) + + # Add to moderator group + self.mod_group.user_set.add(self.user) + self.mod_group.user_set.add(self.teacher) + + self.course = Course.objects.create( + name="Python Course", + enrollment="Open Enrollment", creator=self.user) + + self.question = Question.objects.create( + summary="Test_question", description="Add two numbers", + points=1.0, language="python", type="code", user=self.user + ) + self.quiz = Quiz.objects.create( + start_date_time=datetime(2014, 10, 9, 10, 8, 15, 0, tzone), + end_date_time=datetime(2199, 10, 9, 10, 8, 15, 0, tzone), + duration=30, active=True, instructions="Demo Instructions", + attempts_allowed=-1, time_between_attempts=0, + description='demo quiz', pass_criteria=40, + creator=self.user + ) + + self.question_paper = QuestionPaper.objects.create( + quiz=self.quiz, + total_marks=5.0, fixed_question_order=str(self.question.id) + ) + + self.question_paper.fixed_questions.add(self.question) + + self.lesson = Lesson.objects.create( + name="test lesson", description="test description", + creator=self.user) + # create quiz leanring unit + self.learning_unit = LearningUnit.objects.create( + order=0, learning_type="quiz", quiz=self.quiz) + # create lesson leanring unit + self.learning_unit1 = LearningUnit.objects.create( + order=1, learning_type="lesson", lesson=self.lesson) + # create learning module + self.learning_module = LearningModule.objects.create( + order=0, name="test module", description="module", + check_prerequisite=False, creator=self.user) + self.learning_module.learning_unit.add(self.learning_unit) + self.learning_module.learning_unit.add(self.learning_unit1) + self.learning_module1 = LearningModule.objects.create( + order=0, name="my module", description="my description", + check_prerequisite=False, creator=self.user) + self.course.teachers.add(self.teacher) + self.course.learning_module.add(self.learning_module) + + self.expected_url = "/exam/manage/courses/all_learning_module/" + + def tearDown(self): + self.user.delete() + self.student.delete() + self.teacher.delete() + self.quiz.delete() + self.course.delete() + self.learning_unit.delete() + self.learning_module.delete() + + def test_add_new_module_denies_non_moderator(self): + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass + ) + + # Student tries to add learning module + response = self.client.post(reverse('yaksh:add_module'), + data={"name": "test module1", + "description": "my test1", + "Save": "Save"}) + self.assertEqual(response.status_code, 404) + + # Student tries to view learning modules + response = self.client.get(reverse('yaksh:show_all_modules')) + self.assertEqual(response.status_code, 404) + + def test_add_new_module(self): + """ Check if new module is created """ + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + + # Test add new module + response = self.client.post(reverse('yaksh:add_module'), + data={"name": "test module1", + "description": "my test1", + "Save": "Save"}) + + self.assertEqual(response.status_code, 302) + self.assertRedirects(response, self.expected_url) + learning_module = LearningModule.objects.get(name="test module1") + self.assertEqual(learning_module.description, "my test1") + self.assertEqual(learning_module.creator, self.user) + self.assertTrue(learning_module.check_prerequisite) + self.assertEqual(learning_module.html_data, + Markdown().convert("my test1")) + + def test_edit_module(self): + """ Check if existing module is editable """ + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + + # Test add new module + response = self.client.post( + reverse('yaksh:edit_module', + kwargs={"module_id": self.learning_module.id}), + data={"name": "test module2", + "description": "my test2", + "Save": "Save"}) + + self.assertEqual(response.status_code, 302) + self.assertRedirects(response, self.expected_url) + learning_module = LearningModule.objects.get(name="test module2") + self.assertEqual(learning_module.description, "my test2") + self.assertEqual(learning_module.creator, self.user) + self.assertFalse(learning_module.check_prerequisite) + self.assertEqual(learning_module.html_data, + Markdown().convert("my test2")) + + def test_show_all_modules(self): + """Try to get all learning modules""" + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + response = self.client.get(reverse('yaksh:show_all_modules')) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/courses.html') + self.assertEqual(response.context['type'], "learning_module") + self.assertEqual(response.context['learning_modules'][0], + self.learning_module) + + def test_teacher_can_edit_module(self): + """ Check if teacher can edit the module """ + self.client.login( + username=self.teacher.username, + password=self.teacher_plaintext_pass + ) + response = self.client.post( + reverse('yaksh:edit_module', + kwargs={"module_id": self.learning_module.id, + "course_id": self.course.id}), + data={"name": "teacher module 2", + "description": "teacher module 2", + "Save": "Save"}) + + self.assertEqual(response.status_code, 302) + self.assertRedirects(response, "/exam/manage/courses/") + learning_module = LearningModule.objects.get(name="teacher module 2") + self.assertEqual(learning_module.description, "teacher module 2") + self.assertEqual(learning_module.creator, self.user) + + def test_teacher_can_design_module(self): + """ Check if teacher can design the module i.e add learning units """ + self.client.login( + username=self.teacher.username, + password=self.teacher_plaintext_pass + ) + response = self.client.post( + reverse('yaksh:design_module', + kwargs={"module_id": self.learning_module1.id, + "course_id": self.course.id}), + data={"Add": "Add", + "choosen_list": ",".join([str(self.quiz.id)+":"+"quiz"]) + }) + + # Test add learning unit + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/add_module.html') + learning_unit = self.learning_module1.learning_unit.all().first() + self.assertEqual(self.quiz, learning_unit.quiz) + self.assertEqual(learning_unit.learning_type, "quiz") + self.assertEqual(learning_unit.order, 1) + + # Test change order of learning unit + response = self.client.post( + reverse('yaksh:design_module', + kwargs={"module_id": self.learning_module1.id, + "course_id": self.course.id}), + data={"Change": "Change", + "ordered_list": ",".join([str(learning_unit.id)+":"+"0"]) + }) + updated_learning_unit = LearningUnit.objects.get(id=learning_unit.id) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/add_module.html') + self.assertEqual(updated_learning_unit.order, 0) + + # Test change check prerequisite + response = self.client.post( + reverse('yaksh:design_module', + kwargs={"module_id": self.learning_module1.id, + "course_id": self.course.id}), + data={"Change_prerequisite": "Change_prerequisite", + "check_prereq": [str(learning_unit.id)] + }) + updated_learning_unit = LearningUnit.objects.get(id=learning_unit.id) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/add_module.html') + self.assertFalse(updated_learning_unit.check_prerequisite) + + # Test to remove learning unit from learning module + response = self.client.post( + reverse('yaksh:design_module', + kwargs={"module_id": self.learning_module1.id, + "course_id": self.course.id}), + data={"Remove": "Remove", + "delete_list": [str(learning_unit.id)] + }) + updated_learning_unit = LearningUnit.objects.filter( + id=learning_unit.id).exists() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/add_module.html') + self.assertFalse(updated_learning_unit) + self.assertFalse(self.learning_module1.learning_unit.all().exists()) + + def test_get_learning_units_for_design(self): + self.client.login( + username=self.teacher.username, + password=self.teacher_plaintext_pass + ) + response = self.client.get( + reverse('yaksh:design_module', + kwargs={"module_id": self.learning_module1.id, + "course_id": self.course.id})) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/add_module.html') + self.assertEqual(response.context['quiz_les_list'], set()) + self.assertEqual(len(response.context['learning_units']), 0) + self.assertEqual(response.context['status'], "design") + self.assertEqual(response.context['module_id'], + str(self.learning_module1.id)) + self.assertEqual(response.context['course_id'], str(self.course.id)) + + def test_view_module(self): + """ Student tries to view a module containing learning units """ + + # Student is not enrolled in the course is thrown out + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass + ) + response = self.client.get( + reverse('yaksh:view_module', + kwargs={"module_id": self.learning_module.id, + "course_id": self.course.id})) + self.assertEqual(response.status_code, 404) + + # add student to the course + self.course.students.add(self.student.id) + + # check if enrolled student can view module + response = self.client.get( + reverse('yaksh:view_module', + kwargs={"module_id": self.learning_module.id, + "course_id": self.course.id})) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, "yaksh/show_video.html") + self.assertEqual(response.context['learning_units'][0], + self.learning_unit) + self.assertEqual(response.context["state"], "module") + self.assertEqual(response.context["first_unit"], self.learning_unit) + self.assertEqual(response.context["user"], self.student) + + def test_get_next_unit(self): + """ Check if we get correct next unit """ + + # Student who is not enrolled is thrown out + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass + ) + response = self.client.get( + reverse('yaksh:view_module', + kwargs={"module_id": self.learning_module.id, + "course_id": self.course.id})) + self.assertEqual(response.status_code, 404) + + # Enroll student in the course + self.course.students.add(self.student.id) + + # Get First unit as next unit + response = self.client.get( + reverse('yaksh:next_unit', + kwargs={"module_id": self.learning_module.id, + "course_id": self.course.id, + "current_unit_id": self.learning_unit.id, + "first_unit": "1"}), + follow=True) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context['attempt_num'], 1) + self.assertEqual(response.context["questionpaper"], + self.question_paper) + self.assertEqual(response.context["course"], self.course) + self.assertEqual(response.context["module"], self.learning_module) + self.assertEqual(response.context["user"], self.student) + + # Get next unit after first unit + response = self.client.get( + reverse('yaksh:next_unit', + kwargs={"module_id": self.learning_module.id, + "course_id": self.course.id, + "current_unit_id": self.learning_unit.id}), + follow=True) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context["state"], "lesson") + self.assertEqual(response.context["current_unit"].id, + self.learning_unit1.id) + + +class TestLessons(TestCase): + def setUp(self): + self.client = Client() + + self.mod_group = Group.objects.create(name='moderator') + tzone = pytz.timezone('UTC') + # Create Moderator with profile + self.user_plaintext_pass = 'demo' + self.user = User.objects.create_user( + username='demo_user', + password=self.user_plaintext_pass, + first_name='first_name', + last_name='last_name', + email='demo@test.com' + ) + + Profile.objects.create( + user=self.user, + roll_number=10, + institute='IIT', + department='Chemical', + position='Moderator', + timezone='UTC' + ) + + # Create a student + self.student_plaintext_pass = 'demo_student' + self.student = User.objects.create_user( + username='demo_student', + password=self.student_plaintext_pass, + first_name='first_name', + last_name='last_name', + email='demo@student.com' + ) + + # Create a teacher to add to the course + self.teacher_plaintext_pass = 'demo_teacher' + self.teacher = User.objects.create_user( + username='demo_teacher', + password=self.teacher_plaintext_pass, + first_name='first_name', + last_name='last_name', + email='demo@student.com' + ) + + # Add to moderator group + self.mod_group.user_set.add(self.user) + self.mod_group.user_set.add(self.teacher) + + self.course = Course.objects.create( + name="Python Course", + enrollment="Open Enrollment", creator=self.user) + + self.quiz = 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='demo quiz', pass_criteria=40, + creator=self.user + ) + + self.lesson = Lesson.objects.create( + name="test lesson", description="test description", + creator=self.user) + self.learning_unit = LearningUnit.objects.create( + order=0, learning_type="lesson", lesson=self.lesson) + self.learning_module = LearningModule.objects.create( + order=0, name="test module", description="module", + check_prerequisite=False, creator=self.user) + self.learning_module.learning_unit.add(self.learning_unit.id) + self.course.learning_module.add(self.learning_module.id) + self.course.teachers.add(self.teacher.id) + + self.expected_url = "/exam/manage/courses/" + + def tearDown(self): + self.user.delete() + self.student.delete() + self.teacher.delete() + self.quiz.delete() + self.course.delete() + self.learning_unit.delete() + self.learning_module.delete() + self.lesson.delete() + + def test_edit_lesson_denies_non_moderator(self): + """ Student should not be allowed to edit lesson """ + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass + ) + + # Student tries to edit lesson + response = self.client.get( + reverse('yaksh:edit_lesson', + kwargs={"lesson_id": self.lesson.id, + "course_id": self.course.id})) + self.assertEqual(response.status_code, 404) + + def test_teacher_can_edit_lesson(self): + """ Teacher should be allowed to edit lesson """ + self.client.login( + username=self.teacher.username, + password=self.teacher_plaintext_pass + ) + dummy_file = SimpleUploadedFile("test.txt", b"test") + response = self.client.post( + reverse('yaksh:edit_lesson', + kwargs={"lesson_id": self.lesson.id, + "course_id": self.course.id}), + data={"name": "updated lesson", + "description": "updated description", + "Lesson_files": dummy_file, + "Save": "Save"} + ) + + # Teacher edits existing lesson and adds file + self.assertEqual(response.status_code, 302) + self.assertRedirects(response, self.expected_url) + updated_lesson = Lesson.objects.get(name="updated lesson") + self.assertEqual(updated_lesson.description, "updated description") + self.assertEqual(updated_lesson.creator, self.user) + self.assertEqual(updated_lesson.html_data, + Markdown().convert("updated description")) + lesson_files = LessonFile.objects.filter( + lesson=self.lesson).first() + self.assertIn("test.txt", lesson_files.file.name) + lesson_file_path = lesson_files.file.path + # Teacher removes the lesson file + response = self.client.post( + reverse('yaksh:edit_lesson', + kwargs={"lesson_id": self.lesson.id, + "course_id": self.course.id}), + data={"delete_files": [str(lesson_files.id)], + "Delete": "Delete"} + ) + self.assertEqual(response.status_code, 302) + self.assertRedirects(response, self.expected_url) + lesson_file_exists = LessonFile.objects.filter( + lesson=self.lesson).exists() + self.assertFalse(lesson_file_exists) + self.assertFalse(os.path.exists(lesson_file_path)) + + def test_show_lesson(self): + """ Student should be able to view lessons """ + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass + ) + response = self.client.get( + reverse('yaksh:show_lesson', + kwargs={"lesson_id": self.lesson.id, + "module_id": self.learning_module.id, + "course_id": self.course.id})) + # Student is unable to view lesson + self.assertEqual(response.status_code, 404) + + # Add student to course + self.course.students.add(self.student.id) + response = self.client.get( + reverse('yaksh:show_lesson', + kwargs={"lesson_id": self.lesson.id, + "module_id": self.learning_module.id, + "course_id": self.course.id})) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context["state"], "lesson") + self.assertEqual(response.context["current_unit"], self.learning_unit) + + def test_show_all_lessons(self): + """ Moderator should be able to see all created lessons""" + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + response = self.client.get(reverse('yaksh:show_all_lessons')) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, "yaksh/courses.html") + self.assertEqual(response.context["type"], "lesson") + self.assertEqual(response.context["lessons"][0], self.lesson) + diff --git a/yaksh/urls.py b/yaksh/urls.py index 8348666..dada74f 100644 --- a/yaksh/urls.py +++ b/yaksh/urls.py @@ -32,9 +32,10 @@ urlpatterns = [ views.skip), url(r'^enroll_request/(?P<course_id>\d+)/$', views.enroll_request, name='enroll_request'), url(r'^self_enroll/(?P<course_id>\d+)/$', views.self_enroll, name='self_enroll'), - url(r'^view_answerpaper/(?P<questionpaper_id>\d+)/$', views.view_answerpaper, name='view_answerpaper'), - url(r'^show_video/(?P<lesson_id>\d+)/(?P<module_id>\d+)/(?P<course_id>\d+)/$', - views.show_video, name='show_video'), + url(r'^view_answerpaper/(?P<questionpaper_id>\d+)/(?P<course_id>\d+)$', + views.view_answerpaper, name='view_answerpaper'), + url(r'^show_lesson/(?P<lesson_id>\d+)/(?P<module_id>\d+)/(?P<course_id>\d+)/$', + views.show_lesson, name='show_lesson'), url(r'^quizzes/view_module/(?P<module_id>\d+)/(?P<course_id>\d+)/$', views.view_module, name='view_module'), url(r'^next_unit/(?P<course_id>\d+)/(?P<module_id>\d+)/(?P<current_unit_id>\d+)/$', diff --git a/yaksh/views.py b/yaksh/views.py index 524d4d5..e0688f0 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -8,7 +8,7 @@ from django.http import HttpResponse, JsonResponse from django.core.urlresolvers import reverse from django.contrib.auth import login, logout, authenticate from django.shortcuts import render_to_response, get_object_or_404, redirect -from django.template import RequestContext +from django.template import RequestContext, Context, Template from django.http import Http404 from django.db.models import Sum, Max, Q, F from django.views.decorators.csrf import csrf_exempt @@ -296,6 +296,8 @@ def add_quiz(request, quiz_id=None, course_id=None): quiz = get_object_or_404(Quiz, pk=quiz_id) if quiz.creator != user: raise Http404('This quiz does not belong to you') + else: + quiz = None if course_id: course = get_object_or_404(Course, pk=course_id) if not course.is_creator(user) and not course.is_teacher(user): @@ -303,25 +305,15 @@ def add_quiz(request, quiz_id=None, course_id=None): context = {} if request.method == "POST": - if quiz_id is None: - form = QuizForm(request.POST) - if form.is_valid(): - form.instance.creator = user - form.save() - if not course_id: - return my_redirect("/exam/manage/courses/all_quizzes/") - else: - return my_redirect("/exam/manage/courses/") - else: - quiz = Quiz.objects.get(id=quiz_id) - form = QuizForm(request.POST, instance=quiz) - if form.is_valid(): + form = QuizForm(request.POST, instance=quiz) + if form.is_valid(): + if quiz is None: form.instance.creator = user - form.save() - if not course_id: - return my_redirect("/exam/manage/courses/all_quizzes/") - else: - return my_redirect("/exam/manage/courses/") + form.save() + if not course_id: + return my_redirect("/exam/manage/courses/all_quizzes/") + else: + return my_redirect("/exam/manage/courses/") else: quiz = Quiz.objects.get(id=quiz_id) if quiz_id else None @@ -728,9 +720,24 @@ def get_result(request, uid, course_id, module_id): result['status'] = result_state.get('status') if result['status'] == 'done': result = json.loads(result_state.get('result')) - next_question, error_message, paper = _update_paper(request, uid, result) - return show_question(request, next_question, paper, error_message, - course_id=course_id, module_id=module_id) + template_path = os.path.join(*[os.path.dirname(__file__), + 'templates', 'yaksh', + 'error_template.html' + ] + ) + next_question, error_message, paper = _update_paper(request, uid, + result + ) + if result.get('success'): + return show_question(request, next_question, paper, error_message, + course_id=course_id, module_id=module_id) + else: + with open(template_path) as f: + template_data = f.read() + template = Template(template_data) + context = Context({"error_message": result.get('error')}) + render_error = template.render(context) + result["error"] = render_error return JsonResponse(result) @@ -822,6 +829,8 @@ def add_course(request, course_id=None): ci = RequestContext(request) if course_id: course = Course.objects.get(id=course_id) + if not course.is_creator(user) and not course.is_teacher(user): + raise Http404("You are not allowed to view this course") else: course = None @@ -1732,7 +1741,8 @@ def test_quiz(request, mode, quiz_id, course_id=None): def view_answerpaper(request, questionpaper_id, course_id): user = request.user quiz = get_object_or_404(QuestionPaper, pk=questionpaper_id).quiz - if quiz.view_answerpaper and user in quiz.course.students.all(): + course = get_object_or_404(Course, pk=course_id) + if quiz.view_answerpaper and user in course.students.all(): data = AnswerPaper.objects.get_user_data(user, questionpaper_id, course_id) has_user_assignment = AssignmentUpload.objects.filter( @@ -2174,7 +2184,8 @@ def edit_lesson(request, lesson_id=None, course_id=None): lesson_file_form = LessonFileForm(request.POST, request.FILES) lessonfiles = request.FILES.getlist('Lesson_files') if lesson_form.is_valid(): - lesson_form.instance.creator = user + if lesson is None: + lesson_form.instance.creator = user lesson = lesson_form.save() lesson.html_data = get_html_text(lesson.description) lesson.save() @@ -2194,6 +2205,7 @@ def edit_lesson(request, lesson_id=None, course_id=None): files = LessonFile.objects.filter(id__in=remove_files_id) for file in files: file.remove() + return my_redirect(redirect_url) lesson_files = LessonFile.objects.filter(lesson=lesson) lesson_files_form = LessonFileForm() @@ -2209,7 +2221,7 @@ def edit_lesson(request, lesson_id=None, course_id=None): @login_required @email_verified -def show_video(request, lesson_id, module_id, course_id): +def show_lesson(request, lesson_id, module_id, course_id): user = request.user course = Course.objects.get(id=course_id) if user not in course.students.all(): @@ -2222,7 +2234,8 @@ def show_video(request, lesson_id, module_id, course_id): learning_units = learn_module.get_learning_units() if learn_unit.has_prerequisite(): if not learn_unit.is_prerequisite_passed(user, learn_module, course): - return my_redirect("/exam/quizzes/") + msg = "You have not passed the prerequisite" + return view_module(request, learn_module.id, course_id, msg=msg) context = {'lesson': learn_unit.lesson, 'user': user, 'course': course, 'state': "lesson", 'learning_units': learning_units, "current_unit": learn_unit, @@ -2328,7 +2341,8 @@ def add_module(request, module_id=None, course_id=None): if "Save" in request.POST: module_form = LearningModuleForm(request.POST, instance=module) if module_form.is_valid(): - module_form.instance.creator = user + if module is None: + module_form.instance.creator = user module = module_form.save() module.html_data = get_html_text(module.description) module.save() @@ -2429,7 +2443,7 @@ def get_next_unit(request, course_id, module_id, current_unit_id, return my_redirect("/exam/start/{0}/{1}/{2}".format( next_unit.quiz.questionpaper_set.get().id, module_id, course_id)) else: - return my_redirect("/exam/show_video/{0}/{1}/{2}".format( + return my_redirect("/exam/show_lesson/{0}/{1}/{2}".format( next_unit.lesson.id, module_id, course_id)) @@ -2509,7 +2523,7 @@ def view_module(request, module_id, course_id, msg=None): learning_module = course.learning_module.get(id=module_id) if learning_module.has_prerequisite(): if not learning_module.is_prerequisite_passed(user, course): - msg = "You have not completed previous learning module" + msg = "You have not completed the previous learning module" return quizlist_user(request, msg=msg) learning_units = learning_module.get_learning_units() context['learning_units'] = learning_units |