From 4bb56b3ee2c28dfd684ac2e44f80187cfe522d10 Mon Sep 17 00:00:00 2001 From: adityacp Date: Fri, 17 Nov 2017 19:24:24 +0530 Subject: Change in models.py - Add new models LearningModule, LearningUnit, CourseStatus, Lesson, LessonFile - Change model associations - Add new model methods --- yaksh/models.py | 653 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 431 insertions(+), 222 deletions(-) (limited to 'yaksh') diff --git a/yaksh/models.py b/yaksh/models.py index 7e97e6c..a5dbd0a 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -121,6 +121,12 @@ def dict_to_yaml(dictionary): allow_unicode=True, ) + +def get_file_dir(instance, filename): + upload_dir = instance.lesson.name.replace(" ", "_") + return os.sep.join((upload_dir, filename)) + + ############################################################################### class CourseManager(models.Manager): @@ -134,6 +140,331 @@ class CourseManager(models.Manager): def get_hidden_courses(self, code): return self.filter(code=code, hidden=True) + +############################################################################# +class Lesson(models.Model): + name = models.CharField(max_length=255) + description = models.TextField() + html_data = models.TextField(null=True, blank=True) + creator = models.ForeignKey(User) + + def get_files(self): + return LessonFile.objects.filter(lesson=self) + + def get_lesson_completion_status(self, user, course): + course_status = CourseStatus.objects.filter(user=user, course=course) + if course_status.exists(): + learning_unit = course_status.first().completed_units.filter( + lesson_id=self.id) + if learning_unit.exists(): + return "completed" + else: + return "inprogress" + else: + return "not attempted" + + def __str__(self): + return "{0}".format(self.name) + + +############################################################################# +class LessonFile(models.Model): + lesson = models.ForeignKey(Lesson, related_name="lesson") + file = models.FileField(upload_to=get_file_dir) + + def remove(self): + if os.path.exists(self.file.path): + os.remove(self.file.path) + if os.listdir(os.path.dirname(self.file.path)) == []: + os.rmdir(os.path.dirname(self.file.path)) + self.delete() + + +############################################################################### +class QuizManager(models.Manager): + def get_active_quizzes(self): + return self.filter(active=True, is_trial=False) + + def create_trial_quiz(self, trial_course, user): + """Creates a trial quiz for testing questions""" + trial_quiz = self.create(duration=1000, + description="trial_questions", + is_trial=True, + time_between_attempts=0 + ) + return trial_quiz + + def create_trial_from_quiz(self, original_quiz_id, user, godmode, + course_id): + """Creates a trial quiz from existing quiz""" + trial_course_name = "Trial_course_for_course_{0}_{1}".format( + course_id, "godmode" if godmode else "usermode") + trial_quiz_name = "Trial_orig_id_{0}_{1}".format( + original_quiz_id, + "godmode" if godmode else "usermode" + ) + # Get or create Trial Course for usermode/godmode + trial_course = Course.objects.filter(name=trial_course_name) + if trial_course.exists(): + trial_course = trial_course.get(name=trial_course_name) + else: + trial_course = Course.objects.create( + name=trial_course_name, creator=user, enrollment="open", + is_trial=True) + + # Get or create Trial Quiz for usermode/godmode + if self.filter(description=trial_quiz_name).exists(): + trial_quiz = self.get(description=trial_quiz_name) + + else: + trial_quiz = self.get(id=original_quiz_id) + trial_quiz.user = user + trial_quiz.pk = None + trial_quiz.description = trial_quiz_name + trial_quiz.is_trial = True + trial_quiz.prerequisite = None + if godmode: + trial_quiz.time_between_attempts = 0 + trial_quiz.duration = 1000 + trial_quiz.attempts_allowed = -1 + trial_quiz.active = True + trial_quiz.start_date_time = timezone.now() + trial_quiz.end_date_time = datetime( + 2199, 1, 1, 0, 0, 0, 0, tzinfo=pytz.utc + ) + trial_quiz.save() + + # Get or create Trial Ordered Lesson for usermode/godmode + learning_modules = trial_course.get_learning_modules() + if learning_modules: + quiz = learning_modules[0].learning_unit.filter(quiz=trial_quiz) + if not quiz.exists(): + trial_learning_unit = LearningUnit.objects.create( + order=1, quiz=trial_quiz, learning_type="quiz", + check_prerequisite=False) + learning_modules[0].learning_unit.add(trial_learning_unit.id) + trial_learning_module = learning_modules[0] + else: + trial_learning_module = LearningModule.objects.create( + name="Trial for {}".format(trial_course), order=1, + check_prerequisite=False, creator=user, is_trial=True) + trial_learning_unit = LearningUnit.objects.create( + order=1, quiz=trial_quiz, learning_type="quiz", + check_prerequisite=False) + trial_learning_module.learning_unit.add(trial_learning_unit.id) + trial_course.learning_module.add(trial_learning_module.id) + + # Add user to trial_course + trial_course.enroll(False, user) + return trial_quiz, trial_course, trial_learning_module + + +############################################################################### +class Quiz(models.Model): + """A quiz that students will participate in. One can think of this + as the "examination" event. + """ + + # The start date of the quiz. + start_date_time = models.DateTimeField( + "Start Date and Time of the quiz", + default=timezone.now, + null=True + ) + + # The end date and time of the quiz + end_date_time = models.DateTimeField( + "End Date and Time of the quiz", + default=datetime( + 2199, 1, 1, + tzinfo=pytz.timezone(timezone.get_current_timezone_name()) + ), + null=True + ) + + # This is always in minutes. + duration = models.IntegerField("Duration of quiz in minutes", default=20) + + # Is the quiz active. The admin should deactivate the quiz once it is + # complete. + active = models.BooleanField(default=True) + + # Description of quiz. + description = models.CharField(max_length=256) + + # Mininum passing percentage condition. + pass_criteria = models.FloatField("Passing percentage", default=40) + + # Number of attempts for the quiz + attempts_allowed = models.IntegerField(default=1, choices=attempts) + + time_between_attempts = models.IntegerField( + "Number of Days", choices=days_between_attempts + ) + + is_trial = models.BooleanField(default=False) + + instructions = models.TextField('Instructions for Students', + default=None, blank=True, null=True) + + view_answerpaper = models.BooleanField('Allow student to view their answer\ + paper', default=False) + + allow_skip = models.BooleanField("Allow students to skip questions", + default=True) + + weightage = models.FloatField(default=1.0) + + creator = models.ForeignKey(User, null=True) + + objects = QuizManager() + + class Meta: + verbose_name_plural = "Quizzes" + + def is_expired(self): + return not self.start_date_time <= timezone.now() < self.end_date_time + + def create_demo_quiz(self, user): + demo_quiz = Quiz.objects.create( + start_date_time=timezone.now(), + end_date_time=timezone.now() + timedelta(176590), + duration=30, active=True, + attempts_allowed=-1, + time_between_attempts=0, + description='Yaksh Demo quiz', pass_criteria=0, + prerequisite=None, creator=user + ) + return demo_quiz + + def get_total_students(self, course): + return AnswerPaper.objects.filter( + question_paper=self.questionpaper_set.get().id, + course=course + ).values_list("user", flat=True).distinct().count() + + def get_passed_students(self, course): + return AnswerPaper.objects.filter( + question_paper=self.questionpaper_set.get().id, + course=course, passed=True + ).values_list("user", flat=True).distinct().count() + + def get_failed_students(self, course): + return AnswerPaper.objects.filter( + question_paper=self.questionpaper_set.get().id, + course=course, passed=False + ).values_list("user", flat=True).distinct().count() + + def get_quiz_completion_status(self, user, course): + ans_pprs = AnswerPaper.objects.filter( + question_paper=self.questionpaper_set.get().id, + user=user, course=course).order_by("-attempt_number") + if ans_pprs.exists(): + latest_ans_ppr_status = ans_pprs.first().status + else: + latest_ans_ppr_status = "not attempted" + return latest_ans_ppr_status + + def __str__(self): + desc = self.description or 'Quiz' + return '%s: on %s for %d minutes' % (desc, self.start_date_time, + self.duration) + + +########################################################################## +class LearningUnit(models.Model): + """ Maintain order of lesson and quiz added in the course """ + order = models.IntegerField() + learning_type = models.CharField(max_length=16) + lesson = models.ForeignKey(Lesson, null=True, blank=True) + quiz = models.ForeignKey(Quiz, null=True, blank=True) + check_prerequisite = models.BooleanField(default=True) + + def toggle_check_prerequisite(self): + if self.check_prerequisite: + self.check_prerequisite = False + else: + self.check_prerequisite = True + + def get_completion_status(self, user, course): + if self.learning_type == "quiz": + status = self.quiz.get_quiz_completion_status(user, course) + else: + status = self.lesson.get_lesson_completion_status(user, course) + return status + + def has_prerequisite(self): + return self.check_prerequisite + + def is_prerequisite_passed(self, user, learning_module, course): + ordered_units = learning_module.learning_unit.order_by("order") + ordered_units_ids = list(ordered_units.values_list("id", flat=True)) + current_unit_index = ordered_units_ids.index(self.id) + if current_unit_index == 0: + success = True + else: + prev_unit = ordered_units.get( + id=ordered_units_ids[current_unit_index-1]) + if prev_unit.learning_type == "quiz": + success = prev_unit.quiz.get_quiz_completion_status( + user, course) + else: + success = prev_unit.lesson.get_lesson_completion_status( + user, course) + return success + + +############################################################################### +class LearningModule(models.Model): + """ Learning Module to maintain learning units""" + learning_unit = models.ManyToManyField(LearningUnit, + related_name="learning_unit") + name = models.CharField(max_length=255) + description = models.TextField(default=None, null=True, blank=True) + order = models.IntegerField(default=0) + creator = models.ForeignKey(User, related_name="module_creator") + check_prerequisite = models.BooleanField(default=True) + html_data = models.TextField(null=True, blank=True) + is_trial = models.BooleanField(default=False) + + def get_quiz_units(self): + return [unit.quiz for unit in self.learning_unit.filter( + learning_type="quiz")] + + def get_learning_units(self): + return self.learning_unit.order_by("order") + + def get_added_quiz_lesson(self): + learning_units = self.learning_unit.order_by("order") + added_quiz_lessons = [] + if learning_units.exists(): + for unit in learning_units: + if unit.learning_type == "quiz": + added_quiz_lessons.append(("quiz", unit.quiz)) + else: + added_quiz_lessons.append(("lesson", unit.lesson)) + return added_quiz_lessons + + def toggle_check_prerequisite(self): + if self.check_prerequisite: + self.check_prerequisite = False + else: + self.check_prerequisite = True + + def get_next_unit(self, current_unit_id): + ordered_units = self.learning_unit.order_by("order") + ordered_units_ids = list(ordered_units.values_list("id", flat=True)) + current_unit_index = ordered_units_ids.index(current_unit_id) + if current_unit_index + 1 == len(ordered_units_ids): + next_index = 0 + else: + next_index = current_unit_index + 1 + return ordered_units.get(id=ordered_units_ids[next_index]) + + def __str__(self): + return self.name + + ############################################################################### class Course(models.Model): """ Course for students""" @@ -150,6 +481,8 @@ class Course(models.Model): teachers = models.ManyToManyField(User, related_name='teachers') is_trial = models.BooleanField(default=False) instructions = models.TextField(default=None, null=True, blank=True) + learning_module = models.ManyToManyField(LearningModule, + related_name='learning_module') # The start date of the course enrollment. start_enroll_time = models.DateTimeField( @@ -179,30 +512,12 @@ class Course(models.Model): return new_course def create_duplicate_course(self, user): - quizzes = self.quiz_set.all() - prerequisite_map = [] - duplicate_quiz_map = {} + 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) - 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() + new_course.learning_module.add(*learning_modules) return new_course @@ -247,9 +562,6 @@ class Course(models.Model): def is_self_enroll(self): return True if self.enrollment == enrollment_methods[1][0] else False - def get_quizzes(self): - return self.quiz_set.filter(is_trial=False) - def activate(self): self.active = True @@ -266,18 +578,25 @@ class Course(models.Model): self.teachers.remove(*teachers) def create_demo(self, user): - course = Course.objects.filter(creator=user, name="Yaksh Demo course") + course = Course.objects.filter(creator=user, + name="Yaksh Demo course").exists() if not course: course = Course.objects.create(name="Yaksh Demo course", enrollment="open", creator=user) quiz = Quiz() - demo_quiz = quiz.create_demo_quiz(course) + demo_quiz = quiz.create_demo_quiz(user) demo_ques = Question() demo_ques.create_demo_questions(user) demo_que_ppr = QuestionPaper() demo_que_ppr.create_demo_quiz_ppr(demo_quiz, user) success = True + ordered_unit = LearningUnit.objects.create( + order=1, learning_type="quiz", quiz=demo_quiz) + learning_module = LearningModule.objects.create( + name="demo module", description="demo module", creator=user) + learning_module.learning_unit.add(ordered_unit) + course.learning_module.add(learning_module) else: success = False return success @@ -288,10 +607,50 @@ class Course(models.Model): students = self.students.exclude(id__in=teachers) return students + def get_learning_modules(self): + return self.learning_module.order_by("order") + + def get_unit_completion_status(self, module, user, unit): + course_module = self.learning_module.get(id=module.id) + learning_unit = course_module.learning_unit.get(id=unit.id) + return learning_unit.get_completion_status(user, self) + + def get_quizzes(self): + learning_modules = self.learning_module.all() + quiz_list = [] + for module in learning_modules: + quiz_list.extend(module.get_quiz_units()) + return quiz_list + + def get_quiz_details(self): + return [(self, quiz, quiz.get_total_students(self), + quiz.get_passed_students(self), + quiz.get_failed_students(self)) + for quiz in self.get_quizzes()] + + def get_learning_units(self): + learning_modules = self.learning_module.all() + learning_unit_list = [] + for module in learning_modules: + learning_unit_list.extend(module.get_learning_units()) + return learning_unit_list + def __str__(self): return self.name +############################################################################### +class CourseStatus(models.Model): + completed_units = models.ManyToManyField(LearningUnit, + related_name="completed_units") + current_unit = models.ForeignKey(LearningUnit, related_name="last_lesson", + null=True, blank=True) + course = models.ForeignKey(Course) + user = models.ForeignKey(User) + grade = models.CharField(max_length=255, null=True, blank=True) + total_marks = models.FloatField(default=0.0) + + ############################################################################### class ConcurrentUser(models.Model): concurrent_user = models.OneToOneField(User) @@ -620,165 +979,6 @@ class Answer(models.Model): return self.answer -############################################################################### -class QuizManager(models.Manager): - def get_active_quizzes(self): - return self.filter(active=True, is_trial=False) - - def create_trial_quiz(self, trial_course, user): - """Creates a trial quiz for testing questions""" - trial_quiz = self.create(course=trial_course, - duration=1000, - description="trial_questions", - is_trial=True, - time_between_attempts=0 - ) - return trial_quiz - - def create_trial_from_quiz(self, original_quiz_id, user, godmode): - """Creates a trial quiz from existing quiz""" - trial_quiz_name = "Trial_orig_id_{0}_{1}".format( - original_quiz_id, - "godmode" if godmode else "usermode" - ) - - if self.filter(description=trial_quiz_name).exists(): - trial_quiz = self.get(description=trial_quiz_name) - - else: - trial_quiz = self.get(id=original_quiz_id) - trial_quiz.course.enroll(False, user) - trial_quiz.pk = None - trial_quiz.description = trial_quiz_name - trial_quiz.is_trial = True - trial_quiz.prerequisite = None - if godmode: - trial_quiz.time_between_attempts = 0 - trial_quiz.duration = 1000 - trial_quiz.attempts_allowed = -1 - trial_quiz.active = True - trial_quiz.start_date_time = timezone.now() - trial_quiz.end_date_time = datetime( - 2199, 1, 1, 0, 0, 0, 0, tzinfo=pytz.utc - ) - trial_quiz.save() - return trial_quiz - - -############################################################################### -class Quiz(models.Model): - """A quiz that students will participate in. One can think of this - as the "examination" event. - """ - - course = models.ForeignKey(Course) - - # The start date of the quiz. - start_date_time = models.DateTimeField( - "Start Date and Time of the quiz", - default=timezone.now, - null=True - ) - - # The end date and time of the quiz - end_date_time = models.DateTimeField( - "End Date and Time of the quiz", - default=datetime( - 2199, 1, 1, - tzinfo=pytz.timezone(timezone.get_current_timezone_name()) - ), - null=True - ) - - # This is always in minutes. - duration = models.IntegerField("Duration of quiz in minutes", default=20) - - # Is the quiz active. The admin should deactivate the quiz once it is - # complete. - active = models.BooleanField(default=True) - - # Description of quiz. - description = models.CharField(max_length=256) - - # Mininum passing percentage condition. - pass_criteria = models.FloatField("Passing percentage", default=40) - - # List of prerequisite quizzes to be passed to take this quiz - prerequisite = models.ForeignKey("Quiz", null=True, blank=True) - - # Programming language for a quiz - language = models.CharField(max_length=20, choices=languages) - - # Number of attempts for the quiz - attempts_allowed = models.IntegerField(default=1, choices=attempts) - - time_between_attempts = models.IntegerField( - "Number of Days", choices=days_between_attempts - ) - - is_trial = models.BooleanField(default=False) - - instructions = models.TextField('Instructions for Students', - default=None, blank=True, null=True) - - view_answerpaper = models.BooleanField('Allow student to view their answer\ - paper', default=False) - - allow_skip = models.BooleanField("Allow students to skip questions", - default=True) - - objects = QuizManager() - - class Meta: - verbose_name_plural = "Quizzes" - - def is_expired(self): - return not self.start_date_time <= timezone.now() < self.end_date_time - - 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(), - end_date_time=timezone.now() + timedelta(176590), - duration=30, active=True, - attempts_allowed=-1, - time_between_attempts=0, - description='Yaksh Demo quiz', pass_criteria=0, - language='Python', prerequisite=None, - course=course - ) - return demo_quiz - - def __str__(self): - desc = self.description or 'Quiz' - return '%s: on %s for %d minutes' % (desc, self.start_date_time, - self.duration) - - ############################################################################### class QuestionPaperManager(models.Manager): @@ -884,18 +1084,20 @@ class QuestionPaper(models.Model): all_questions = questions return all_questions - def make_answerpaper(self, user, ip, attempt_num): + def make_answerpaper(self, user, ip, attempt_num, course_id): """Creates an answer paper for the user to attempt the quiz""" try: ans_paper = AnswerPaper.objects.get(user=user, attempt_number=attempt_num, - question_paper=self + question_paper=self, + course_id=course_id ) except AnswerPaper.DoesNotExist: ans_paper = AnswerPaper( user=user, user_ip=ip, - attempt_number=attempt_num + attempt_number=attempt_num, + course_id=course_id ) ans_paper.start_time = timezone.now() ans_paper.end_time = ans_paper.start_time + \ @@ -911,25 +1113,22 @@ class QuestionPaper(models.Model): except AnswerPaper.MultipleObjectsReturned: ans_paper = AnswerPaper.objects.get(user=user, attempt_number=attempt_num, - question_paper=self + question_paper=self, + course_id=course_id ).order_by('-id') ans_paper = ans_paper[0] return ans_paper - def _is_questionpaper_passed(self, user): - return AnswerPaper.objects.filter(question_paper=self, user=user, - passed=True).exists() - def _is_attempt_allowed(self, user): attempts = AnswerPaper.objects.get_total_attempt(questionpaper=self, user=user) return attempts != self.quiz.attempts_allowed - def can_attempt_now(self, user): + def can_attempt_now(self, user, course_id): if self._is_attempt_allowed(user): last_attempt = AnswerPaper.objects.get_user_last_attempt( - user=user, questionpaper=self + user=user, questionpaper=self, course_id=course_id ) if last_attempt: time_lag = (timezone.now() - last_attempt.start_time).days @@ -939,14 +1138,6 @@ class QuestionPaper(models.Model): else: return False - def _get_prequisite_paper(self): - return self.quiz.prerequisite.questionpaper_set.get() - - def is_prerequisite_passed(self, user): - if self.quiz.has_prerequisite(): - prerequisite = self._get_prequisite_paper() - return prerequisite._is_questionpaper_passed(user) - def create_demo_quiz_ppr(self, demo_quiz, user): question_paper = QuestionPaper.objects.create(quiz=demo_quiz, shuffle_questions=False @@ -1038,27 +1229,32 @@ class AnswerPaperManager(models.Manager): questions_answered.append(question.id) return Counter(questions_answered) - def get_attempt_numbers(self, questionpaper_id, status='completed'): + def get_attempt_numbers(self, questionpaper_id, course_id, + status='completed'): ''' Return list of attempt numbers''' attempt_numbers = self.filter( - question_paper_id=questionpaper_id, status=status + question_paper_id=questionpaper_id, status=status, + course_id=course_id ).values_list('attempt_number', flat=True).distinct() return attempt_numbers - def has_attempt(self, questionpaper_id, attempt_number, + def has_attempt(self, questionpaper_id, attempt_number, course_id, status='completed'): ''' Whether question paper is attempted''' return self.filter( question_paper_id=questionpaper_id, - attempt_number=attempt_number, status=status + attempt_number=attempt_number, status=status, + course_id=course_id ).exists() - def get_count(self, questionpaper_id, attempt_number, status='completed'): + def get_count(self, questionpaper_id, attempt_number, course_id, + status='completed'): ''' Return count of answerpapers for a specfic question paper and attempt number''' return self.filter( question_paper_id=questionpaper_id, - attempt_number=attempt_number, status=status + attempt_number=attempt_number, status=status, + course_id=course_id ).count() def get_question_statistics(self, questionpaper_id, attempt_number, @@ -1083,18 +1279,21 @@ class AnswerPaperManager(models.Manager): question_stats[question] = [0, questions[question.id]] return question_stats - def _get_answerpapers_for_quiz(self, questionpaper_id, status=False): + def _get_answerpapers_for_quiz(self, questionpaper_id, course_id, + status=False): if not status: - return self.filter(question_paper_id=questionpaper_id) + return self.filter(question_paper_id=questionpaper_id, + course_id=course_id) else: return self.filter(question_paper_id=questionpaper_id, + course_id=course_id, status="completed") def _get_answerpapers_users(self, answerpapers): return answerpapers.values_list('user', flat=True).distinct() - def get_latest_attempts(self, questionpaper_id): - papers = self._get_answerpapers_for_quiz(questionpaper_id) + def get_latest_attempts(self, questionpaper_id, course_id): + papers = self._get_answerpapers_for_quiz(questionpaper_id, course_id) users = self._get_answerpapers_users(papers) latest_attempts = [] for user in users: @@ -1106,9 +1305,10 @@ class AnswerPaperManager(models.Manager): user_id=user_id ).order_by('-attempt_number')[0] - def get_user_last_attempt(self, questionpaper, user): + def get_user_last_attempt(self, questionpaper, user, course_id): attempts = self.filter(question_paper=questionpaper, - user=user).order_by('-attempt_number') + user=user, + course_id=course_id).order_by('-attempt_number') if attempts: return attempts[0] @@ -1118,23 +1318,28 @@ class AnswerPaperManager(models.Manager): def get_total_attempt(self, questionpaper, user): return self.filter(question_paper=questionpaper, user=user).count() - def get_users_for_questionpaper(self, questionpaper_id): - return self._get_answerpapers_for_quiz(questionpaper_id, status=True)\ + def get_users_for_questionpaper(self, questionpaper_id, course_id): + return self._get_answerpapers_for_quiz(questionpaper_id, course_id, + status=True)\ .values("user__id", "user__first_name", "user__last_name")\ .order_by("user__first_name")\ .distinct() - def get_user_all_attempts(self, questionpaper, user): - return self.filter(question_paper=questionpaper, user=user)\ + def get_user_all_attempts(self, questionpaper, user, course_id): + return self.filter(question_paper=questionpaper, user=user, + course_id=course_id)\ .order_by('-attempt_number') - def get_user_data(self, user, questionpaper_id, attempt_number=None): + def get_user_data(self, user, questionpaper_id, course_id, + attempt_number=None): if attempt_number is not None: papers = self.filter(user=user, question_paper_id=questionpaper_id, + course_id=course_id, attempt_number=attempt_number) else: papers = self.filter( - user=user, question_paper_id=questionpaper_id + user=user, question_paper_id=questionpaper_id, + course_id=course_id ).order_by("-attempt_number") data = {} profile = user.profile if hasattr(user, 'profile') else None @@ -1144,9 +1349,9 @@ class AnswerPaperManager(models.Manager): data['questionpaperid'] = questionpaper_id return data - def get_user_best_of_attempts_marks(self, quiz, user_id): + def get_user_best_of_attempts_marks(self, quiz, user_id, course_id): best_attempt = 0.0 - papers = self.filter(question_paper__quiz=quiz, + papers = self.filter(question_paper__quiz=quiz, course_id=course_id, user=user_id).values("marks_obtained") if papers: best_attempt = max([marks["marks_obtained"] for marks in papers]) @@ -1165,6 +1370,9 @@ class AnswerPaper(models.Model): # The Quiz to which this question paper is attached to. question_paper = models.ForeignKey(QuestionPaper) + # Answepaper will be unique to the course + course = models.ForeignKey(Course) + # The attempt number for the question paper. attempt_number = models.IntegerField() @@ -1438,6 +1646,7 @@ class AnswerPaper(models.Model): result['error'] = ['Correct answer'] elif question.type == 'float': + user_answer = float(user_answer) tc_status = [] user_answer = float(user_answer) for tc in question.get_test_cases(): -- cgit From 15850f69a19c9c22782bd49d17f54521701a9140 Mon Sep 17 00:00:00 2001 From: adityacp Date: Fri, 17 Nov 2017 19:26:55 +0530 Subject: Change in forms.py - Add model forms for Lesson, LearningModule - Add forms for LessonFile --- yaksh/forms.py | 237 +++++++++++++++++++++++++++------------------------------ 1 file changed, 114 insertions(+), 123 deletions(-) (limited to 'yaksh') diff --git a/yaksh/forms.py b/yaksh/forms.py index 2740497..25eb2c5 100644 --- a/yaksh/forms.py +++ b/yaksh/forms.py @@ -1,15 +1,11 @@ from django import forms -from yaksh.models import get_model_class, Profile, Quiz, Question, TestCase, Course,\ - QuestionPaper, StandardTestCase, StdIOBasedTestCase, \ - HookTestCase, IntegerTestCase, StringTestCase +from yaksh.models import ( + get_model_class, Profile, Quiz, Question, Course, QuestionPaper, Lesson, + LearningModule +) from django.contrib.auth import authenticate from django.contrib.auth.models import User -from django.contrib.contenttypes.models import ContentType from django.conf import settings -from taggit.managers import TaggableManager -from taggit.forms import TagField -from django.forms.models import inlineformset_factory -from django.db.models import Q from django.utils import timezone from textwrap import dedent try: @@ -17,7 +13,6 @@ try: except ImportError: from string import ascii_letters as letters from string import punctuation, digits -import datetime import pytz from .send_emails import generate_activation_key @@ -29,7 +24,7 @@ languages = ( ("cpp", "C++ Language"), ("java", "Java Language"), ("scilab", "Scilab"), - ) +) question_types = ( ("select", "Select Question Type"), @@ -40,17 +35,17 @@ question_types = ( ("integer", "Answer in Integer"), ("string", "Answer in String"), ("float", "Answer in Float"), - ) +) test_case_types = ( - ("standardtestcase", "Standard Testcase"), - ("stdiobasedtestcase", "StdIO Based Testcase"), - ("mcqtestcase", "MCQ Testcase"), - ("hooktestcase", "Hook Testcase"), - ("integertestcase", "Integer Testcase"), - ("stringtestcase", "String Testcase"), - ("floattestcase", "Float Testcase"), - ) + ("standardtestcase", "Standard Testcase"), + ("stdiobasedtestcase", "StdIO Based Testcase"), + ("mcqtestcase", "MCQ Testcase"), + ("hooktestcase", "Hook Testcase"), + ("integertestcase", "Integer Testcase"), + ("stringtestcase", "String Testcase"), + ("floattestcase", "Float Testcase"), +) UNAME_CHARS = letters + "._" + digits PWD_CHARS = letters + punctuation + digits @@ -59,8 +54,10 @@ attempts = [(i, i) for i in range(1, 6)] attempts.append((-1, 'Infinite')) days_between_attempts = ((j, j) for j in range(401)) -def get_object_form(model, exclude_fields=None): + +def get_object_form(model, exclude_fields=None): model_class = get_model_class(model) + class _ObjectForm(forms.ModelForm): class Meta: model = model_class @@ -77,20 +74,21 @@ class UserRegisterForm(forms.Form): period and underscores only.') email = forms.EmailField() password = forms.CharField(max_length=30, widget=forms.PasswordInput()) - confirm_password = forms.CharField\ - (max_length=30, widget=forms.PasswordInput()) + confirm_password = forms.CharField( + max_length=30, widget=forms.PasswordInput()) first_name = forms.CharField(max_length=30) last_name = forms.CharField(max_length=30) - roll_number = forms.CharField\ - (max_length=30, help_text="Use a dummy if you don't have one.") - institute = forms.CharField\ - (max_length=128, help_text='Institute/Organization') - department = forms.CharField\ - (max_length=64, help_text='Department you work/study at') - position = forms.CharField\ - (max_length=64, help_text='Student/Faculty/Researcher/Industry/etc.') - timezone = forms.ChoiceField(choices=[(tz, tz) for tz in pytz.common_timezones], - initial=pytz.utc) + roll_number = forms.CharField( + max_length=30, help_text="Use a dummy if you don't have one.") + institute = forms.CharField( + max_length=128, help_text='Institute/Organization') + department = forms.CharField( + max_length=64, help_text='Department you work/study at') + position = forms.CharField( + max_length=64, help_text='Student/Faculty/Researcher/Industry/etc.') + timezone = forms.ChoiceField( + choices=[(tz, tz) for tz in pytz.common_timezones], + initial=pytz.utc) def clean_username(self): u_name = self.cleaned_data["username"] @@ -146,9 +144,10 @@ class UserRegisterForm(forms.Form): if settings.IS_DEVELOPMENT: new_profile.is_email_verified = True else: - new_profile.activation_key = generate_activation_key(new_user.username) - new_profile.key_expiry_time = timezone.now() + \ - timezone.timedelta(minutes=20) + new_profile.activation_key = generate_activation_key( + new_user.username) + new_profile.key_expiry_time = timezone.now() + timezone.timedelta( + minutes=20) new_profile.save() return u_name, pwd, new_user.email, new_profile.activation_key @@ -166,8 +165,9 @@ class UserLoginForm(forms.Form): self.cleaned_data["password"] user = authenticate(username=u_name, password=pwd) except Exception: - raise forms.ValidationError\ - ("Username and/or Password is not entered") + raise forms.ValidationError( + "Username and/or Password is not entered" + ) if not user: raise forms.ValidationError("Invalid username/password") return user @@ -178,82 +178,38 @@ class QuizForm(forms.ModelForm): It has the related fields and functions required.""" def __init__(self, *args, **kwargs): - user = kwargs.pop('user') - course_id = kwargs.pop('course') super(QuizForm, self).__init__(*args, **kwargs) - prerequisite_list = Quiz.objects.filter( - course__id=course_id, - is_trial=False - ).exclude(id=self.instance.id) - - self.fields['prerequisite'] = forms.ModelChoiceField(prerequisite_list) - self.fields['prerequisite'].required = False - self.fields['course'] = forms.ModelChoiceField( - queryset=Course.objects.filter(id=course_id), empty_label=None) - self.fields["instructions"].initial = dedent("""\ -

