summaryrefslogtreecommitdiff
path: root/yaksh/models.py
diff options
context:
space:
mode:
Diffstat (limited to 'yaksh/models.py')
-rw-r--r--yaksh/models.py197
1 files changed, 185 insertions, 12 deletions
diff --git a/yaksh/models.py b/yaksh/models.py
index 1b76eed..0c5a6f5 100644
--- a/yaksh/models.py
+++ b/yaksh/models.py
@@ -1,3 +1,4 @@
+# Python Imports
from __future__ import unicode_literals, division
from datetime import datetime, timedelta
import uuid
@@ -8,14 +9,6 @@ from ruamel.yaml.scalarstring import PreservedScalarString
from ruamel.yaml.comments import CommentedMap
from random import sample
from collections import Counter, defaultdict
-
-from django.db import models
-from django.contrib.auth.models import User, Group, Permission
-from django.core.exceptions import ValidationError
-from django.contrib.contenttypes.models import ContentType
-from taggit.managers import TaggableManager
-from django.utils import timezone
-from django.core.files import File
import glob
try:
@@ -31,14 +24,29 @@ import zipfile
import tempfile
from textwrap import dedent
from ast import literal_eval
-from .file_utils import extract_files, delete_files
+
+# Django Imports
+from django.db import models
+from django.contrib.auth.models import User, Group, Permission
+from django.core.exceptions import ValidationError
+from django.contrib.contenttypes.models import ContentType
+from taggit.managers import TaggableManager
+from django.utils import timezone
+from django.core.files import File
+from django.contrib.contenttypes.fields import (
+ GenericForeignKey, GenericRelation
+)
+from django.contrib.contenttypes.models import ContentType
from django.template import Context, Template
+from django.conf import settings
+from django.forms.models import model_to_dict
+from django.db.models import Count
+# Local Imports
from yaksh.code_server import (
submit, get_result as get_result_from_code_server
)
from yaksh.settings import SERVER_POOL_PORT, SERVER_HOST_NAME
-from django.conf import settings
-from django.forms.models import model_to_dict
+from .file_utils import extract_files, delete_files
from grades.models import GradingSystem
languages = (
@@ -281,11 +289,16 @@ class Lesson(models.Model):
# A video file
video_file = models.FileField(
- upload_to=get_file_dir, default=None,
+ upload_to=get_file_dir, max_length=255, default=None,
null=True, blank=True,
help_text="Please upload video files in mp4, ogv, webm format"
)
+ video_path = models.CharField(
+ max_length=255, default=None, null=True, blank=True,
+ help_text="Youtube id, vimeo id, others"
+ )
+
def __str__(self):
return "{0}".format(self.name)
@@ -1337,6 +1350,8 @@ class Question(models.Model):
# Solution for the question.
solution = models.TextField(blank=True)
+ content = GenericRelation("TableOfContents")
+
tc_code_types = {
"python": [
("standardtestcase", "Standard TestCase"),
@@ -2750,6 +2765,164 @@ class Comment(ForumBase):
self.post_field.title)
+class TOCManager(models.Manager):
+
+ def get_data(self, course_id, lesson_id):
+ contents = TableOfContents.objects.filter(
+ course_id=course_id, lesson_id=lesson_id, content__in=[2, 3, 4]
+ )
+ data = {}
+ for toc in contents:
+ data[toc] = LessonQuizAnswer.objects.filter(
+ toc_id=toc.id).values_list("toc_id").distinct().count()
+ return data
+
+ def get_question_stats(self, toc_id):
+ answers = LessonQuizAnswer.objects.get_queryset().filter(
+ toc_id=toc_id).order_by('id')
+ question = answers.first().toc.content_object
+ answers = answers.values(
+ "student__first_name", "student__last_name", "student__email",
+ "student_id", "toc_id"
+ ).distinct()
+ return question, answers
+
+ def get_answer(self, toc_id, user_id):
+ submission = LessonQuizAnswer.objects.filter(
+ toc_id=toc_id, student_id=user_id).last()
+ question = submission.toc.content_object
+ attempted_answer = submission.answer
+ if question.type == "mcq":
+ submitted_answer = literal_eval(attempted_answer.answer)
+ answers = [
+ tc.options
+ for tc in question.get_test_cases(id=submitted_answer)
+ ]
+ answer = ",".join(answers)
+ elif question.type == "mcc":
+ submitted_answer = literal_eval(attempted_answer.answer)
+ answers = [
+ tc.options
+ for tc in question.get_test_cases(id__in=submitted_answer)
+ ]
+ answer = ",".join(answers)
+ else:
+ answer = attempted_answer.answer
+ return answer, attempted_answer.correct
+
+
+class TableOfContents(models.Model):
+ toc_types = ((1, "Topic"), (2, "Graded Quiz"), (3, "Exercise"), (4, "Poll"))
+ course = models.ForeignKey(Course, on_delete=models.CASCADE,
+ related_name='course')
+ lesson = models.ForeignKey(Lesson, on_delete=models.CASCADE,
+ related_name='contents')
+ time = models.CharField(max_length=100, default=0)
+ content = models.IntegerField(choices=toc_types)
+ content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
+ object_id = models.PositiveIntegerField()
+ content_object = GenericForeignKey()
+
+ objects = TOCManager()
+
+ class Meta:
+ verbose_name_plural = "Table Of Contents"
+
+ def get_toc_text(self):
+ if self.content == 1:
+ content_name = self.content_object.name
+ else:
+ content_name = self.content_object.summary
+ return content_name
+
+ def __str__(self):
+ return f"TOC for {self.lesson.name} with {self.get_content_display()}"
+
+
+class Topic(models.Model):
+ name = models.CharField(max_length=255)
+ description = models.TextField(null=True, blank=True)
+ content = GenericRelation(TableOfContents)
+
+ def __str__(self):
+ return f"{self.name}"
+
+
+class LessonQuizAnswer(models.Model):
+ toc = models.ForeignKey(TableOfContents, on_delete=models.CASCADE)
+ student = models.ForeignKey(User, on_delete=models.CASCADE)
+ answer = models.ForeignKey(Answer, on_delete=models.CASCADE)
+
+ def check_answer(self, user_answer):
+ result = {'success': False, 'error': ['Incorrect answer'],
+ 'weight': 0.0}
+ question = self.toc.content_object
+ if question.type == 'mcq':
+ expected_answer = question.get_test_case(correct=True).id
+ if user_answer.strip() == str(expected_answer).strip():
+ result['success'] = True
+ result['error'] = ['Correct answer']
+
+ elif question.type == 'mcc':
+ expected_answers = [
+ str(opt.id) for opt in question.get_test_cases(correct=True)
+ ]
+ if set(user_answer) == set(expected_answers):
+ result['success'] = True
+ result['error'] = ['Correct answer']
+
+ elif question.type == 'integer':
+ expected_answers = [
+ int(tc.correct) for tc in question.get_test_cases()
+ ]
+ if int(user_answer) in expected_answers:
+ result['success'] = True
+ result['error'] = ['Correct answer']
+
+ elif question.type == 'string':
+ tc_status = []
+ for tc in question.get_test_cases():
+ if tc.string_check == "lower":
+ if tc.correct.lower().splitlines()\
+ == user_answer.lower().splitlines():
+ tc_status.append(True)
+ else:
+ if tc.correct.splitlines()\
+ == user_answer.splitlines():
+ tc_status.append(True)
+ if any(tc_status):
+ result['success'] = True
+ result['error'] = ['Correct answer']
+
+ elif question.type == 'float':
+ user_answer = float(user_answer)
+ tc_status = []
+ for tc in question.get_test_cases():
+ if abs(tc.correct - user_answer) <= tc.error_margin:
+ tc_status.append(True)
+ if any(tc_status):
+ result['success'] = True
+ result['error'] = ['Correct answer']
+
+ elif question.type == 'arrange':
+ testcase_ids = sorted(
+ [tc.id for tc in question.get_test_cases()]
+ )
+ if user_answer == testcase_ids:
+ result['success'] = True
+ result['error'] = ['Correct answer']
+ self.answer.error = result
+ ans_status = result.get("success")
+ self.answer.correct = ans_status
+ if ans_status:
+ self.answer.marks = self.answer.question.points
+ self.answer.save()
+ return result
+
+ def __str__(self):
+ return f"Lesson answer of {self.toc} by {self.student.get_full_name()}"
+
+
class MicroManager(models.Model):
manager = models.ForeignKey(User, on_delete=models.CASCADE,
related_name='micromanaging', null=True)