summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKing2018-07-13 05:13:04 -0700
committerGitHub2018-07-13 05:13:04 -0700
commita9e36d0ba393bc709c8bd61b133170e9506aa510 (patch)
tree710c21594258dff7cfaa22e3ec39191855c2d9a8
parentf0f4a882a796319f766ff67cd3f8133a04054dfd (diff)
parent4346684d4ed863e5628697ccebe92bbe85fb77a4 (diff)
downloadonline_test-a9e36d0ba393bc709c8bd61b133170e9506aa510.tar.gz
online_test-a9e36d0ba393bc709c8bd61b133170e9506aa510.tar.bz2
online_test-a9e36d0ba393bc709c8bd61b133170e9506aa510.zip
Merge pull request #498 from maheshgudi/release-0.9v0.9.0
release v0.9
-rw-r--r--CHANGELOG.txt17
-rw-r--r--online_test/__init__.py2
-rw-r--r--yaksh/evaluator_tests/test_python_evaluation.py1
-rw-r--r--yaksh/file_utils.py66
-rw-r--r--yaksh/fixtures/demo_questions.zipbin3230 -> 9957 bytes
-rw-r--r--yaksh/live_server_tests/selenium_test.py9
-rw-r--r--yaksh/migrations/0013_release_0_9_0.py48
-rw-r--r--yaksh/models.py83
-rw-r--r--yaksh/test_views.py14
9 files changed, 155 insertions, 85 deletions
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index d603d34..5aa0cc3 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -1,3 +1,20 @@
+=== 0.9 (13-07-2018) ===
+
+* Questions can be searched using tags while creating/editing question papers.
+* Fixed a bug that would not select all questions in Question page.
+* Fixed a bug in QuestionFilterForm that would force marks value to be selected
+ in Question page.
+* Added a feature that can download all lessons of a course for offline viewing.
+* Yaml files can be used to upload Questions along with zip files.
+ Support for uploading multiple Yaml files at once also added.
+* Moderator can switch between student and moderator from the dashboard.
+* Updated Yaksh to act like a Django app. Updated pip package.
+* Appropriate Exceptions are raised for C, C++ and Java assertion and
+ STDIO questions.
+* Fixed a bug that would create multiple TestCaseOrder objects for an
+ answerpaper.
+* Updated README.rst.
+
=== 0.8.1 (18-06-2018) ===
* Fixed a bug where quiz completion shows inprogress even after completing.
diff --git a/online_test/__init__.py b/online_test/__init__.py
index ef72cc0..e46aee1 100644
--- a/online_test/__init__.py
+++ b/online_test/__init__.py
@@ -1 +1 @@
-__version__ = '0.8.1'
+__version__ = '0.9'
diff --git a/yaksh/evaluator_tests/test_python_evaluation.py b/yaksh/evaluator_tests/test_python_evaluation.py
index 1933d17..ad9b2c2 100644
--- a/yaksh/evaluator_tests/test_python_evaluation.py
+++ b/yaksh/evaluator_tests/test_python_evaluation.py
@@ -173,7 +173,6 @@ class PythonAssertionEvaluationTestCases(EvaluatorBaseTest):
grader = Grader(self.in_dir)
result = grader.evaluate(kwargs)
err = result.get("error")[0]['traceback']
-
# Then
self.assertFalse(result.get("success"))
for msg in syntax_error_msg:
diff --git a/yaksh/file_utils.py b/yaksh/file_utils.py
index 1dc6006..7c31c70 100644
--- a/yaksh/file_utils.py
+++ b/yaksh/file_utils.py
@@ -3,7 +3,6 @@ import os
import zipfile
import tempfile
import csv
-from django.template import Context, Template
def copy_files(file_paths):
@@ -67,68 +66,3 @@ def is_csv(document):
except (csv.Error, UnicodeDecodeError):
return False, None
return True, dialect
-
-
-def write_static_files_to_zip(zipfile, course_name, current_dir, static_files):
- """ Write static files to zip
-
- Parameters
- ----------
-
- zipfile : Zipfile object
- zip file in which the static files need to be added
-
- course_name : str
- Create a folder with course name
-
- current_dir: str
- Path from which the static files will be taken
-
- static_files: dict
- Dictionary containing static folders as keys and static files as
- values
- """
- for folder in static_files.keys():
- folder_path = os.sep.join((current_dir, "static", "yaksh", folder))
- for file in static_files[folder]:
- file_path = os.sep.join((folder_path, file))
- with open(file_path, "rb") as f:
- zipfile.writestr(
- os.sep.join((course_name, "static", folder, file)),
- f.read()
- )
-
-
-def write_templates_to_zip(zipfile, template_path, data, filename, filepath):
- """ Write template files to zip
-
- Parameters
- ----------
-
- zipfile : Zipfile object
- zip file in which the template files need to be added
-
- template_path : str
- Path from which the template file will be loaded
-
- data: dict
- Dictionary containing context data required for template
-
- filename: str
- Filename with which the template file should be named
-
- filepath: str
- File path in zip where the template will be added
- """
- rendered_template = render_template(template_path, data)
- zipfile.writestr(os.sep.join((filepath, "{0}.html".format(filename))),
- str(rendered_template))
-
-
-def render_template(template_path, data):
- with open(template_path) as f:
- template_data = f.read()
- template = Template(template_data)
- context = Context(data)
- render = template.render(context)
- return render
diff --git a/yaksh/fixtures/demo_questions.zip b/yaksh/fixtures/demo_questions.zip
index 1618341..6b0f852 100644
--- a/yaksh/fixtures/demo_questions.zip
+++ b/yaksh/fixtures/demo_questions.zip
Binary files differ
diff --git a/yaksh/live_server_tests/selenium_test.py b/yaksh/live_server_tests/selenium_test.py
index 6351f9e..5bf1988 100644
--- a/yaksh/live_server_tests/selenium_test.py
+++ b/yaksh/live_server_tests/selenium_test.py
@@ -118,7 +118,7 @@ class SeleniumTest():
# Correct Answer
loop_count = 1
- answer = '\"#!/bin/bash\\ncat $1 | cut -d: -f2 | paste -d: $3 - $2\"'
+ answer = '\"#!/bin/bash\\necho Hello, World!\"'
self.submit_answer(question_label, answer, loop_count)
def open_quiz(self):
@@ -135,9 +135,9 @@ class SeleniumTest():
)
start_exam_elem.click()
- self.test_c_question(question_label=7)
- self.test_python_question(question_label=5)
- self.test_bash_question(question_label=4)
+ self.test_c_question(question_label=6)
+ self.test_python_question(question_label=4)
+ self.test_bash_question(question_label=10)
def quit_quiz(self):
quit_link_elem = WebDriverWait(self.driver, 5).until(
@@ -172,6 +172,7 @@ def wrap_run_load_test(args):
selenium_test = SeleniumTest(url=url, quiz_name=quiz_name)
return selenium_test.run_load_test(*args)
+
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument(
diff --git a/yaksh/migrations/0013_release_0_9_0.py b/yaksh/migrations/0013_release_0_9_0.py
new file mode 100644
index 0000000..3f7f377
--- /dev/null
+++ b/yaksh/migrations/0013_release_0_9_0.py
@@ -0,0 +1,48 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10 on 2018-07-13 10:24
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import yaksh.models
+
+
+def set_is_moderator(apps, schema_editor):
+ """ Set is_moderator to True for all users that belong
+ to Moderator group """
+
+ Profile = apps.get_model('yaksh', 'Profile')
+ for prof in Profile.objects.all():
+ user = prof.user
+ if user.groups.filter(name='moderator').exists():
+ prof.is_moderator = True
+ prof.save()
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('yaksh', '0012_release_0_8_1'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='lesson',
+ name='video_file',
+ field=models.FileField(blank=True, default=None, help_text='Please upload video files in mp4, ogv, webm format', null=True, upload_to=yaksh.models.get_file_dir),
+ ),
+ migrations.AddField(
+ model_name='profile',
+ name='is_moderator',
+ field=models.BooleanField(default=False),
+ ),
+ migrations.AlterField(
+ model_name='lessonfile',
+ name='file',
+ field=models.FileField(default=None, upload_to=yaksh.models.get_file_dir),
+ ),
+ migrations.AlterUniqueTogether(
+ name='testcaseorder',
+ unique_together=set([('answer_paper', 'question', 'order')]),
+ ),
+ migrations.RunPython(set_is_moderator),
+ ]
diff --git a/yaksh/models.py b/yaksh/models.py
index 152289f..60b09c5 100644
--- a/yaksh/models.py
+++ b/yaksh/models.py
@@ -28,10 +28,8 @@ import zipfile
import tempfile
from textwrap import dedent
from ast import literal_eval
-from .file_utils import (
- extract_files, delete_files, write_templates_to_zip,
- write_static_files_to_zip
-)
+from .file_utils import extract_files, delete_files
+from django.template import Context, Template
from yaksh.code_server import (
submit, get_result as get_result_from_code_server
)
@@ -137,6 +135,7 @@ def get_file_dir(instance, filename):
upload_dir = instance.name.replace(" ", "_")
return os.sep.join((upload_dir, filename))
+
def create_group(group_name, app_label):
try:
group = Group.objects.get(name=group_name)
@@ -153,6 +152,71 @@ def create_group(group_name, app_label):
return group
+def write_static_files_to_zip(zipfile, course_name, current_dir, static_files):
+ """ Write static files to zip
+
+ Parameters
+ ----------
+
+ zipfile : Zipfile object
+ zip file in which the static files need to be added
+
+ course_name : str
+ Create a folder with course name
+
+ current_dir: str
+ Path from which the static files will be taken
+
+ static_files: dict
+ Dictionary containing static folders as keys and static files as
+ values
+ """
+ for folder in static_files.keys():
+ folder_path = os.sep.join((current_dir, "static", "yaksh", folder))
+ for file in static_files[folder]:
+ file_path = os.sep.join((folder_path, file))
+ with open(file_path, "rb") as f:
+ zipfile.writestr(
+ os.sep.join((course_name, "static", folder, file)),
+ f.read()
+ )
+
+
+def write_templates_to_zip(zipfile, template_path, data, filename, filepath):
+ """ Write template files to zip
+
+ Parameters
+ ----------
+
+ zipfile : Zipfile object
+ zip file in which the template files need to be added
+
+ template_path : str
+ Path from which the template file will be loaded
+
+ data: dict
+ Dictionary containing context data required for template
+
+ filename: str
+ Filename with which the template file should be named
+
+ filepath: str
+ File path in zip where the template will be added
+ """
+ rendered_template = render_template(template_path, data)
+ zipfile.writestr(os.sep.join((filepath, "{0}.html".format(filename))),
+ str(rendered_template))
+
+
+def render_template(template_path, data):
+ with open(template_path) as f:
+ template_data = f.read()
+ template = Template(template_data)
+ context = Context(data)
+ render = template.render(context)
+ return render
+
+
###############################################################################
class CourseManager(models.Manager):
@@ -1490,8 +1554,8 @@ class QuestionPaper(models.Model):
testcases_ids = ",".join([str(tc.id) for tc in testcases]
)
if not TestCaseOrder.objects.filter(
- answer_paper=ans_paper, question=question
- ).exists():
+ answer_paper=ans_paper, question=question
+ ).exists():
TestCaseOrder.objects.create(
answer_paper=ans_paper, question=question,
order=testcases_ids)
@@ -1532,9 +1596,11 @@ class QuestionPaper(models.Model):
question_paper = QuestionPaper.objects.create(quiz=demo_quiz,
shuffle_questions=False
)
- summaries = ['Roots of quadratic equation', 'Print Output',
+ summaries = ['Find the value of n', 'Print Output in Python2.x',
'Adding decimals', 'For Loop over String',
- 'Hello World in File', 'Extract columns from files',
+ 'Hello World in File',
+ 'Arrange code to convert km to miles',
+ 'Print Hello, World!', "Square of two numbers",
'Check Palindrome', 'Add 3 numbers', 'Reverse a string'
]
questions = Question.objects.filter(active=True,
@@ -2331,7 +2397,6 @@ class TestCaseOrder(models.Model):
# Order of the test case for a question.
order = models.TextField()
-
class Meta:
unique_together = ("answer_paper", "question", "order")
diff --git a/yaksh/test_views.py b/yaksh/test_views.py
index 899ed31..3520c61 100644
--- a/yaksh/test_views.py
+++ b/yaksh/test_views.py
@@ -1345,6 +1345,7 @@ class TestAddQuiz(TestCase):
self.assertEqual(response.context['quizzes'][0], self.quiz)
self.assertTemplateUsed(response, "yaksh/courses.html")
+
class TestAddAsModerator(TestCase):
def setUp(self):
self.client = Client()
@@ -1399,6 +1400,7 @@ class TestAddAsModerator(TestCase):
with self.assertRaises(Http404):
add_as_moderator(self.user, 'moderator')
+
class TestToggleModerator(TestCase):
def setUp(self):
self.client = Client()
@@ -1481,6 +1483,7 @@ class TestToggleModerator(TestCase):
self.assertEqual(response.status_code, 404)
+
class TestAddTeacher(TestCase):
def setUp(self):
self.client = Client()
@@ -2850,7 +2853,8 @@ class TestCourseDetail(TestCase):
target_status_code=301)
def test_send_mail_to_course_students(self):
- """ Check if bulk mail is sent to multiple students enrolled in a course
+ """ Check if bulk mail is sent to multiple students enrolled
+ in a course
"""
self.client.login(
username=self.user1.username,
@@ -4384,9 +4388,11 @@ class TestShowQuestions(TestCase):
data={'file': questions_file,
'upload': 'upload'}
)
- summaries = ['Roots of quadratic equation', 'Print Output',
+ summaries = ['Find the value of n', 'Print Output in Python2.x',
'Adding decimals', 'For Loop over String',
- 'Hello World in File', 'Extract columns from files',
+ 'Hello World in File',
+ 'Arrange code to convert km to miles',
+ 'Print Hello, World!', "Square of two numbers",
'Check Palindrome', 'Add 3 numbers', 'Reverse a string'
]
@@ -4395,7 +4401,7 @@ class TestShowQuestions(TestCase):
user=self.user).count()
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'yaksh/showquestions.html')
- self.assertEqual(uploaded_ques, 9)
+ self.assertEqual(uploaded_ques, 11)
f.close()
dummy_file = SimpleUploadedFile("test.txt", b"test")
response = self.client.post(