- This examination system has been - developed with the intention of - making you learn programming and - be assessed in an interactive and - fun manner. - You will be presented with a - series of programming questions - and problems that you will answer - online and get immediate - feedback for. -

-

- Here are some important - instructions and rules that you - should understand carefully.

- -

- We hope you enjoy taking this - exam !!! -

- """) - - def clean_prerequisite(self): - prereq = self.cleaned_data['prerequisite'] - if prereq and prereq.prerequisite: - if prereq.prerequisite.id == self.instance.id: - raise forms.ValidationError("Please set another prerequisite quiz") - return prereq + self.fields["instructions"].initial = dedent("""\ +

+ This examination system has been developed with the intention of + making you learn programming and be assessed in an interactive and + fun manner.You will be presented with a series of programming + questions and problems that you will answer online and get + immediate feedback for. +

Here are some important instructions and rules that you + should understand carefully.

+ +

We hope you enjoy taking this exam !!!

+ """) class Meta: model = Quiz - exclude = ["is_trial"] + exclude = ["is_trial", "creator"] class QuestionForm(forms.ModelForm): @@ -266,15 +222,19 @@ class QuestionForm(forms.ModelForm): class FileForm(forms.Form): - file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}), - required=False) + file_field = forms.FileField(widget=forms.ClearableFileInput( + attrs={'multiple': True}), + required=False) class RandomQuestionForm(forms.Form): - question_type = forms.CharField(max_length=8, widget=forms.Select\ - (choices=question_types)) - marks = forms.CharField(max_length=8, widget=forms.Select\ - (choices=(('select', 'Select Marks'),))) + question_type = forms.CharField( + max_length=8, widget=forms.Select(choices=question_types) + ) + marks = forms.CharField( + max_length=8, widget=forms.Select( + choices=(('select', 'Select Marks'),)) + ) shuffle_questions = forms.BooleanField(required=False) @@ -286,13 +246,14 @@ class QuestionFilterForm(forms.Form): points_list = questions.values_list('points', flat=True).distinct() points_options = [(None, 'Select Marks')] points_options.extend([(point, point) for point in points_list]) - self.fields['marks'] = forms.FloatField(widget=forms.Select\ - (choices=points_options)) - - language = forms.CharField(max_length=8, widget=forms.Select\ - (choices=languages)) - question_type = forms.CharField(max_length=8, widget=forms.Select\ - (choices=question_types)) + self.fields['marks'] = forms.FloatField( + widget=forms.Select(choices=points_options) + ) + language = forms.CharField( + max_length=8, widget=forms.Select(choices=languages)) + question_type = forms.CharField( + max_length=8, widget=forms.Select(choices=question_types) + ) class CourseForm(forms.ModelForm): @@ -311,8 +272,7 @@ class CourseForm(forms.ModelForm): class Meta: model = Course - exclude = ['creator', 'requests', 'students', 'rejected', - 'created_on', 'is_trial', 'hidden', 'teachers'] + fields = ['name', 'enrollment', 'active', 'code', 'instructions'] class ProfileForm(forms.ModelForm): @@ -342,3 +302,34 @@ class QuestionPaperForm(forms.ModelForm): class Meta: model = QuestionPaper fields = ['shuffle_questions'] + + +class LessonForm(forms.ModelForm): + def __init__(self, *args, **kwargs): + super(LessonForm, self).__init__(*args, **kwargs) + des_msg = "Enter Lesson Description as Markdown text" + name_msg = "Enter Lesson Name" + self.fields['description'].widget.attrs['placeholder'] = des_msg + self.fields['name'].widget.attrs['placeholder'] = name_msg + + class Meta: + model = Lesson + exclude = ['completed_lessons', 'creator', 'html_data'] + + +class LessonFileForm(forms.Form): + Lesson_files = forms.FileField(widget=forms.ClearableFileInput( + attrs={'multiple': True}), + required=False) + + +class LearningModuleForm(forms.ModelForm): + def __init__(self, *args, **kwargs): + super(LearningModuleForm, self).__init__(*args, **kwargs) + name_msg = "Enter Learning Module Name" + self.fields['name'].widget.attrs['placeholder'] = name_msg + self.fields['name'].widget.attrs['size'] = 30 + + class Meta: + model = LearningModule + fields = ['name', 'description'] -- cgit From b70cc57b29c17a3f4c600a120c5cbc7f5259ac3d Mon Sep 17 00:00:00 2001 From: adityacp Date: Fri, 17 Nov 2017 19:28:51 +0530 Subject: Change in urls.py - Add new urls for creating course with module and units - Fix existing urls --- yaksh/urls.py | 83 +++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 64 insertions(+), 19 deletions(-) (limited to 'yaksh') diff --git a/yaksh/urls.py b/yaksh/urls.py index 7f484b9..8348666 100644 --- a/yaksh/urls.py +++ b/yaksh/urls.py @@ -11,50 +11,66 @@ urlpatterns = [ url(r'^quizzes/$', views.quizlist_user, name='quizlist_user'), url(r'^quizzes/(?P\w+)/$', views.quizlist_user, name='quizlist_user'), url(r'^results/$', views.results_user), - url(r'^start/$', views.start), - url(r'^start/(?P\d+)/$', views.start), - url(r'^start/(?P\d+)/(?P\d+)/$', views.start), - url(r'^quit/(?P\d+)/(?P\d+)/$', views.quit), + url(r'^start/(?P\d+)/(?P\d+)/(?P\d+)/$', + views.start), + url(r'^start/(?P\d+)/(?P\d+)/(?P\d+)/(?P\d+)/$', + views.start), + url(r'^quit/(?P\d+)/(?P\d+)/(?P\d+)/(?P\d+)/$', + views.quit), url(r'^complete/$', views.complete), - url(r'^complete/(?P\d+)/(?P\d+)/$',\ + url(r'^complete/(?P\d+)/(?P\d+)/(?P\d+)/(?P\d+)/$',\ views.complete), url(r'^register/$', views.user_register, name="register"), url(r'^(?P\d+)/check/$', views.check, name="check"), - url(r'^get_result/(?P\d+)/$', views.get_result), - url(r'^(?P\d+)/check/(?P\d+)/(?P\d+)/$',\ + url(r'^get_result/(?P\d+)/(?P\d+)/(?P\d+)/$', + views.get_result), + url(r'^(?P\d+)/check/(?P\d+)/(?P\d+)/(?P\d+)/(?P\d+)/$',\ views.check, name="check"), - url(r'^(?P\d+)/skip/(?P\d+)/(?P\d+)/$', + url(r'^(?P\d+)/skip/(?P\d+)/(?P\d+)/(?P\d+)/(?P\d+)/$', views.skip), - url(r'^(?P\d+)/skip/(?P\d+)/(?P\d+)/(?P\d+)/$', + url(r'^(?P\d+)/skip/(?P\d+)/(?P\d+)/(?P\d+)/(?P\d+)/(?P\d+)/$', views.skip), url(r'^enroll_request/(?P\d+)/$', views.enroll_request, name='enroll_request'), url(r'^self_enroll/(?P\d+)/$', views.self_enroll, name='self_enroll'), url(r'^view_answerpaper/(?P\d+)/$', views.view_answerpaper, name='view_answerpaper'), + url(r'^show_video/(?P\d+)/(?P\d+)/(?P\d+)/$', + views.show_video, name='show_video'), + url(r'^quizzes/view_module/(?P\d+)/(?P\d+)/$', + views.view_module, name='view_module'), + url(r'^next_unit/(?P\d+)/(?P\d+)/(?P\d+)/$', + views.get_next_unit, name='next_unit'), + url(r'^next_unit/(?P\d+)/(?P\d+)/(?P\d+)/(?P\d+)/$', + views.get_next_unit, name='next_unit'), url(r'^manage/$', views.prof_manage, name='manage'), url(r'^manage/addquestion/$', views.add_question, name="add_question"), url(r'^manage/addquestion/(?P\d+)/$', views.add_question, name="add_question"), - url(r'^manage/addquiz/(?P\d+)/$', views.add_quiz, name='add_quiz'), - url(r'^manage/addquiz/(?P\d+)/(?P\d+)/$', views.add_quiz, name='edit_quiz'), + url(r'^manage/addquiz/$', views.add_quiz, name='add_quiz'), + url(r'^manage/addquiz/(?P\d+)/$', + views.add_quiz, name='edit_quiz'), + url(r'^manage/addquiz/(?P\d+)/(?P\d+)$', + views.add_quiz, name='edit_quiz'), url(r'^manage/gradeuser/$', views.grade_user, name="grade_user"), - url(r'^manage/gradeuser/(?P\d+)/$',views.grade_user, name="grade_user"), - url(r'^manage/gradeuser/(?P\d+)/(?P\d+)/$', + url(r'^manage/gradeuser/(?P\d+)/(?P\d+)/$', views.grade_user, name="grade_user"), - url(r'^manage/gradeuser/(?P\d+)/(?P\d+)/(?P\d+)/$', + url(r'^manage/gradeuser/(?P\d+)/(?P\d+)/(?P\d+)/$', + views.grade_user, name="grade_user"), + url(r'^manage/gradeuser/(?P\d+)/(?P\d+)/(?P\d+)/(?P\d+)/$', views.grade_user, name="grade_user"), url(r'^manage/questions/$', views.show_all_questions, name="show_questions"), url(r'^manage/monitor/$', views.monitor, name="monitor"), - url(r'^manage/monitor/(?P\d+)/$', views.monitor, name="monitor"), - url(r'^manage/user_data/(?P\d+)/(?P\d+)/$', + url(r'^manage/monitor/(?P\d+)/(?P\d+)/$', + views.monitor, name="monitor"), + url(r'^manage/user_data/(?P\d+)/(?P\d+)/(?P\d+)/$', views.user_data, name="user_data"), url(r'^manage/user_data/(?P\d+)/$', views.user_data), url(r'^manage/quiz/designquestionpaper/(?P\d+)/$', views.design_questionpaper, name='design_questionpaper'), url(r'^manage/designquestionpaper/(?P\d+)/(?P\d+)/$', views.design_questionpaper, name='designquestionpaper'), - url(r'^manage/statistics/question/(?P\d+)/$', + url(r'^manage/statistics/question/(?P\d+)/(?P\d+)/$', views.show_statistics, name="show_statistics"), - url(r'^manage/statistics/question/(?P\d+)/(?P\d+)/$', + url(r'^manage/statistics/question/(?P\d+)/(?P\d+)/(?P\d+)/$', views.show_statistics, name="show_statistics"), url(r'^manage/download_quiz_csv/(?P\d+)/(?P\d+)/$', views.download_quiz_csv, name="download_quiz_csv"), @@ -101,7 +117,8 @@ urlpatterns = [ views.regrade, name='regrade'), url(r'^manage/regrade/paper/(?P\d+)/(?P\d+)/$', views.regrade, name='regrade'), - url(r'^manage/(?Pgodmode|usermode)/(?P\d+)/$', views.test_quiz), + url(r'^manage/(?Pgodmode|usermode)/(?P\d+)/(?P\d+)/$', + views.test_quiz), url(r'^manage/create_demo_course/$', views.create_demo_course), url(r'^manage/courses/download_course_csv/(?P\d+)/$', views.download_course_csv, name="download_course_csv"), @@ -113,4 +130,32 @@ urlpatterns = [ views.download_yaml_template, name="download_yaml_template"), url(r'^manage/download_sample_csv/', views.download_sample_csv, name="download_sample_csv"), + url(r'^manage/courses/edit_lesson/$', + views.edit_lesson, name="edit_lesson"), + url(r'^manage/courses/edit_lesson/(?P\d+)/$', + views.edit_lesson, name="edit_lesson"), + url(r'^manage/courses/edit_lesson/(?P\d+)/(?P\d+)/$', + views.edit_lesson, name="edit_lesson"), + url(r'^manage/courses/designmodule/(?P\d+)/$', + views.design_module, name="design_module"), + url(r'^manage/courses/designmodule/(?P\d+)/(?P\d+)/$', + views.design_module, name="design_module"), + url(r'^manage/courses/all_quizzes/$', + views.show_all_quizzes, name="show_all_quizzes"), + url(r'^manage/courses/all_lessons/$', + views.show_all_lessons, name="show_all_lessons"), + url(r'^manage/courses/lesson/preview/$', + views.preview_html_text, name="preview_html_text"), + url(r'^manage/courses/all_learning_module/$', + views.show_all_modules, name="show_all_modules"), + url(r'^manage/courses/add_module/$', + views.add_module, name="add_module"), + url(r'^manage/courses/add_module/(?P\d+)/$', + views.add_module, name="edit_module"), + url(r'^manage/courses/add_module/(?P\d+)/(?P\d+)/$', + views.add_module, name="edit_module"), + url(r'^manage/courses/designcourse/(?P\d+)/$', + views.design_course, name="design_course"), + url(r'^manage/courses/designcourse/(?P\d+)/$', + views.design_course, name="design_course"), ] -- cgit From e839a158750b8202226c37ec605e21313443f508 Mon Sep 17 00:00:00 2001 From: adityacp Date: Fri, 17 Nov 2017 19:33:38 +0530 Subject: Change in views.py - View function for creating new lesson - View function for creating new learning modules - View function for adding modules to course - View function for controlling and viewing learning modules --- yaksh/views.py | 736 ++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 593 insertions(+), 143 deletions(-) (limited to 'yaksh') diff --git a/yaksh/views.py b/yaksh/views.py index bc03ca2..5a97626 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -25,6 +25,7 @@ import json import six from textwrap import dedent import zipfile +from markdown import Markdown try: from StringIO import StringIO as string_io except ImportError: @@ -37,12 +38,15 @@ from yaksh.models import ( HookTestCase, IntegerTestCase, McqTestCase, Profile, QuestionPaper, QuestionSet, Quiz, Question, StandardTestCase, StdIOBasedTestCase, StringTestCase, TestCase, User, - get_model_class, FIXTURES_DIR_PATH + get_model_class, FIXTURES_DIR_PATH, Lesson, LessonFile, + LearningUnit, LearningModule, + CourseStatus ) from yaksh.forms import ( UserRegisterForm, UserLoginForm, QuizForm, QuestionForm, RandomQuestionForm, QuestionFilterForm, CourseForm, ProfileForm, - UploadFileForm, get_object_form, FileForm, QuestionPaperForm + UploadFileForm, get_object_form, FileForm, QuestionPaperForm, LessonForm, + LessonFileForm, LearningModuleForm ) from .settings import URL_ROOT from .file_utils import extract_files, is_csv @@ -79,11 +83,15 @@ def add_to_group(users): if not is_moderator(user): user.groups.add(group) - CSV_FIELDS = ['name', 'username', 'roll_number', 'institute', 'department', 'questions', 'marks_obtained', 'out_of', 'percentage', 'status'] +def get_html_text(md_text): + """Takes markdown text and converts it to html""" + return Markdown().convert(md_text) + + @email_verified def index(request, next_url=None): """The start page. @@ -276,35 +284,49 @@ def add_question(request, question_id=None): @login_required @email_verified -def add_quiz(request, course_id, quiz_id=None): +def add_quiz(request, quiz_id=None, course_id=None): """To add a new quiz in the database. Create a new quiz and store it.""" user = request.user - course = get_object_or_404(Course, pk=course_id) ci = RequestContext(request) - if not is_moderator(user) or (user != course.creator and user not in course.teachers.all()): + if not is_moderator(user): raise Http404('You are not allowed to view this course !') + if quiz_id and not course_id: + quiz = get_object_or_404(Quiz, pk=quiz_id) + if quiz.creator != user: + raise Http404('This quiz does not belong to you') + if course_id: + course = get_object_or_404(Course, pk=course_id) + if not course.is_creator(user) and not course.is_teacher(user): + raise Http404('This quiz does not belong to you') + context = {} if request.method == "POST": if quiz_id is None: - form = QuizForm(request.POST, user=user, course=course_id) + form = QuizForm(request.POST) if form.is_valid(): + form.instance.creator = user form.save() - return my_redirect("/exam/manage/courses/") - + 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, user=user, course=course_id, - instance=quiz - ) + form = QuizForm(request.POST, instance=quiz) if form.is_valid(): + form.instance.creator = user form.save() - return my_redirect("/exam/manage/courses/") + 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 - form = QuizForm(user=user,course=course_id, instance=quiz) + form = QuizForm(instance=quiz) context["quiz_id"] = quiz_id + context["course_id"] = course_id context["form"] = form return my_render_to_response( 'yaksh/add_quiz.html', context, context_instance=ci @@ -319,46 +341,36 @@ def prof_manage(request, msg=None): rights/permissions and log in.""" user = request.user ci = RequestContext(request) - if user.is_authenticated() and is_moderator(user): - question_papers = QuestionPaper.objects.filter( - Q(quiz__course__creator=user) | - Q(quiz__course__teachers=user), - quiz__is_trial=False - ).distinct() - trial_paper = AnswerPaper.objects.filter( - user=user, question_paper__quiz__is_trial=True - ) - if request.method == "POST": - delete_paper = request.POST.getlist('delete_paper') - for answerpaper_id in delete_paper: - answerpaper = AnswerPaper.objects.get(id=answerpaper_id) - qpaper = answerpaper.question_paper - if qpaper.quiz.course.is_trial: - qpaper.quiz.course.delete() + if not user.is_authenticated() and not is_moderator(user): + return my_redirect('/exam/login/') + courses = Course.objects.filter(creator=user, is_trial=False) + + trial_paper = AnswerPaper.objects.filter( + user=user, question_paper__quiz__is_trial=True, + course__is_trial=True + ) + if request.method == "POST": + delete_paper = request.POST.getlist('delete_paper') + for answerpaper_id in delete_paper: + answerpaper = AnswerPaper.objects.get(id=answerpaper_id) + qpaper = answerpaper.question_paper + answerpaper.course.delete() + if qpaper.quiz.is_trial: + qpaper.quiz.delete() + else: + if qpaper.answerpaper_set.count() == 1: + qpaper.quiz.delete() else: - if qpaper.answerpaper_set.count() == 1: - qpaper.quiz.delete() - else: - answerpaper.delete() - users_per_paper = [] - for paper in question_papers: - answer_papers = AnswerPaper.objects.filter(question_paper=paper) - users_passed = AnswerPaper.objects.filter( - question_paper=paper, passed=True - ).count() - users_failed = AnswerPaper.objects.filter( - question_paper=paper, - passed=False - ).count() - temp = paper, answer_papers, users_passed, users_failed - users_per_paper.append(temp) - context = {'user': user, 'users_per_paper': users_per_paper, - 'trial_paper': trial_paper, 'msg': msg - } - return my_render_to_response( - 'yaksh/moderator_dashboard.html', context, context_instance=ci - ) - return my_redirect('/exam/login/') + answerpaper.delete() + users_per_paper = [] + for course in courses: + users_per_paper.extend(course.get_quiz_details()) + context = {'user': user, 'users_per_paper': users_per_paper, + 'trial_paper': trial_paper, 'msg': msg + } + return my_render_to_response( + 'yaksh/moderator_dashboard.html', context, context_instance=ci + ) def user_login(request): @@ -391,42 +403,53 @@ def user_login(request): @login_required @email_verified -def start(request, questionpaper_id=None, attempt_num=None): +def start(request, questionpaper_id=None, attempt_num=None, course_id=None, + module_id=None): """Check the user cedentials and if any quiz is available, start the exam.""" user = request.user ci = RequestContext(request) # check conditions try: - quest_paper = QuestionPaper.objects.get(id=questionpaper_id) + quest_paper = QuestionPaper.objects.select_related( + "quiz").get(id=questionpaper_id) except QuestionPaper.DoesNotExist: msg = 'Quiz not found, please contact your '\ 'instructor/administrator.' - return complete(request, msg, attempt_num, questionpaper_id=None) + return complete(request, msg, attempt_num, course_id=course_id, + questionpaper_id=None, module_id=module_id) if not quest_paper.has_questions(): msg = 'Quiz does not have Questions, please contact your '\ 'instructor/administrator.' - return complete(request, msg, attempt_num, questionpaper_id=None) - if not quest_paper.quiz.course.is_enrolled(user): + return complete(request, msg, attempt_num, course_id=course_id, + questionpaper_id=None, module_id=module_id) + course = Course.objects.prefetch_related("learning_module").get( + id=course_id) + learning_module = course.learning_module.get(id=module_id) + learning_unit = learning_module.learning_unit.get(quiz=quest_paper.quiz.id) + if not course.is_enrolled(user): raise Http404('You are not allowed to view this page!') # prerequisite check and passing criteria - if quest_paper.quiz.is_expired() or not quest_paper.quiz.course.active: - if is_moderator(user): - return redirect("/exam/manage") - return redirect("/exam/quizzes") - if quest_paper.quiz.has_prerequisite() and not quest_paper.is_prerequisite_passed(user): + if quest_paper.quiz.is_expired() or not course.active: if is_moderator(user): return redirect("/exam/manage") return redirect("/exam/quizzes") + if learning_unit.has_prerequisite(): + if not learning_unit.is_prerequisite_passed( + user, learning_module, course): + if is_moderator(user): + return redirect("/exam/manage") + return redirect("/exam/quizzes") # if any previous attempt last_attempt = AnswerPaper.objects.get_user_last_attempt( - questionpaper=quest_paper, user=user) + quest_paper, user, course_id) if last_attempt and last_attempt.is_attempt_inprogress(): return show_question( - request, last_attempt.current_question(), last_attempt + request, last_attempt.current_question(), last_attempt, + course_id=course_id, module_id=module_id ) # allowed to start - if not quest_paper.can_attempt_now(user): + if not quest_paper.can_attempt_now(user, course_id): if is_moderator(user): return redirect("/exam/manage") return redirect("/exam/quizzes") @@ -438,7 +461,9 @@ def start(request, questionpaper_id=None, attempt_num=None): context = { 'user': user, 'questionpaper': quest_paper, - 'attempt_num': attempt_number + 'attempt_num': attempt_number, + 'course': course_id, + 'module_id': module_id } if is_moderator(user): context["user"] = "moderator" @@ -449,10 +474,12 @@ def start(request, questionpaper_id=None, attempt_num=None): if not hasattr(user, 'profile'): msg = 'You do not have a profile and cannot take the quiz!' raise Http404(msg) - new_paper = quest_paper.make_answerpaper(user, ip, attempt_number) + new_paper = quest_paper.make_answerpaper(user, ip, attempt_number, + course_id) if new_paper.status == 'inprogress': return show_question(request, new_paper.current_question(), - new_paper + new_paper, course_id=course_id, + module_id=module_id ) else: msg = 'You have already finished the quiz!' @@ -460,23 +487,27 @@ def start(request, questionpaper_id=None, attempt_num=None): @login_required @email_verified -def show_question(request, question, paper, error_message=None, notification=None): +def show_question(request, question, paper, error_message=None, notification=None, + course_id=None, module_id=None): """Show a question if possible.""" user = request.user if not question: msg = 'Congratulations! You have successfully completed the quiz.' return complete( - request, msg, paper.attempt_number, paper.question_paper.id + request, msg, paper.attempt_number, paper.question_paper.id, + course_id=course_id, module_id=module_id ) if not paper.question_paper.quiz.active: reason = 'The quiz has been deactivated!' return complete( - request, reason, paper.attempt_number, paper.question_paper.id + request, reason, paper.attempt_number, paper.question_paper.id, + module_id=module_id ) if paper.time_left() <= 0: reason = 'Your time is up!' return complete( - request, reason, paper.attempt_number, paper.question_paper.id + request, reason, paper.attempt_number, paper.question_paper.id, + course_id, module_id=module_id ) if question in paper.questions_answered.all(): notification = ( @@ -493,7 +524,9 @@ def show_question(request, question, paper, error_message=None, notification=Non 'test_cases': test_cases, 'files': files, 'notification': notification, - 'last_attempt': question.snippet.encode('unicode-escape') + 'last_attempt': question.snippet.encode('unicode-escape'), + 'course_id': course_id, + 'module_id': module_id } answers = paper.get_previous_answers(question) if answers: @@ -507,11 +540,12 @@ def show_question(request, question, paper, error_message=None, notification=Non @login_required @email_verified -def skip(request, q_id, next_q=None, attempt_num=None, questionpaper_id=None): +def skip(request, q_id, next_q=None, attempt_num=None, questionpaper_id=None, + course_id=None, module_id=None): user = request.user paper = get_object_or_404( AnswerPaper, user=request.user, attempt_number=attempt_num, - question_paper=questionpaper_id + question_paper=questionpaper_id, course_id=course_id ) question = get_object_or_404(Question, pk=q_id) @@ -529,19 +563,22 @@ def skip(request, q_id, next_q=None, attempt_num=None, questionpaper_id=None): next_q = get_object_or_404(Question, pk=next_q) else: next_q = paper.next_question(q_id) - return show_question(request, next_q, paper) + return show_question(request, next_q, paper, course_id=course_id, + module_id=module_id) @login_required @email_verified -def check(request, q_id, attempt_num=None, questionpaper_id=None): +def check(request, q_id, attempt_num=None, questionpaper_id=None, + course_id=None, module_id=None): """Checks the answers of the user for particular question""" user = request.user paper = get_object_or_404( AnswerPaper, user=request.user, attempt_number=attempt_num, - question_paper=questionpaper_id + question_paper=questionpaper_id, + course_id=course_id ) current_question = get_object_or_404(Question, pk=q_id) @@ -555,7 +592,8 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None): except ValueError: msg = "Please enter an Integer Value" return show_question( - request, current_question, paper, notification=msg + request, current_question, paper, notification=msg, + course_id=course_id, module_id=module_id ) elif current_question.type == 'float': try: @@ -563,7 +601,8 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None): except ValueError: msg = "Please enter a Float Value" return show_question(request, current_question, - paper, notification=msg) + paper, notification=msg, + course_id=course_id, module_id=module_id) elif current_question.type == 'string': user_answer = str(request.POST.get('answer')) @@ -576,7 +615,8 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None): if not assignment_filename: msg = "Please upload assignment file" return show_question( - request, current_question, paper, notification=msg + request, current_question, paper, notification=msg, + course_id=course_id, module_id=module_id ) for fname in assignment_filename: assignment_files = AssignmentUpload.objects.filter( @@ -603,13 +643,15 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None): new_answer.save() paper.answers.add(new_answer) next_q = paper.add_completed_question(current_question.id) - return show_question(request, next_q, paper) + return show_question(request, next_q, paper, + course_id=course_id, module_id=module_id) else: user_answer = request.POST.get('answer') if not user_answer: msg = "Please submit a valid answer." return show_question( - request, current_question, paper, notification=msg + request, current_question, paper, notification=msg, + course_id=course_id, module_id=module_id ) if current_question in paper.get_questions_answered()\ and current_question.type not in ['code', 'upload']: @@ -640,18 +682,22 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None): result = json.loads(result_details.get('result')) next_question, error_message, paper = _update_paper(request, uid, result) - return show_question(request, next_question, paper, error_message) + return show_question(request, next_question, paper, + error_message, course_id=course_id, + module_id=module_id) else: return JsonResponse(result) else: next_question, error_message, paper = _update_paper(request, uid, result) - return show_question(request, next_question, paper, error_message) + return show_question(request, next_question, paper, error_message, + course_id=course_id, module_id=module_id) else: - return show_question(request, current_question, paper) + return show_question(request, current_question, paper, + course_id=course_id, module_id=module_id) @csrf_exempt -def get_result(request, uid): +def get_result(request, uid, course_id, module_id): result = {} url = 'http://localhost:%s' % SERVER_POOL_PORT result_state = get_result_from_code_server(url, uid) @@ -659,7 +705,8 @@ def get_result(request, uid): 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) + return show_question(request, next_question, paper, error_message, + course_id=course_id, module_id=module_id) return JsonResponse(result) @@ -698,19 +745,23 @@ def _update_paper(request, uid, result): @login_required @email_verified -def quit(request, reason=None, attempt_num=None, questionpaper_id=None): +def quit(request, reason=None, attempt_num=None, questionpaper_id=None, + course_id=None, module_id=None): """Show the quit page when the user logs out.""" paper = AnswerPaper.objects.get(user=request.user, attempt_number=attempt_num, - question_paper=questionpaper_id) - context = {'paper': paper, 'message': reason} + question_paper=questionpaper_id, + course_id=course_id) + context = {'paper': paper, 'message': reason, 'course_id': course_id, + 'module_id': module_id} return my_render_to_response('yaksh/quit.html', context, context_instance=RequestContext(request)) @login_required @email_verified -def complete(request, reason=None, attempt_num=None, questionpaper_id=None): +def complete(request, reason=None, attempt_num=None, questionpaper_id=None, + course_id=None, module_id=None): """Show a page to inform user that the quiz has been compeleted.""" user = request.user if questionpaper_id is None: @@ -722,12 +773,21 @@ def complete(request, reason=None, attempt_num=None, questionpaper_id=None): q_paper = QuestionPaper.objects.get(id=questionpaper_id) paper = AnswerPaper.objects.get( user=user, question_paper=q_paper, - attempt_number=attempt_num + attempt_number=attempt_num, + course_id=course_id ) + course = Course.objects.prefetch_related("learning_module").get( + id=course_id) + learning_module = course.learning_module.prefetch_related( + "learning_unit").get(id=module_id) + learning_unit = learning_module.learning_unit.get(quiz=q_paper.quiz) + paper.update_marks() paper.set_end_time(timezone.now()) message = reason or "Quiz has been submitted" - context = {'message': message, 'paper': paper} + context = {'message': message, 'paper': paper, + 'module_id': learning_module.id, + 'course_id': course_id, 'learning_unit': learning_unit} return my_render_to_response('yaksh/complete.html', context) @@ -749,7 +809,7 @@ def add_course(request, course_id=None): new_course = form.save(commit=False) new_course.creator = user new_course.save() - return my_redirect('/exam/manage/') + return my_redirect('/exam/manage/courses') else: return my_render_to_response( 'yaksh/add_course.html', {'form': form}, context_instance=ci @@ -807,7 +867,8 @@ def courses(request): creator=user, is_trial=False).order_by('-active', '-id') allotted_courses = Course.objects.filter( teachers=user, is_trial=False).order_by('-active', '-id') - context = {'courses': courses, "allotted_courses": allotted_courses} + context = {'courses': courses, "allotted_courses": allotted_courses, + "type": "courses"} return my_render_to_response('yaksh/courses.html', context, context_instance=ci) @@ -939,39 +1000,45 @@ def toggle_course_status(request, course_id): else: course.activate() course.save() - return course_detail(request, course_id) + return my_redirect("/exam/manage/courses") @login_required @email_verified -def show_statistics(request, questionpaper_id, attempt_number=None): +def show_statistics(request, questionpaper_id, attempt_number=None, + course_id=None): user = request.user if not is_moderator(user): raise Http404('You are not allowed to view this page') - attempt_numbers = AnswerPaper.objects.get_attempt_numbers(questionpaper_id) + attempt_numbers = AnswerPaper.objects.get_attempt_numbers( + questionpaper_id, course_id) quiz = get_object_or_404(QuestionPaper, pk=questionpaper_id).quiz if attempt_number is None: context = {'quiz': quiz, 'attempts': attempt_numbers, - 'questionpaper_id': questionpaper_id} + 'questionpaper_id': questionpaper_id, + 'course_id': course_id} return my_render_to_response('yaksh/statistics_question.html', context, context_instance=RequestContext(request)) total_attempt = AnswerPaper.objects.get_count(questionpaper_id, - attempt_number) - if not AnswerPaper.objects.has_attempt(questionpaper_id, attempt_number): + attempt_number, + course_id) + if not AnswerPaper.objects.has_attempt(questionpaper_id, attempt_number, + course_id): return my_redirect('/exam/manage/') question_stats = AnswerPaper.objects.get_question_statistics( questionpaper_id, attempt_number ) context = {'question_stats': question_stats, 'quiz': quiz, 'questionpaper_id': questionpaper_id, - 'attempts': attempt_numbers, 'total': total_attempt} + 'attempts': attempt_numbers, 'total': total_attempt, + 'course_id': course_id} return my_render_to_response('yaksh/statistics_question.html', context, context_instance=RequestContext(request)) @login_required @email_verified -def monitor(request, quiz_id=None): +def monitor(request, quiz_id=None, course_id=None): """Monitor the progress of the papers taken so far.""" user = request.user @@ -994,13 +1061,12 @@ def monitor(request, quiz_id=None): # quiz_id is not None. try: quiz = get_object_or_404(Quiz, id=quiz_id) - if not quiz.course.is_creator(user) and not quiz.course.is_teacher(user): + course = get_object_or_404(Course, id=course_id) + if not course.is_creator(user) and not course.is_teacher(user): raise Http404('This course does not belong to you') - q_paper = QuestionPaper.objects.filter(Q(quiz__course__creator=user) | - Q(quiz__course__teachers=user), - quiz__is_trial=False, + q_paper = QuestionPaper.objects.filter(quiz__is_trial=False, quiz_id=quiz_id).distinct() - except QuestionPaper.DoesNotExist: + except (QuestionPaper.DoesNotExist, Course.DoesNotExist): papers = [] q_paper = None latest_attempts = [] @@ -1011,7 +1077,8 @@ def monitor(request, quiz_id=None): else: attempt_numbers = [] latest_attempts = [] - papers = AnswerPaper.objects.filter(question_paper=q_paper).order_by( + papers = AnswerPaper.objects.filter(question_paper=q_paper, + course_id=course_id).order_by( 'user__profile__roll_number' ) users = papers.values_list('user').distinct() @@ -1032,7 +1099,8 @@ def monitor(request, quiz_id=None): "msg": "Quiz Results", "latest_attempts": latest_attempts, "csv_fields": csv_fields, - "attempt_numbers": attempt_numbers + "attempt_numbers": attempt_numbers, + "course": course } return my_render_to_response('yaksh/monitor.html', context, context_instance=ci) @@ -1097,7 +1165,7 @@ def design_questionpaper(request, quiz_id, questionpaper_id=None): if not is_moderator(user): raise Http404('You are not allowed to view this page!') quiz = Quiz.objects.get(id=quiz_id) - if not quiz.course.is_creator(user) and not quiz.course.is_teacher(user): + if not quiz.creator == user: raise Http404('This course does not belong to you') filter_form = QuestionFilterForm(user=user) questions = None @@ -1159,7 +1227,7 @@ def design_questionpaper(request, quiz_id, questionpaper_id=None): if 'save' in request.POST or 'back' in request.POST: qpaper_form.save() - return my_redirect('/exam/manage/courses/') + return my_redirect('/exam/manage/courses/all_quizzes/') if marks: questions = _get_questions(user, question_type, marks) @@ -1250,10 +1318,11 @@ def show_all_questions(request): if request.POST.get('test') == 'test': question_ids = request.POST.getlist("question") if question_ids: - trial_paper = test_mode(user, False, question_ids, None) + trial_paper, trial_course = test_mode(user, False, question_ids, None) trial_paper.update_total_marks() trial_paper.save() - return my_redirect("/exam/start/1/{0}".format(trial_paper.id)) + return my_redirect("/exam/start/1/{0}/{1}/".format( + trial_paper.id, trial_course.id)) else: context["msg"] = "Please select atleast one question to test" @@ -1272,15 +1341,15 @@ def show_all_questions(request): @login_required @email_verified -def user_data(request, user_id, questionpaper_id=None): +def user_data(request, user_id, questionpaper_id=None, course_id=None): """Render user data.""" current_user = request.user if not current_user.is_authenticated() or not is_moderator(current_user): raise Http404('You are not allowed to view this page!') user = User.objects.get(id=user_id) - data = AnswerPaper.objects.get_user_data(user, questionpaper_id) + data = AnswerPaper.objects.get_user_data(user, questionpaper_id, course_id) - context = {'data': data} + context = {'data': data, 'course_id': course_id} return my_render_to_response('yaksh/user_data.html', context, context_instance=RequestContext(request)) @@ -1323,7 +1392,6 @@ def download_quiz_csv(request, course_id, quiz_id): attempt_number=attempt_number) if not answerpapers: return monitor(request, quiz_id) - response = HttpResponse(content_type='text/csv') response['Content-Disposition'] = 'attachment; filename="{0}-{1}-attempt{2}.csv"'.format( course.name.replace('.', ''), quiz.description.replace('.', ''), @@ -1365,7 +1433,8 @@ def download_quiz_csv(request, course_id, quiz_id): @login_required @email_verified -def grade_user(request, quiz_id=None, user_id=None, attempt_number=None): +def grade_user(request, quiz_id=None, user_id=None, attempt_number=None, + course_id=None): """Present an interface with which we can easily grade a user's papers and update all their marks and also give comments for each paper. """ @@ -1382,11 +1451,12 @@ def grade_user(request, quiz_id=None, user_id=None, attempt_number=None): quiz_id=quiz_id ).values("id") user_details = AnswerPaper.objects.get_users_for_questionpaper( - questionpaper_id + questionpaper_id, course_id ) quiz = get_object_or_404(Quiz, id=quiz_id) - if not quiz.course.is_creator(current_user) and not \ - quiz.course.is_teacher(current_user): + course = get_object_or_404(Course, id=course_id) + if not course.is_creator(current_user) and not \ + course.is_teacher(current_user): raise Http404('This course does not belong to you') has_quiz_assignments = AssignmentUpload.objects.filter( @@ -1396,11 +1466,12 @@ def grade_user(request, quiz_id=None, user_id=None, attempt_number=None): "users": user_details, "quiz_id": quiz_id, "quiz": quiz, - "has_quiz_assignments": has_quiz_assignments + "has_quiz_assignments": has_quiz_assignments, + "course_id": course_id } if user_id is not None: attempts = AnswerPaper.objects.get_user_all_attempts( - questionpaper_id, user_id + questionpaper_id, user_id, course_id ) try: if attempt_number is None: @@ -1413,7 +1484,7 @@ def grade_user(request, quiz_id=None, user_id=None, attempt_number=None): ).exists() user = User.objects.get(id=user_id) data = AnswerPaper.objects.get_user_data( - user, questionpaper_id, attempt_number + user, questionpaper_id, course_id, attempt_number ) context = { "data": data, @@ -1422,7 +1493,8 @@ def grade_user(request, quiz_id=None, user_id=None, attempt_number=None): "attempts": attempts, "user_id": user_id, "has_user_assignments": has_user_assignments, - "has_quiz_assignments": has_quiz_assignments + "has_quiz_assignments": has_quiz_assignments, + "course_id": course_id } if request.method == "POST": papers = data['papers'] @@ -1584,7 +1656,8 @@ def remove_teachers(request, course_id): return my_redirect('/exam/manage/courses') -def test_mode(user, godmode=False, questions_list=None, quiz_id=None): +def test_mode(user, godmode=False, questions_list=None, quiz_id=None, + course_id=None): """creates a trial question paper for the moderators""" if questions_list is not None: @@ -1593,19 +1666,26 @@ def test_mode(user, godmode=False, questions_list=None, quiz_id=None): trial_questionpaper = QuestionPaper.objects.create_trial_paper_to_test_questions( trial_quiz, questions_list ) + trial_unit = LearningUnit.objects.create( + order=1, learning_type="quiz", quiz=trial_quiz) + module = LearningModule.objects.create( + order=1, creator=user, check_prerequisite=False, + name="Trial for {0}".format(trial_course.name)) + module.learning_unit.add(trial_unit) + trial_course.learning_module.add(module.id) else: - trial_quiz = Quiz.objects.create_trial_from_quiz( - quiz_id, user, godmode + trial_quiz, trial_course, module = Quiz.objects.create_trial_from_quiz( + quiz_id, user, godmode, course_id ) trial_questionpaper = QuestionPaper.objects.create_trial_paper_to_test_quiz( trial_quiz, quiz_id ) - return trial_questionpaper + return trial_questionpaper, trial_course, module @login_required @email_verified -def test_quiz(request, mode, quiz_id): +def test_quiz(request, mode, quiz_id, course_id=None): """creates a trial quiz for the moderators""" godmode = True if mode == "godmode" else False current_user = request.user @@ -1613,17 +1693,20 @@ def test_quiz(request, mode, quiz_id): if (quiz.is_expired() or not quiz.active) and not godmode: return my_redirect('/exam/manage') - trial_questionpaper = test_mode(current_user, godmode, None, quiz_id) - return my_redirect("/exam/start/{0}".format(trial_questionpaper.id)) + trial_questionpaper, trial_course = test_mode( + current_user, godmode, None, quiz_id, course_id) + return my_redirect("/exam/start/{0}/{1}".format( + trial_questionpaper.id, trial_course.id)) @login_required @email_verified -def view_answerpaper(request, questionpaper_id): +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(): - data = AnswerPaper.objects.get_user_data(user, questionpaper_id) + data = AnswerPaper.objects.get_user_data(user, questionpaper_id, + course_id) has_user_assignment = AssignmentUpload.objects.filter( user=user, question_paper_id=questionpaper_id @@ -1668,7 +1751,8 @@ def grader(request, extra_context=None): @login_required @email_verified -def regrade(request, course_id, question_id=None, answerpaper_id=None, questionpaper_id=None): +def regrade(request, course_id, question_id=None, answerpaper_id=None, + questionpaper_id=None): user = request.user course = get_object_or_404(Course, pk=course_id) if not is_moderator(user) or (user != course.creator and user not in course.teachers.all()): @@ -1680,7 +1764,7 @@ def regrade(request, course_id, question_id=None, answerpaper_id=None, questionp details.append(answerpaper.regrade(question.id)) if questionpaper_id is not None and question_id is not None: answerpapers = AnswerPaper.objects.filter(questions=question_id, - question_paper_id=questionpaper_id) + question_paper_id=questionpaper_id, course_id=course_id) for answerpaper in answerpapers: details.append(answerpaper.regrade(question_id)) if answerpaper_id is not None and question_id is not None: @@ -1695,7 +1779,8 @@ def download_course_csv(request, course_id): user = request.user if not is_moderator(user): raise Http404('You are not allowed to view this page!') - course = get_object_or_404(Course, pk=course_id) + course = Course.objects.prefetch_related("learning_module").get( + id=course_id) if not course.is_creator(user) and not course.is_teacher(user): raise Http404('The question paper does not belong to your course') students = course.get_only_students().annotate( @@ -1705,14 +1790,14 @@ def download_course_csv(request, course_id): "id", "first_name", "last_name", "email", "institute", "roll_number" ) - quizzes = Quiz.objects.filter(course=course, is_trial=False) + quizzes = course.get_quizzes() for student in students: total_course_marks = 0.0 user_course_marks = 0.0 for quiz in quizzes: quiz_best_marks = AnswerPaper.objects.get_user_best_of_attempts_marks\ - (quiz, student["id"]) + (quiz, student["id"], course_id) user_course_marks += quiz_best_marks total_course_marks += quiz.questionpaper_set.values_list( "total_marks", flat=True)[0] @@ -2004,7 +2089,7 @@ def download_sample_csv(request): @email_verified def duplicate_course(request, course_id): user = request.user - course = get_object_or_404(Course, pk=course_id) + course = Course.objects.get(id=course_id) if not is_moderator(user): raise Http404('You are not allowed to view this page!') @@ -2033,3 +2118,368 @@ def download_yaml_template(request): return response + +@login_required +@email_verified +def edit_lesson(request, lesson_id=None, course_id=None): + user = request.user + ci = RequestContext(request) + if not is_moderator(user): + raise Http404('You are not allowed to view this page!') + if lesson_id: + lesson = Lesson.objects.get(id=lesson_id) + if not lesson.creator == user and not course_id: + raise Http404('This Lesson does not belong to you') + else: + lesson = None + if course_id: + course = get_object_or_404(Course, id=course_id) + if not course.is_creator(user) and not course.is_teacher(user): + raise Http404('This Lesson does not belong to you') + redirect_url = "/exam/manage/courses/" + else: + redirect_url = "/exam/manage/courses/all_lessons/" + context = {} + if request.method == "POST": + if "Save" in request.POST: + lesson_form = LessonForm(request.POST, instance=lesson) + lesson_file_form = LessonFileForm(request.POST, request.FILES) + lessonfiles = request.FILES.getlist('Lesson_files') + if lesson_form.is_valid(): + lesson_form.instance.creator = user + lesson = lesson_form.save() + lesson.html_data = get_html_text(lesson.description) + lesson.save() + if lessonfiles: + for les_file in lessonfiles: + LessonFile.objects.get_or_create( + lesson=lesson, file=les_file + ) + return my_redirect(redirect_url) + else: + context['lesson_form'] = lesson_form + context['lesson_file_form'] = lesson_file_form + + if 'Delete' in request.POST: + remove_files_id = request.POST.getlist('delete_files') + if remove_files_id: + files = LessonFile.objects.filter(id__in=remove_files_id) + for file in files: + file.remove() + + lesson_files = LessonFile.objects.filter(lesson=lesson) + lesson_files_form = LessonFileForm() + lesson_form = LessonForm(instance=lesson) + context['lesson_form'] = lesson_form + context['lesson_file_form'] = lesson_files_form + context['lesson_files'] = lesson_files + context['course_id'] = course_id + return my_render_to_response( + 'yaksh/add_lesson.html', context, context_instance=ci + ) + + +@login_required +@email_verified +def show_video(request, lesson_id, module_id, course_id): + user = request.user + course = Course.objects.prefetch_related("learning_module").get( + id=course_id) + if user not in course.students.all(): + raise Http404('This course does not belong to you') + learn_module = course.learning_module.get(id=module_id) + learn_unit = learn_module.learning_unit.select_related('lesson').get( + lesson_id=lesson_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/") + context = {'lesson': learn_unit.lesson, 'user': user, + 'course': course, 'state': "lesson", + 'learning_units': learning_units, "current_unit": learn_unit, + 'learning_module': learn_module} + return my_render_to_response('yaksh/show_video.html', context) + + +@login_required +@email_verified +def design_module(request, module_id, course_id=None): + user = request.user + ci = RequestContext(request) + if not is_moderator(user): + raise Http404('You are not allowed to view this page!') + context = {} + if course_id: + course = Course.objects.get(id=course_id) + if not course.is_creator(user) and not course.is_teacher(user): + raise Http404('This course does not belong to you') + learning_module = LearningModule.objects.get(id=module_id) + if request.method == "POST": + if "Add" in request.POST: + add_values = request.POST.get("choosen_list").split(',') + to_add_list = [] + if add_values: + ordered_units = learning_module.get_learning_units() + if ordered_units.exists(): + start_val = ordered_units.last().order + 1 + else: + start_val = 1 + for order, value in enumerate(add_values, start_val): + learning_id, learning_type = value.split(":") + if learning_type == "quiz": + learning_unit = LearningUnit.objects.create( + order=order, quiz_id=learning_id, + learning_type=learning_type) + else: + learning_unit = LearningUnit.objects.create( + order=order, lesson_id=learning_id, + learning_type=learning_type) + to_add_list.append(learning_unit) + learning_module.learning_unit.add(*to_add_list) + + if "Change" in request.POST: + order_list = request.POST.get("ordered_list").split(",") + for order in order_list: + learning_unit, learning_order = order.split(":") + if learning_order: + learning_unit = learning_module.learning_unit.get( + id=learning_unit) + learning_unit.order = learning_order + learning_unit.save() + + if "Remove" in request.POST: + remove_values = request.POST.getlist("delete_list") + if remove_values: + learning_module.learning_unit.remove(*remove_values) + LearningUnit.objects.filter(id__in=remove_values).delete() + + if "Change_prerequisite" in request.POST: + unit_list = request.POST.getlist("check_prereq") + for unit in unit_list: + learning_unit = learning_module.learning_unit.get(id=unit) + learning_unit.toggle_check_prerequisite() + learning_unit.save() + + added_quiz_lesson = learning_module.get_added_quiz_lesson() + quizzes = [("quiz", quiz) for quiz in Quiz.objects.filter( + creator=user, is_trial=False)] + lessons = [("lesson", lesson) + for lesson in Lesson.objects.filter(creator=user)] + quiz_les_list = set(quizzes + lessons) - set(added_quiz_lesson) + context['quiz_les_list'] = quiz_les_list + context['learning_units'] = learning_module.get_learning_units() + context['status'] = 'design' + context['module_id'] = module_id + context['course_id'] = course_id + return my_render_to_response('yaksh/add_module.html', context, + context_instance=ci) + + +@login_required +@email_verified +def add_module(request, module_id=None, course_id=None): + user = request.user + ci = RequestContext(request) + if not is_moderator(user): + raise Http404('You are not allowed to view this page!') + redirect_url = "/exam/manage/courses/all_learning_module/" + if course_id: + course = Course.objects.get(id=course_id) + if not course.is_creator(user) and not course.is_teacher(user): + raise Http404('This course does not belong to you') + redirect_url = "/exam/manage/courses/" + if module_id: + module = LearningModule.objects.get(id=module_id) + if not module.creator == user and not course_id: + raise Http404('This Learning Module does not belong to you') + else: + module = None + context = {} + if request.method == "POST": + if "Save" in request.POST: + module_form = LearningModuleForm(request.POST, instance=module) + if module_form.is_valid(): + module_form.instance.creator = user + module = module_form.save() + module.html_data = get_html_text(module.description) + module.save() + return my_redirect(redirect_url) + else: + context['module_form'] = module_form + + module_form = LearningModuleForm(instance=module) + context['module_form'] = module_form + context['course_id'] = course_id + context['status'] = "add" + return my_render_to_response("yaksh/add_module.html", + context, context_instance=ci) + + +@login_required +@email_verified +def show_all_quizzes(request): + user = request.user + if not is_moderator(user): + raise Http404('You are not allowed to view this page!') + quizzes = Quiz.objects.filter(creator=user, is_trial=False) + context = {"quizzes": quizzes, "type": "quiz"} + return my_render_to_response('yaksh/courses.html', context) + + +@login_required +@email_verified +def show_all_lessons(request): + user = request.user + if not is_moderator(user): + raise Http404('You are not allowed to view this page!') + lessons = Lesson.objects.filter(creator=user) + context = {"lessons": lessons, "type": "lesson"} + return my_render_to_response('yaksh/courses.html', context) + + +@login_required +@email_verified +def show_all_modules(request): + user = request.user + if not is_moderator(user): + raise Http404('You are not allowed to view this page!') + learning_modules = LearningModule.objects.filter(creator=user) + context = {"learning_modules": learning_modules, "type": "learning_module"} + return my_render_to_response('yaksh/courses.html', context) + + +@login_required +@email_verified +def preview_html_text(request): + user = request.user + if not is_moderator(user): + raise Http404('You are not allowed to view this page!') + response_kwargs = {} + request_data = json.loads(request.body.decode("utf-8")) + html_text = get_html_text(request_data['description']) + return HttpResponse(json.dumps({"data": html_text}), **response_kwargs) + + +@login_required +@email_verified +def get_next_unit(request, course_id, module_id, current_unit_id, + first_unit=None): + user = request.user + course = Course.objects.prefetch_related("learning_module").get( + id=course_id) + if user not in course.students.all(): + raise Http404('You are not enrolled for this course!') + learning_module = course.learning_module.prefetch_related( + "learning_unit").get(id=module_id) + current_learning_unit = learning_module.learning_unit.get( + id=current_unit_id) + + course_status = CourseStatus.objects.filter( + user=user, course_id=course_id, + ) + if first_unit: + next_unit = current_learning_unit + else: + next_unit = learning_module.get_next_unit(current_learning_unit.id) + if not course_status.exists(): + course_status = CourseStatus.objects.create( + user=user, course_id=course_id + ) + else: + course_status = course_status.first() + + # Add learning unit to completed units list + if not first_unit: + course_status.completed_units.add(current_learning_unit.id) + + # make next available unit as current unit + course_status.current_unit = next_unit + course_status.save() + if next_unit.learning_type == "quiz": + 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( + next_unit.lesson.id, module_id, course_id)) + + +@login_required +@email_verified +def design_course(request, course_id): + user = request.user + ci = RequestContext(request) + if not is_moderator(user): + raise Http404('You are not allowed to view this page!') + course = Course.objects.get(id=course_id) + if not course.is_creator(user) and not course.is_teacher(user): + raise Http404('This course does not belong to you') + context = {} + if request.method == "POST": + if "Add" in request.POST: + add_values = request.POST.getlist("module_list") + to_add_list = [] + if add_values: + ordered_modules = course.get_learning_modules() + if ordered_modules.exists(): + start_val = ordered_modules.last().order + 1 + else: + start_val = 1 + for order, value in enumerate(add_values, start_val): + learning_module = LearningModule.objects.get(id=int(value)) + learning_module.order = order + learning_module.save() + to_add_list.append(learning_module) + course.learning_module.add(*to_add_list) + + if "Change" in request.POST: + order_list = request.POST.get("ordered_list").split(",") + for order in order_list: + learning_unit, learning_order = order.split(":") + if learning_order: + learning_module = course.learning_module.get( + id=learning_unit) + learning_module.order = learning_order + learning_module.save() + + if "Remove" in request.POST: + remove_values = request.POST.getlist("delete_list") + if remove_values: + course.learning_module.remove(*remove_values) + + if "Change_prerequisite" in request.POST: + unit_list = request.POST.getlist("check_prereq") + for unit in unit_list: + learning_module = course.learning_module.get(id=unit) + learning_module.toggle_check_prerequisite() + learning_module.save() + + added_learning_modules = course.get_learning_modules() + all_learning_modules = LearningModule.objects.filter( + creator=user, is_trial=False) + + learning_modules = set(all_learning_modules) - set(added_learning_modules) + context['added_learning_modules'] = added_learning_modules + context['learning_modules'] = learning_modules + context['course_id'] = course_id + return my_render_to_response('yaksh/design_course_session.html', context, + context_instance=ci) + + +@login_required +@email_verified +def view_module(request, module_id, course_id): + user = request.user + course = Course.objects.prefetch_related('learning_module').get( + id=course_id) + if user not in course.students.all(): + raise Http404('You are not enrolled for this course!') + context = {} + learning_module = course.learning_module.get(id=module_id) + learning_units = learning_module.get_learning_units() + context['learning_units'] = learning_units + context['learning_module'] = learning_module + context['first_unit'] = learning_units[0] + context['user'] = user + context['course'] = course + context['state'] = "module" + return my_render_to_response('yaksh/show_video.html', context) -- cgit From a962b59a011c3bcd97c695e839f5b4184926653d Mon Sep 17 00:00:00 2001 From: adityacp Date: Fri, 17 Nov 2017 19:42:23 +0530 Subject: Add new custom template tag to get learning unit status --- yaksh/templatetags/custom_filters.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'yaksh') diff --git a/yaksh/templatetags/custom_filters.py b/yaksh/templatetags/custom_filters.py index df6ecce..1195653 100644 --- a/yaksh/templatetags/custom_filters.py +++ b/yaksh/templatetags/custom_filters.py @@ -1,5 +1,6 @@ from django import template from django.template.defaultfilters import stringfilter +import os try: from itertools import zip_longest except ImportError: @@ -27,3 +28,14 @@ def inprogress(answerpaper): @register.filter(name='zip') def zip_longest_out(a, b): return zip_longest(a, b) + + +@register.filter(name="file_title") +def file_title(name): + return os.path.basename(name) + + +@register.simple_tag +def get_unit_status(course, module, unit, user): + return course.get_unit_completion_status(module, user, unit) + -- cgit From d4a2b0af95ee4347a71346fa3f20409d938d5a46 Mon Sep 17 00:00:00 2001 From: adityacp Date: Fri, 17 Nov 2017 19:42:43 +0530 Subject: Change in templates - Add new templates for creating lessons, modules, design course - Change existing templates for student and moderator interface --- yaksh/templates/base.html | 2 +- yaksh/templates/exam.html | 8 +- yaksh/templates/user.html | 4 +- yaksh/templates/yaksh/add_course.html | 4 +- yaksh/templates/yaksh/add_lesson.html | 61 +++ yaksh/templates/yaksh/add_module.html | 140 ++++++ yaksh/templates/yaksh/add_quiz.html | 13 +- yaksh/templates/yaksh/complete.html | 9 +- yaksh/templates/yaksh/course_detail.html | 10 +- yaksh/templates/yaksh/courses.html | 554 +++++++++++++++++------ yaksh/templates/yaksh/design_course_session.html | 107 +++++ yaksh/templates/yaksh/grade_user.html | 12 +- yaksh/templates/yaksh/intro.html | 13 +- yaksh/templates/yaksh/moderator_dashboard.html | 11 +- yaksh/templates/yaksh/monitor.html | 10 +- yaksh/templates/yaksh/question.html | 6 +- yaksh/templates/yaksh/quit.html | 7 +- yaksh/templates/yaksh/quizzes_user.html | 74 ++- yaksh/templates/yaksh/regrade.html | 4 +- yaksh/templates/yaksh/show_video.html | 63 +++ yaksh/templates/yaksh/statistics_question.html | 2 +- yaksh/templates/yaksh/user_data.html | 13 +- 22 files changed, 886 insertions(+), 241 deletions(-) create mode 100644 yaksh/templates/yaksh/add_lesson.html create mode 100644 yaksh/templates/yaksh/add_module.html create mode 100644 yaksh/templates/yaksh/design_course_session.html create mode 100644 yaksh/templates/yaksh/show_video.html (limited to 'yaksh') diff --git a/yaksh/templates/base.html b/yaksh/templates/base.html index e7cc15c..007d9b8 100644 --- a/yaksh/templates/base.html +++ b/yaksh/templates/base.html @@ -56,7 +56,7 @@ +

Developed by FOSSEE group, IIT Bombay

diff --git a/yaksh/templates/exam.html b/yaksh/templates/exam.html index a1f0df4..9b565eb 100644 --- a/yaksh/templates/exam.html +++ b/yaksh/templates/exam.html @@ -15,7 +15,7 @@ Yaksh
diff --git a/yaksh/templates/yaksh/add_course.html b/yaksh/templates/yaksh/add_course.html index b8fc11c..904cf5f 100644 --- a/yaksh/templates/yaksh/add_course.html +++ b/yaksh/templates/yaksh/add_course.html @@ -25,7 +25,7 @@ -
-
+
+
{% endblock %} diff --git a/yaksh/templates/yaksh/add_lesson.html b/yaksh/templates/yaksh/add_lesson.html new file mode 100644 index 0000000..9e1ee1d --- /dev/null +++ b/yaksh/templates/yaksh/add_lesson.html @@ -0,0 +1,61 @@ +{% extends "manage.html" %} +{% load custom_filters %} + +{% block title %}Create/Edit Lesson{% endblock %} + +{% block script %} + +{% endblock %} + +{% block content %} +
+ {% csrf_token %} +
+ + {{ lesson_form.as_table }} + {{ lesson_file_form.as_table }} +
+
+

+
+ {% if lesson_files %} +
+

Files added to this lesson

+
+ {% for f in lesson_files %} +

 Delete  + {{ f.file.name|file_title }} + ({{f.file.url}}) +


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

No Files added to this lesson

+
+ {% endif %} + +
+

+
+ + {% if lesson_files %} + + {% endif %} + + +
+
+ +
+{% endblock %} \ No newline at end of file diff --git a/yaksh/templates/yaksh/add_module.html b/yaksh/templates/yaksh/add_module.html new file mode 100644 index 0000000..f9676e6 --- /dev/null +++ b/yaksh/templates/yaksh/add_module.html @@ -0,0 +1,140 @@ +{% extends "manage.html" %} +{% load custom_filters %} +{% block title %}Create/Edit Learning Module{% endblock %} + +{% block pagetitle %}

Design Learning Module

{% endblock %} + +{% block script %} + + + +{% endblock %} + +{% block css %} + +{% endblock %} + +{% block content %} +{% if course_id %} + Cancel +{% else %} + Cancel +{% endif %} +{% if status == "add" %} +
+ {% csrf_token %} +
+ + {{ module_form.as_table }} +
+
+

+
+ + +
+
+
+ +{% endif %} + +{% if status == "design" %} +

Add/Edit Learning Units

+
+{% csrf_token %} +
+
+
+
+

Available Lessons and quizzes: (Add Lessons and Quizzes)

+
+
    + {% for type, unit in quiz_les_list %} +
  • + +
  • + {% endfor %} +
+
+
+
+
+ +
+

+
+
+
+

Choosen Lessons and quizzes: +

+
+ + + + + + + + {% for unit in learning_units %} + +
    +
+ {% if unit.learning_type == "quiz" %} + + + {% else %} + + + {% endif %} + + + + {% endfor %} +
SelectQuiz/LessonOrderCheck Prerequisite + + + What's This + +
+ + {{ unit.quiz.description }} ({{unit.learning_type}}) + {{ unit.lesson.name }} ({{unit.learning_type}}) + + +  {{unit.check_prerequisite}} +
+
+
+
+
+ + + +
+
+
+
+
+{% endif %} +{% endblock %} \ No newline at end of file diff --git a/yaksh/templates/yaksh/add_quiz.html b/yaksh/templates/yaksh/add_quiz.html index 08bb124..d3705e3 100644 --- a/yaksh/templates/yaksh/add_quiz.html +++ b/yaksh/templates/yaksh/add_quiz.html @@ -18,7 +18,7 @@
{% csrf_token %}
- +
{{ form.as_table }}
@@ -30,14 +32,6 @@ Rejected Students {% endif %}
  • - - {% if course.active %}Deactivate Course {% else %} Activate Course {% endif %} -
  • -
  • - - Clone Course -
  • -
  • Send Mail
  • diff --git a/yaksh/templates/yaksh/courses.html b/yaksh/templates/yaksh/courses.html index e09a9cc..b3d7d1f 100644 --- a/yaksh/templates/yaksh/courses.html +++ b/yaksh/templates/yaksh/courses.html @@ -1,173 +1,425 @@ {% extends "manage.html" %} {% block title %} Courses {% endblock %} {% block pagetitle %} Courses {% endblock pagetitle %} +{% block script %} + +{% endblock %} {% block content %} +
    + +
    + + + + + + + + +
    +{% if type == "quiz" %} + Add new Quiz + {% if not quizzes %} +

    No new Quiz Added

    +

    + {% else %} +
    +

    Quizzes

    + + + + + + + + {% for quiz in quizzes %} + + + + + {% endfor %} + +
    Sr.NoQuizQuestionPaper
    {{forloop.counter}} + + + {% if quiz.questionpaper_set.get %} + + Question Paper for {{ quiz.description }} +
    + {% else %} +

    No Question Paper + Add +

    + {% endif %} +
    -

    - {% endfor %} -{% else %} -

    No new Courses allotted

    -

    + {% endif %} +{% endif %} +
    + + + +
    +{% if type == "lesson" %} + Add new Lesson + {% if not lessons %} +

    No new Lessons Added

    +

    + {% else %} +
    +

    Lessons

    + + + + + + + {% for lesson in lessons %} + + + + {% endfor %} + +
    Sr.NoLesson
    {{forloop.counter}} + +
    +
    + {% endif %} +{% endif %} +
    + + +
    +{% if type == "learning_module" %} + + Add new Module + {% if not learning_modules %} +

    No new learning modules Added

    +

    + {% else %} +
    +

    Learning Modules

    + + + + + + + + {% for module in learning_modules %} + + + + + + {% endfor %} + +
    Sr.NoLearning ModulesDesign ModuleLearning Units
    {{forloop.counter}} + + {{ module.name }} + + + Add Quizzes/Lessons for {{module.name}} + + + {% if module.get_learning_units %} + {% for unit in module.get_learning_units %} +
      + {% if unit.learning_type == 'quiz' %} + {{unit.quiz.description}} + {% else %} + {{unit.lesson.name}} + {% endif %} +
    + {% endfor %} + {% else %} + No Learning units + {% endif %} +
    +
    + {% endif %} {% endif %} -
    -
    +
    + {% endblock %} diff --git a/yaksh/templates/yaksh/design_course_session.html b/yaksh/templates/yaksh/design_course_session.html new file mode 100644 index 0000000..87acc33 --- /dev/null +++ b/yaksh/templates/yaksh/design_course_session.html @@ -0,0 +1,107 @@ +{% extends "manage.html" %} +{% load custom_filters %} +{% block title %}Design Course Session{% endblock %} + +{% block pagetitle %}Design Course Session{% endblock %} + +{% block script %} + + +{% endblock %} + +{% block css %} + +{% endblock %} + +{% block main %} +
    +{% csrf_token %} +
    +
    +
    +
    +

    Available Lessons and quizzes: (Add Lessons and Quizzes)

    +
    + + + + + + + {% for module in learning_modules %} +
      +
    + + + + + + + {% endfor %} +
    SelectLearning ModuleLearning Units
    {{ module.name }} + {% for unit in module.get_learning_units %} +
      +
    • + {% if unit.learning_type == "quiz" %} + {{unit.quiz.description}} + {% else %} + {{unit.lesson.name}} + {% endif %} +
    • +
    + {% endfor %} +
    +
    +
    +
    +
    + +
    +

    +
    +
    +
    +

    Choosen Lessons and quizzes: (Change Order)

    +
    + + + + + + + + {% for module in added_learning_modules %} + +
      +
    + + + + + + {% endfor %} +
    SelectLearning ModuleOrderCheck Prerequisite + + + What's This + +
    + + {{ module.name }} + + +  {{module.check_prerequisite}} +
    +
    +
    +
    +
    + +    + +
    +
    +
    +
    +
    +{% endblock %} \ No newline at end of file diff --git a/yaksh/templates/yaksh/grade_user.html b/yaksh/templates/yaksh/grade_user.html index d946647..a68d348 100644 --- a/yaksh/templates/yaksh/grade_user.html +++ b/yaksh/templates/yaksh/grade_user.html @@ -34,7 +34,7 @@ $(document).ready(function() {% if course.get_quizzes %} {% for quiz in course.get_quizzes %} -
  • +
  • {{quiz.description}}
  • {% endfor %} @@ -52,7 +52,7 @@ $(document).ready(function() {% if users %}
    {% for user in users %} -

    +

    {{user.user__first_name}} {{user.user__last_name}}

    {% endfor %}
    @@ -95,7 +95,7 @@ Attempt Number: {{paper.attempt_number}} - {{paper.question_paper.quiz.description}} + {{paper.question_paper.quiz.description}} {% endfor %} diff --git a/yaksh/templates/yaksh/monitor.html b/yaksh/templates/yaksh/monitor.html index 8df2e7d..e40293b 100644 --- a/yaksh/templates/yaksh/monitor.html +++ b/yaksh/templates/yaksh/monitor.html @@ -46,7 +46,7 @@ $(document).ready(function() {% if course.get_quizzes %} {% for quiz in course.get_quizzes %} -
  • +
  • {{quiz.description}}
  • {% endfor %} @@ -64,7 +64,7 @@ $(document).ready(function() {% if msg != "Monitor" %} {% if quiz %} {% if papers %} -

    Course Name: {{ quiz.course.name }}

    +

    Course Name: {{ course.name }}

    Quiz Name: {{ quiz.description }}

    Number of papers: {{ papers|length }}

    {% completed papers as completed_papers %} @@ -75,7 +75,7 @@ $(document).ready(function() {# template tag used to get the count of inprogress papers #}

    Papers in progress: {{ inprogress_papers }}

    -

    Question Statisitics

    +

    Question Statisitics

    -
    + {% csrf_token %} diff --git a/yaksh/templates/yaksh/quit.html b/yaksh/templates/yaksh/quit.html index d18b790..b168724 100644 --- a/yaksh/templates/yaksh/quit.html +++ b/yaksh/templates/yaksh/quit.html @@ -30,8 +30,11 @@

    Your current answers are saved.

    Are you sure you wish to quit the exam?

    Be sure, as you won't be able to restart this exam.

    - + {% csrf_token %} -
     
    +
    +   + +
    {% endblock content %} diff --git a/yaksh/templates/yaksh/quizzes_user.html b/yaksh/templates/yaksh/quizzes_user.html index b90db18..5699a07 100644 --- a/yaksh/templates/yaksh/quizzes_user.html +++ b/yaksh/templates/yaksh/quizzes_user.html @@ -1,4 +1,5 @@ {% extends "user.html" %} +{% load custom_filters %} {% block pagetitle %} {{ title }} {% endblock %} {% block main %} {% if 'Enrolled Courses' not in title%} @@ -50,39 +51,64 @@ No Courses to display
    - {% if user in course.students.all %} + {% if user in course.students.all and course.get_learning_modules %} - - - - {% for quiz in course.get_quizzes %} - {% if quiz.active and quiz.course_id == course.id %} + + + + {% for module in course.get_learning_modules %} - {% if not quiz.is_expired and course.active %} - - {% else %} - - {% endif %} + - {% endif %} {% endfor %}
    QuizView Answer PaperPre requisite quizLearning ModulesLearning UnitsStatus
    - {{ quiz.description }}
    -
    - {{ quiz.description }} Inactive
    -
    - {% if quiz.view_answerpaper %} - Can View - {% else %} - Cannot view now - {% endif %} + + {{module.name}} - {% if quiz.prerequisite %} - You have to pass {{ quiz.prerequisite.description }} for taking {{ paper.quiz.description }} + + + + + {% for unit in module.get_learning_units %} + +
      +
    + + + + + {% endfor %} +
    Lesson/quizstatusView Answerpaper
    + {% if unit.learning_type == "quiz" %} + {{unit.quiz.description}} + {% else %} + {{unit.lesson.name}} + {% endif %} + + {% get_unit_status course module unit user as status %} + {% if status == "completed" %} + {{status}} + {% else %} + {{status}} + {% endif %} + + {% if unit.learning_type == "quiz" %} + {% if quiz.view_answerpaper %} + Can View + {% else %} + Cannot view now + {% endif %} + {% else %} + ------ + {% endif %} +
    +
    + {% if module.status == "completed" %} + {{module.status}} {% else %} - No pre requisites for {{ quiz.description }} + {{module.status}} {% endif %}
    {% endif %} diff --git a/yaksh/templates/yaksh/regrade.html b/yaksh/templates/yaksh/regrade.html index 844c6ee..77e28df 100644 --- a/yaksh/templates/yaksh/regrade.html +++ b/yaksh/templates/yaksh/regrade.html @@ -33,7 +33,7 @@ Course: {{ course }}
    - {% for quiz in course.quiz_set.all %} + {% for quiz in course.get_quizzes %}

    Quiz: {{ quiz }}

    {% with questionpaper=quiz.questionpaper_set.get %} @@ -69,7 +69,7 @@ Course: {{ course }}
    - {% for quiz in course.quiz_set.all %} + {% for quiz in course.get_quizzes %}

    Quiz: {{ quiz }}

      diff --git a/yaksh/templates/yaksh/show_video.html b/yaksh/templates/yaksh/show_video.html new file mode 100644 index 0000000..f0d1c73 --- /dev/null +++ b/yaksh/templates/yaksh/show_video.html @@ -0,0 +1,63 @@ +{% extends "user.html" %} +{% load custom_filters %} + +{% block title %} {{ learning_module.name }} {% endblock %} + +{% block pagetitle %} {{ learning_module.name }} {% endblock %} + +{% block usersidebar %} +


      +

      Module List

      +
        +{% for unit in learning_units %} + +
      • +{% if unit.learning_type == "quiz" %} + + {{ unit.quiz.description }} +{% else %} + + {{ unit.lesson.name }} +{% endif %} + +{% get_unit_status course learning_module unit user as status %} +{% if status == "completed" %} + {{status}} +{% else %} + {{status}} +{% endif %} +
      • +
        +
        +{% endfor %} +
      +{% endblock %} + +{% block main %} +{% if state == "module" %} +
      +
      + {{learning_module.html_data|safe}} +
      +
      + +{% else %} +

      {{lesson.name}}

      +
      +
      + {{lesson.html_data|safe}} +
      +
      + +{% endif %} +{% endblock %} \ No newline at end of file diff --git a/yaksh/templates/yaksh/statistics_question.html b/yaksh/templates/yaksh/statistics_question.html index 31e889b..c6f4e57 100644 --- a/yaksh/templates/yaksh/statistics_question.html +++ b/yaksh/templates/yaksh/statistics_question.html @@ -6,7 +6,7 @@
      {% for attempt in attempts %} -

      Attempt {{ attempt }}

      +

      Attempt {{ attempt }}

      {% endfor %}
      diff --git a/yaksh/templates/yaksh/user_data.html b/yaksh/templates/yaksh/user_data.html index e12a0a0..60269e4 100644 --- a/yaksh/templates/yaksh/user_data.html +++ b/yaksh/templates/yaksh/user_data.html @@ -26,14 +26,9 @@ Last login: {{ data.user.last_login }}

      {% if data.papers %} -{% if data.questionpaperid %} -

      +

      Grade/correct paper

      -{% else %} -

      - Grade/correct paper -{% endif %} {% for paper in data.papers %} {% if forloop.counter == 2 and data.questionpaperid %} @@ -58,11 +53,11 @@ User IP address: {{ paper.user_ip }}

      Details: {{forloop.counter}}. {{ question.summary }} - Show Question + Show Question Mark(s): {{ question.points }}
      -