summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPrabhu Ramachandran2017-04-28 17:25:03 +0530
committerGitHub2017-04-28 17:25:03 +0530
commite56c50bb99a8694e8f1c8533df3f04e4613bcb08 (patch)
tree0935e7b5cdbb5d72d2c106ca7234520c985d4291
parentb285378b2eca29e7125bf9474cd57c973a202f37 (diff)
parent3597ee5fa814b0c7c737e72797d9e9911ca5e0dd (diff)
downloadonline_test-e56c50bb99a8694e8f1c8533df3f04e4613bcb08.tar.gz
online_test-e56c50bb99a8694e8f1c8533df3f04e4613bcb08.tar.bz2
online_test-e56c50bb99a8694e8f1c8533df3f04e4613bcb08.zip
Merge pull request #277 from ankitjavalkar/course-clone
Course clone
-rw-r--r--yaksh/models.py69
-rw-r--r--yaksh/templates/yaksh/course_detail.html4
-rw-r--r--yaksh/test_models.py202
-rw-r--r--yaksh/urls.py2
-rw-r--r--yaksh/views.py15
5 files changed, 292 insertions, 0 deletions
diff --git a/yaksh/models.py b/yaksh/models.py
index f6867f0..ad64f2a 100644
--- a/yaksh/models.py
+++ b/yaksh/models.py
@@ -151,6 +151,42 @@ class Course(models.Model):
objects = CourseManager()
+ def create_duplicate_course(self, user):
+ quizzes = self.quiz_set.all()
+ prerequisite_map = []
+ duplicate_quiz_map = {}
+ new_course = Course.objects.create(creator=user,
+ name="Copy Of {0}".format(self.name),
+ enrollment=self.enrollment,
+ active=self.active,
+ is_trial=self.is_trial,
+ instructions=self.instructions,
+ start_enroll_time=self.start_enroll_time,
+ end_enroll_time=self.end_enroll_time
+ )
+
+ new_course.teachers.add(*self.teachers.all())
+
+ for q in quizzes:
+ new_quiz = q._create_duplicate_quiz(new_course)
+ if q.id not in duplicate_quiz_map.keys():
+ duplicate_quiz_map[q.id] = new_quiz.id
+
+ for orig_qid, dupl_qid in duplicate_quiz_map.items():
+ original_quiz = Quiz.objects.get(id=orig_qid)
+ if original_quiz.prerequisite:
+ duplicate_quiz = Quiz.objects.get(id=dupl_qid)
+ prereq_id = original_quiz.prerequisite.id
+ duplicate_prereq_id = duplicate_quiz_map.get(prereq_id)
+ if duplicate_prereq_id:
+ duplicate_prerequisite = Quiz.objects.get(
+ id=duplicate_prereq_id
+ )
+ duplicate_quiz.prerequisite = duplicate_prerequisite
+ duplicate_quiz.save()
+
+ return new_course
+
def request(self, *users):
self.requests.add(*users)
@@ -656,6 +692,28 @@ class Quiz(models.Model):
def has_prerequisite(self):
return True if self.prerequisite else False
+ def _create_duplicate_quiz(self, course):
+ questionpaper = self.questionpaper_set.all()
+ new_quiz = Quiz.objects.create(course=course,
+ start_date_time=self.start_date_time,
+ end_date_time=self.end_date_time,
+ duration=self.duration,
+ active=self.active,
+ description="Copy Of {0}".format(self.description),
+ pass_criteria=self.pass_criteria,
+ language=self.language,
+ attempts_allowed=self.attempts_allowed,
+ time_between_attempts=self.time_between_attempts,
+ is_trial=self.is_trial,
+ instructions=self.instructions,
+ allow_skip=self.allow_skip
+ )
+
+ for qp in questionpaper:
+ qp._create_duplicate_questionpaper(new_quiz)
+
+ return new_quiz
+
def create_demo_quiz(self, course):
demo_quiz = Quiz.objects.create(
start_date_time=timezone.now(),
@@ -741,6 +799,17 @@ class QuestionPaper(models.Model):
objects = QuestionPaperManager()
+ def _create_duplicate_questionpaper(self, quiz):
+ new_questionpaper = QuestionPaper.objects.create(quiz=quiz,
+ shuffle_questions=self.shuffle_questions,
+ total_marks=self.total_marks,
+ fixed_question_order=self.fixed_question_order
+ )
+ new_questionpaper.fixed_questions.add(*self.fixed_questions.all())
+ new_questionpaper.random_questions.add(*self.random_questions.all())
+
+ return new_questionpaper
+
def update_total_marks(self):
""" Updates the total marks for the Question Paper"""
marks = 0.0
diff --git a/yaksh/templates/yaksh/course_detail.html b/yaksh/templates/yaksh/course_detail.html
index 81569fa..cd4144f 100644
--- a/yaksh/templates/yaksh/course_detail.html
+++ b/yaksh/templates/yaksh/course_detail.html
@@ -20,6 +20,10 @@
<a href="{{URL_ROOT}}/exam/manage/toggle_status/{{ course.id }}/">
{% if course.active %}Deactivate Course {% else %} Activate Course {% endif %}</a>
</li>
+ <li>
+ <a href="{{URL_ROOT}}/exam/manage/duplicate_course/{{ course.id }}/">
+ Clone Course</a>
+ </li>
</ul>
</div>
</div>
diff --git a/yaksh/test_models.py b/yaksh/test_models.py
index 9bd8492..5a61c0f 100644
--- a/yaksh/test_models.py
+++ b/yaksh/test_models.py
@@ -29,6 +29,14 @@ def setUpModule():
Profile.objects.create(user=student, roll_number=3, institute='IIT',
department='Chemical', position='Student')
+ user4 = User.objects.create_user(username='demo_user4',
+ password='demo',
+ email='demo4@test.com'
+ )
+ Profile.objects.create(user=user4, roll_number=4, institute='IIT',
+ department='Chemical', position='Student')
+
+
# create a course
course = Course.objects.create(name="Python Course",
enrollment="Enroll Request", creator=user)
@@ -833,10 +841,12 @@ class CourseTestCases(unittest.TestCase):
def setUp(self):
self.course = Course.objects.get(name="Python Course")
self.creator = User.objects.get(username="demo_user")
+ self.template_course_user = User.objects.get(username="demo_user4")
self.student1 = User.objects.get(username="demo_user2")
self.student2 = User.objects.get(username="demo_user3")
self.quiz1 = Quiz.objects.get(description='demo quiz 1')
self.quiz2 = Quiz.objects.get(description='demo quiz 2')
+ self.questions = Question.objects.filter(active=True)
# create courses with disabled enrollment
self.enroll_request_course = Course.objects.create(
@@ -862,6 +872,198 @@ class CourseTestCases(unittest.TestCase):
),
)
+ # create a course that will be cloned
+ self.template_course = Course.objects.create(
+ name="Template Course to clone",
+ enrollment="Open Course",
+ creator=self.creator,
+ start_enroll_time=datetime(2015, 10, 9, 10, 8, 15, 0,
+ tzinfo=pytz.utc
+ ),
+ end_enroll_time=datetime(2015, 11, 9, 10, 8, 15, 0,
+ tzinfo=pytz.utc
+ ),
+ )
+
+ self.template_quiz = Quiz.objects.create(
+ start_date_time=datetime(2014, 10, 9, 10, 8, 15, 0,
+ tzinfo=pytz.utc
+ ),
+ end_date_time=datetime(2015, 10, 9, 10, 8, 15, 0,
+ tzinfo=pytz.utc
+ ),
+ duration=30,
+ active=False,
+ attempts_allowed=-1,
+ time_between_attempts=0,
+ description='template quiz 1',
+ pass_criteria=40,
+ language='Python',
+ course=self.template_course,
+ instructions="Demo Instructions"
+ )
+
+ self.template_question_paper = QuestionPaper.objects.create(
+ quiz=self.template_quiz,
+ total_marks=0.0,
+ shuffle_questions=True
+ )
+
+ self.template_question_paper.fixed_questions.add(self.questions[1],
+ self.questions[2],
+ self.questions[3]
+ )
+
+ self.template_quiz2 = Quiz.objects.create(
+ start_date_time=datetime(2015, 10, 9, 10, 8, 15, 0, tzinfo=pytz.utc),
+ end_date_time=datetime(2199, 10, 9, 10, 8, 15, 0, tzinfo=pytz.utc),
+ duration=30,
+ active=True,
+ attempts_allowed=1,
+ time_between_attempts=0,
+ description='template quiz 2',
+ pass_criteria=0,
+ language='Python',
+ prerequisite=self.template_quiz,
+ course=self.template_course,
+ instructions="Demo Instructions"
+ )
+
+ self.template_question_paper2 = QuestionPaper.objects.create(
+ quiz=self.template_quiz2,
+ total_marks=0.0,
+ shuffle_questions=True
+ )
+
+ self.template_question_paper2.fixed_questions.add(self.questions[1],
+ self.questions[2],
+ self.questions[3]
+ )
+
+ def test_create_duplicate_course(self):
+ """ Test create_duplicate_course method of course """
+ # create a duplicate course
+ cloned_course = self.template_course.create_duplicate_course(
+ self.template_course_user
+ )
+ self.assertEqual(cloned_course.name,
+ 'Copy Of Template Course to clone')
+ self.assertEqual(cloned_course.enrollment,
+ self.template_course.enrollment
+ )
+ self.assertEqual(cloned_course.creator,
+ self.template_course_user
+ )
+ self.assertEqual(cloned_course.start_enroll_time,
+ self.template_course.start_enroll_time
+ )
+ self.assertEqual(cloned_course.end_enroll_time,
+ self.template_course.end_enroll_time
+ )
+
+ # get duplicate quiz associated with duplicate course
+ cloned_quiz = cloned_course.quiz_set.all()[0]
+
+ self.assertEqual(cloned_quiz.start_date_time,
+ self.template_quiz.start_date_time
+ )
+ self.assertEqual(cloned_quiz.end_date_time,
+ self.template_quiz.end_date_time
+ )
+ self.assertEqual(cloned_quiz.duration,
+ self.template_quiz.duration
+ )
+ self.assertEqual(cloned_quiz.active,
+ self.template_quiz.active
+ )
+ self.assertEqual(cloned_quiz.attempts_allowed,
+ self.template_quiz.attempts_allowed
+ )
+ self.assertEqual(cloned_quiz.time_between_attempts,
+ self.template_quiz.time_between_attempts
+ )
+ self.assertEqual(cloned_quiz.description,
+ 'Copy Of template quiz 1'
+ )
+ self.assertEqual(cloned_quiz.pass_criteria,
+ self.template_quiz.pass_criteria
+ )
+ self.assertEqual(cloned_quiz.language,
+ self.template_quiz.language
+ )
+ self.assertEqual(cloned_quiz.course,
+ cloned_course
+ )
+ self.assertEqual(cloned_quiz.instructions,
+ self.template_quiz.instructions
+ )
+
+ # Get duplicate questionpaper associated with duplicate quiz
+ cloned_qp = cloned_quiz.questionpaper_set.all()[0]
+
+ self.assertEqual(cloned_qp.quiz, cloned_quiz)
+ self.assertEqual(cloned_qp.total_marks,
+ self.template_question_paper.total_marks
+ )
+ self.assertEqual(cloned_qp.shuffle_questions,
+ self.template_question_paper.shuffle_questions
+ )
+
+ for q in cloned_qp.fixed_questions.all():
+ self.assertIn(q, self.template_question_paper.fixed_questions.all())
+
+ # get second duplicate quiz associated with duplicate course
+ cloned_quiz = cloned_course.quiz_set.all()[1]
+
+ self.assertEqual(cloned_quiz.start_date_time,
+ self.template_quiz2.start_date_time
+ )
+ self.assertEqual(cloned_quiz.end_date_time,
+ self.template_quiz2.end_date_time
+ )
+ self.assertEqual(cloned_quiz.duration,
+ self.template_quiz2.duration
+ )
+ self.assertEqual(cloned_quiz.active,
+ self.template_quiz2.active
+ )
+ self.assertEqual(cloned_quiz.attempts_allowed,
+ self.template_quiz2.attempts_allowed
+ )
+ self.assertEqual(cloned_quiz.time_between_attempts,
+ self.template_quiz2.time_between_attempts
+ )
+ self.assertEqual(cloned_quiz.description,
+ 'Copy Of template quiz 2'
+ )
+ self.assertEqual(cloned_quiz.pass_criteria,
+ self.template_quiz2.pass_criteria
+ )
+ self.assertEqual(cloned_quiz.language,
+ self.template_quiz2.language
+ )
+ self.assertEqual(cloned_quiz.course,
+ cloned_course
+ )
+ self.assertEqual(cloned_quiz.instructions,
+ self.template_quiz2.instructions
+ )
+
+ # Get second duplicate questionpaper associated with duplicate quiz
+ cloned_qp = cloned_quiz.questionpaper_set.all()[0]
+
+ self.assertEqual(cloned_qp.quiz, cloned_quiz)
+ self.assertEqual(cloned_qp.total_marks,
+ self.template_question_paper2.total_marks
+ )
+ self.assertEqual(cloned_qp.shuffle_questions,
+ self.template_question_paper2.shuffle_questions
+ )
+
+ for q in cloned_qp.fixed_questions.all():
+ self.assertIn(q, self.template_question_paper2.fixed_questions.all())
+
+
def test_is_creator(self):
""" Test is_creator method of Course"""
self.assertTrue(self.course.is_creator(self.creator))
diff --git a/yaksh/urls.py b/yaksh/urls.py
index 20ce918..b02b797 100644
--- a/yaksh/urls.py
+++ b/yaksh/urls.py
@@ -59,6 +59,8 @@ urlpatterns = [
views.show_statistics),
url(r'^manage/monitor/download_csv/(?P<questionpaper_id>\d+)/$',
views.download_csv),
+ 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 35df9f9..6a4325e 100644
--- a/yaksh/views.py
+++ b/yaksh/views.py
@@ -1597,3 +1597,18 @@ def download_assignment_file(request, quiz_id, question_id=None, user_id=None):
)
response.write(zipfile_name.read())
return response
+
+@login_required
+def duplicate_course(request, course_id):
+ user = request.user
+ course = get_object_or_404(Course, pk=course_id)
+ if not is_moderator(user):
+ raise Http404('You are not allowed to view this page!')
+
+ if course.is_teacher(user) or course.is_creator(user):
+ course.create_duplicate_course(user)
+ else:
+ msg = 'You do not have permissions to clone this course, please contact your '\
+ 'instructor/administrator.'
+ return complete(request, msg, attempt_num=None, questionpaper_id=None)
+ return my_redirect('/exam/manage/courses/')