diff options
author | King | 2018-07-13 05:13:04 -0700 |
---|---|---|
committer | GitHub | 2018-07-13 05:13:04 -0700 |
commit | a9e36d0ba393bc709c8bd61b133170e9506aa510 (patch) | |
tree | 710c21594258dff7cfaa22e3ec39191855c2d9a8 | |
parent | f0f4a882a796319f766ff67cd3f8133a04054dfd (diff) | |
parent | 4346684d4ed863e5628697ccebe92bbe85fb77a4 (diff) | |
download | online_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.txt | 17 | ||||
-rw-r--r-- | online_test/__init__.py | 2 | ||||
-rw-r--r-- | yaksh/evaluator_tests/test_python_evaluation.py | 1 | ||||
-rw-r--r-- | yaksh/file_utils.py | 66 | ||||
-rw-r--r-- | yaksh/fixtures/demo_questions.zip | bin | 3230 -> 9957 bytes | |||
-rw-r--r-- | yaksh/live_server_tests/selenium_test.py | 9 | ||||
-rw-r--r-- | yaksh/migrations/0013_release_0_9_0.py | 48 | ||||
-rw-r--r-- | yaksh/models.py | 83 | ||||
-rw-r--r-- | yaksh/test_views.py | 14 |
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 Binary files differindex 1618341..6b0f852 100644 --- a/yaksh/fixtures/demo_questions.zip +++ b/yaksh/fixtures/demo_questions.zip 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( |