diff options
author | Prabhu Ramachandran | 2018-03-21 18:18:19 +0530 |
---|---|---|
committer | GitHub | 2018-03-21 18:18:19 +0530 |
commit | cb6b1aad8f77035d1bfb598d8b70c51c23c435d7 (patch) | |
tree | 4720cf32e5e24c562ca6aad5f3c10ed062863c5e | |
parent | bff8d493aa2c83e971b067daf103e38b4392c4b9 (diff) | |
parent | 0ae21e437775b056d346311bd9f50220e5d9fb28 (diff) | |
download | online_test-cb6b1aad8f77035d1bfb598d8b70c51c23c435d7.tar.gz online_test-cb6b1aad8f77035d1bfb598d8b70c51c23c435d7.tar.bz2 online_test-cb6b1aad8f77035d1bfb598d8b70c51c23c435d7.zip |
Merge pull request #446 from adityacp/fix_clone_course
Fix clone course
-rw-r--r-- | yaksh/models.py | 70 | ||||
-rw-r--r-- | yaksh/templates/yaksh/complete.html | 3 | ||||
-rw-r--r-- | yaksh/templates/yaksh/courses.html | 16 | ||||
-rw-r--r-- | yaksh/templates/yaksh/design_course_session.html | 4 | ||||
-rw-r--r-- | yaksh/test_views.py | 98 | ||||
-rw-r--r-- | yaksh/urls.py | 4 | ||||
-rw-r--r-- | yaksh/views.py | 14 |
7 files changed, 166 insertions, 43 deletions
diff --git a/yaksh/models.py b/yaksh/models.py index ecc0fc4..08dac7c 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -163,6 +163,23 @@ class Lesson(models.Model): def get_files(self): return LessonFile.objects.filter(lesson=self) + def _create_lesson_copy(self, user): + lesson_files = self.get_files() + new_lesson = self + new_lesson.id = None + new_lesson.name = "Copy of {0}".format(self.name) + new_lesson.creator = user + new_lesson.save() + for _file in lesson_files: + file_name = os.path.basename(_file.file.name) + if os.path.exists(_file.file.path): + lesson_file = open(_file.file.path, "rb") + django_file = File(lesson_file) + lesson_file_obj = LessonFile() + lesson_file_obj.lesson = new_lesson + lesson_file_obj.file.save(file_name, django_file, save=True) + return new_lesson + ############################################################################# class LessonFile(models.Model): @@ -366,6 +383,17 @@ class Quiz(models.Model): course=course, passed=False ).values_list("user", flat=True).distinct().count() + def _create_quiz_copy(self, user): + question_papers = self.questionpaper_set.all() + new_quiz = self + new_quiz.id = None + new_quiz.description = "Copy of {0}".format(self.description) + new_quiz.creator = user + new_quiz.save() + for qp in question_papers: + qp._create_duplicate_questionpaper(new_quiz) + return new_quiz + def __str__(self): desc = self.description or 'Quiz' return '%s: on %s for %d minutes' % (desc, self.start_date_time, @@ -416,6 +444,17 @@ class LearningUnit(models.Model): success = False return success + def _create_unit_copy(self, user): + if self.type == "quiz": + new_quiz = self.quiz._create_quiz_copy(user) + new_unit = LearningUnit.objects.create( + order=self.order, type="quiz", quiz=new_quiz) + else: + new_lesson = self.lesson._create_lesson_copy(user) + new_unit = LearningUnit.objects.create( + order=self.order, type="lesson", lesson=new_lesson) + return new_unit + ############################################################################### class LearningModule(models.Model): @@ -511,6 +550,18 @@ class LearningModule(models.Model): percent = round((count / len(units)) * 100) return percent + def _create_module_copy(self, user, module_name): + learning_units = self.learning_unit.order_by("order") + new_module = self + new_module.id = None + new_module.name = module_name + new_module.creator = user + new_module.save() + for unit in learning_units: + new_unit = unit._create_unit_copy(user) + new_module.learning_unit.add(new_unit) + return new_module + def __str__(self): return self.name @@ -562,14 +613,13 @@ class Course(models.Model): return new_course def create_duplicate_course(self, user): - learning_modules = self.learning_module.all() - - new_course_name = "Copy Of {0}".format(self.name) - new_course = self._create_duplicate_instance(user, new_course_name) - - new_course.learning_module.add(*learning_modules) - - return new_course + learning_modules = self.learning_module.order_by("order") + copy_course_name = "Copy Of {0}".format(self.name) + new_course = self._create_duplicate_instance(user, copy_course_name) + for module in learning_modules: + copy_module_name = "Copy of {0}".format(module.name) + new_module = module._create_module_copy(user, copy_module_name) + new_course.learning_module.add(new_module) def request(self, *users): self.requests.add(*users) @@ -1162,8 +1212,8 @@ class QuestionPaper(models.Model): return questions def _create_duplicate_questionpaper(self, quiz): - new_questionpaper = QuestionPaper.objects.create(quiz=quiz, - shuffle_questions=self.shuffle_questions, + new_questionpaper = QuestionPaper.objects.create( + quiz=quiz, shuffle_questions=self.shuffle_questions, total_marks=self.total_marks, fixed_question_order=self.fixed_question_order ) diff --git a/yaksh/templates/yaksh/complete.html b/yaksh/templates/yaksh/complete.html index 3d6cadc..0881bfe 100644 --- a/yaksh/templates/yaksh/complete.html +++ b/yaksh/templates/yaksh/complete.html @@ -33,9 +33,6 @@ width="80" alt="YAKSH"></img>{% endblock %} <center><h3>{{message}}</h3></center> <center> <br> - {% if not module_id %} - <br><center><h4>You may now close the browser.</h4></center><br> - {% endif %} {% if module_id and not user == "moderator" %} {% if first_unit %} <a href="{{URL_ROOT}}/exam/next_unit/{{course_id}}/{{module_id}}/{{learning_unit.id}}/1" class="btn btn-info" id="Next"> Next diff --git a/yaksh/templates/yaksh/courses.html b/yaksh/templates/yaksh/courses.html index bc96bf5..78d21bf 100644 --- a/yaksh/templates/yaksh/courses.html +++ b/yaksh/templates/yaksh/courses.html @@ -4,6 +4,7 @@ {% block script %} <script> $(document).ready(function(){ + $('[data-toggle="tooltip"]').tooltip(); $("#created_courses").toggle(); $("#link_created_courses").click(function() { if ($("#allotted_courses").is(":visible")){ @@ -24,6 +25,14 @@ }); </script> {% endblock %} +{% block css %} +<style> + .test + .tooltip.top > .tooltip-inner { + padding: 15px; + font-size: 12px; + } +</style> +{% endblock %} {% block content %} <div class="row"> <div class="col-sm-3 col-md-2 sidebar"> @@ -99,7 +108,8 @@ <br><br> <ul> <li> - <a href="{{URL_ROOT}}/exam/manage/courses/designcourse/{{course.id}}/">Design Course + <a href="{{URL_ROOT}}/exam/manage/courses/designcourse/{{course.id}}/" data-toggle="tooltip" title="Add/Remove/Change course modules" data-placement="top"> + Design Course </a> </li> <br> @@ -123,7 +133,7 @@ </li> <br> <li> - <a href="{{URL_ROOT}}/exam/manage/duplicate_course/{{ course.id }}/"> + <a class="test" href="{{URL_ROOT}}/exam/manage/duplicate_course/{{ course.id }}/" data-toggle="tooltip" title="Creates Copy of selected Course as well as its Modules, Lessons/Quizzes" data-placement="top"> Clone Course</a> </li> </ul> @@ -259,7 +269,7 @@ </li> <br> <li> - <a href="{{URL_ROOT}}/exam/manage/duplicate_course/{{ course.id }}/"> + <a class="test" href="{{URL_ROOT}}/exam/manage/duplicate_course/{{ course.id }}/" data-toggle="tooltip" title="Creates Copy of selected Course as well as its Modules, Lessons/Quizzes" data-placement="top"> Clone Course</a> </li> </ul> diff --git a/yaksh/templates/yaksh/design_course_session.html b/yaksh/templates/yaksh/design_course_session.html index ee530e0..6542e3c 100644 --- a/yaksh/templates/yaksh/design_course_session.html +++ b/yaksh/templates/yaksh/design_course_session.html @@ -23,7 +23,7 @@ <div class="row"> <div class="col-md-8 col-md-offset-2 available-list"> <div id="fixed-available-wrapper"> - <p><u><b>Available Lessons and quizzes: (Add Lessons and Quizzes)</b></u></p> + <p><u><b>Available Modules:</b></u></p> <div id="fixed-available"> <table id="course-details" class="table table-bordered"> <tr> @@ -64,7 +64,7 @@ </div> <div class="col-md-8 col-md-offset-2"> <div id="fixed-added-wrapper"> - <p><u><b>Choosen Lessons and quizzes:</b></u></p> + <p><u><b>Choosen Modules:</b></u></p> <div id="fixed-added"> <table id="course-details" class="table table-bordered"> <tr> diff --git a/yaksh/test_views.py b/yaksh/test_views.py index 3b27338..faac617 100644 --- a/yaksh/test_views.py +++ b/yaksh/test_views.py @@ -20,6 +20,7 @@ from django.utils import timezone from django.core import mail from django.conf import settings from django.core.files.uploadedfile import SimpleUploadedFile +from django.core.files import File from yaksh.models import User, Profile, Question, Quiz, QuestionPaper,\ QuestionSet, AnswerPaper, Answer, Course, StandardTestCase,\ @@ -1668,13 +1669,38 @@ class TestCourses(TestCase): order=0, name="test module", description="module", check_prerequisite=False, creator=self.teacher) - self.user1_course = Course.objects.create(name="Python Course", + self.user1_course = Course.objects.create( + name="Python Course", enrollment="Enroll Request", creator=self.user1) + # Create Learning Module for Python Course + self.learning_module1 = LearningModule.objects.create( + order=0, name="demo module", description="module", + check_prerequisite=False, creator=self.user1) + + self.quiz = Quiz.objects.create( + time_between_attempts=0, description='demo quiz', + creator=self.user1) + self.question_paper = QuestionPaper.objects.create( + quiz=self.quiz, total_marks=1.0) + self.lesson = Lesson.objects.create( + name="demo lesson", description="test description", + creator=self.user1) + + self.lesson_unit = LearningUnit.objects.create( + order=1, type="lesson", lesson=self.lesson) + self.quiz_unit = LearningUnit.objects.create( + order=2, type="quiz", quiz=self.quiz) + + # Add units to module + self.learning_module1.learning_unit.add(self.lesson_unit) + self.learning_module1.learning_unit.add(self.quiz_unit) + # Add teacher to user1 course self.user1_course.teachers.add(self.teacher) - self.user2_course = Course.objects.create(name="Java Course", + self.user2_course = Course.objects.create( + name="Java Course", enrollment="Enroll Request", creator=self.user2) self.user2_course.learning_module.add(self.learning_module) @@ -1683,10 +1709,7 @@ class TestCourses(TestCase): self.user1.delete() self.user2.delete() self.student.delete() - self.user1_course.delete() - self.user2_course.delete() self.teacher.delete() - self.learning_module.delete() def test_courses_denies_anonymous(self): """ @@ -1837,7 +1860,7 @@ class TestCourses(TestCase): self.learning_module) def test_duplicate_course(self): - """ Test To clone/duplicate course """ + """ Test To clone/duplicate course and link modules""" # Student Login self.client.login( @@ -1869,27 +1892,64 @@ class TestCourses(TestCase): self.assertTemplateUsed(response, "yaksh/complete.html") self.assertIn(err_msg, response.context['message']) - # Moderator/Course creator login + # Test clone/duplicate courses and create copies of modules and units + + # Teacher Login + # Given + # Add files to a lesson + lesson_file = SimpleUploadedFile("file1.txt", b"Test") + django_file = File(lesson_file) + lesson_file_obj = LessonFile() + lesson_file_obj.lesson = self.lesson + lesson_file_obj.file.save(lesson_file.name, django_file, save=True) + + # Add module to Python Course + self.user1_course.learning_module.add(self.learning_module1) self.client.login( - username=self.user2.username, - password=self.user2_plaintext_pass + username=self.teacher.username, + password=self.teacher_plaintext_pass ) - - # Allows creator to duplicate the course response = self.client.get( reverse('yaksh:duplicate_course', - kwargs={"course_id": self.user2_course.id}), + kwargs={"course_id": self.user1_course.id}), follow=True ) - self.assertEqual(response.status_code, 200) + # When courses = Course.objects.filter( - creator=self.user2).order_by("id") - self.assertEqual(courses.count(), 2) - self.assertEqual(courses.last().creator, self.user2) - self.assertEqual(courses.last().name, "Copy Of Java Course") - self.assertEqual(courses.last().get_learning_modules()[0].id, - self.user2_course.get_learning_modules()[0].id) + creator=self.teacher).order_by("id") + module = courses.last().get_learning_modules()[0] + units = module.get_learning_units() + cloned_lesson = units[0].lesson + cloned_quiz = units[1].quiz + expected_lesson_files = cloned_lesson.get_files() + actual_lesson_files = self.lesson.get_files() + cloned_qp = cloned_quiz.questionpaper_set.get() + self.all_files = LessonFile.objects.filter( + lesson_id__in=[self.lesson.id, cloned_lesson.id]) + + # Then + self.assertEqual(response.status_code, 200) + self.assertEqual(courses.last().creator, self.teacher) + self.assertEqual(courses.last().name, "Copy Of Python Course") + self.assertEqual(module.name, "Copy of demo module") + self.assertEqual(module.creator, self.teacher) + self.assertEqual(module.order, 0) + self.assertEqual(len(units), 2) + self.assertEqual(cloned_lesson.name, "Copy of demo lesson") + self.assertEqual(cloned_lesson.creator, self.teacher) + self.assertEqual(cloned_quiz.description, "Copy of demo quiz") + self.assertEqual(cloned_quiz.creator, self.teacher) + self.assertEqual(cloned_qp.__str__(), + "Question Paper for Copy of demo quiz") + self.assertEqual(os.path.basename(expected_lesson_files[0].file.name), + os.path.basename(actual_lesson_files[0].file.name)) + + for lesson_file in self.all_files: + file_path = lesson_file.file.path + if os.path.exists(file_path): + os.remove(file_path) + shutil.rmtree(os.path.dirname(file_path)) class TestAddCourse(TestCase): diff --git a/yaksh/urls.py b/yaksh/urls.py index 08c2091..b81c7b2 100644 --- a/yaksh/urls.py +++ b/yaksh/urls.py @@ -86,8 +86,8 @@ urlpatterns = [ views.show_statistics, name="show_statistics"), url(r'^manage/download_quiz_csv/(?P<course_id>\d+)/(?P<quiz_id>\d+)/$', views.download_quiz_csv, name="download_quiz_csv"), - url(r'^manage/duplicate_course/(?P<course_id>\d+)/$', views.duplicate_course, - name='duplicate_course'), + url(r'^manage/duplicate_course/(?P<course_id>\d+)/$', + views.duplicate_course, name='duplicate_course'), url(r'manage/courses/$', views.courses, name='courses'), url(r'manage/add_course/$', views.add_course, name='add_course'), url(r'manage/edit_course/(?P<course_id>\d+)$', views.add_course, name='edit_course'), diff --git a/yaksh/views.py b/yaksh/views.py index 27a07d2..ec1807c 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -390,8 +390,8 @@ def prof_manage(request, msg=None): return my_redirect('/exam/login') if not is_moderator(user): return my_redirect('/exam/') - courses = Course.objects.filter(creator=user, is_trial=False) - + courses = Course.objects.filter(Q(creator=user) | Q(teachers=user), + is_trial=False) trial_paper = AnswerPaper.objects.filter( user=user, question_paper__quiz__is_trial=True, course__is_trial=True @@ -410,6 +410,7 @@ def prof_manage(request, msg=None): qpaper.quiz.delete() else: answerpaper.delete() + context = {'user': user, 'courses': courses, 'trial_paper': trial_paper, 'msg': msg } @@ -2255,10 +2256,15 @@ def duplicate_course(request, course_id): raise Http404('You are not allowed to view this page!') if course.is_teacher(user) or course.is_creator(user): + # Create new entries of modules, lessons/quizzes + # from current course to copied course course.create_duplicate_course(user) else: - msg = 'You do not have permissions to clone this course, please contact your '\ - 'instructor/administrator.' + msg = dedent( + '''\ + You do not have permissions to clone {0} course, please contact + your instructor/administrator.'''.format(course.name) + ) return complete(request, msg, attempt_num=None, questionpaper_id=None) return my_redirect('/exam/manage/courses/') |