summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--yaksh/file_utils.py2
-rw-r--r--yaksh/fixtures/demo_questions.zipbin3055 -> 3230 bytes
-rw-r--r--yaksh/models.py30
-rw-r--r--yaksh/templates/yaksh/showquestions.html29
-rw-r--r--yaksh/test_models.py4
-rw-r--r--yaksh/test_views.py89
6 files changed, 136 insertions, 18 deletions
diff --git a/yaksh/file_utils.py b/yaksh/file_utils.py
index 6c3fd5d..7c31c70 100644
--- a/yaksh/file_utils.py
+++ b/yaksh/file_utils.py
@@ -46,7 +46,7 @@ def extract_files(zip_file, path=None):
if path:
extract_path = path
else:
- extract_path = tempfile.gettempdir()
+ extract_path = tempfile.mkdtemp()
zip_file.extractall(extract_path)
zip_file.close()
return zfiles, extract_path
diff --git a/yaksh/fixtures/demo_questions.zip b/yaksh/fixtures/demo_questions.zip
index 4e86485..1618341 100644
--- a/yaksh/fixtures/demo_questions.zip
+++ b/yaksh/fixtures/demo_questions.zip
Binary files differ
diff --git a/yaksh/models.py b/yaksh/models.py
index 5d17dba..3e4644b 100644
--- a/yaksh/models.py
+++ b/yaksh/models.py
@@ -13,6 +13,8 @@ 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:
from StringIO import StringIO as string_io
except ImportError:
@@ -1020,7 +1022,7 @@ class Question(models.Model):
tags = question.pop('tags') if 'tags' in question else None
test_cases = question.pop('testcase')
que, result = Question.objects.get_or_create(**question)
- if file_names:
+ if file_names and file_path:
que._add_files_to_db(file_names, file_path)
if tags:
que.tags.add(*tags)
@@ -1089,13 +1091,15 @@ class Question(models.Model):
files = FileUpload.objects.filter(question=self)
files_list = []
for f in files:
- zip_file.write(f.file.path, (os.path.basename(f.file.path)))
+ zip_file.write(f.file.path, os.path.join("additional_files",
+ os.path.basename(f.file.path))
+ )
files_list.append(((os.path.basename(f.file.path)), f.extract))
return files_list
def _add_files_to_db(self, file_names, path):
for file_name, extract in file_names:
- q_file = os.path.join(path, file_name)
+ q_file = glob.glob(os.path.join(path, "**", file_name))[0]
if os.path.exists(q_file):
que_file = open(q_file, 'rb')
# Converting to Python file object with
@@ -1130,16 +1134,16 @@ class Question(models.Model):
shutil.rmtree(tmp_file_path)
def read_yaml(self, file_path, user, files=None):
- yaml_file = os.path.join(file_path, "questions_dump.yaml")
- msg = ""
- if os.path.exists(yaml_file):
- with open(yaml_file, 'r') as q_file:
- questions_list = q_file.read()
- msg = self.load_questions(questions_list, user,
- file_path, files
- )
- else:
- msg = "Please upload zip file with questions_dump.yaml in it."
+ msg = "Failed to upload Questions"
+ for ext in ["yaml", "yml"]:
+ for yaml_file in glob.glob(
+ os.path.join(file_path, "*.{0}".format(ext))):
+ if os.path.exists(yaml_file):
+ with open(yaml_file, 'r') as q_file:
+ questions_list = q_file.read()
+ msg = self.load_questions(questions_list, user,
+ file_path, files
+ )
if files:
delete_files(files, file_path)
diff --git a/yaksh/templates/yaksh/showquestions.html b/yaksh/templates/yaksh/showquestions.html
index 4240b2e..06c088c 100644
--- a/yaksh/templates/yaksh/showquestions.html
+++ b/yaksh/templates/yaksh/showquestions.html
@@ -20,8 +20,35 @@
</div>
<div class="tab-content col-md-9 col-md-offset-2 main">
<!-- Upload Questions -->
+
<div id="updown" class="tab-pane fade">
-<a class="btn btn-primary" href="{{URL_ROOT}}/exam/manage/courses/download_yaml_template/"> Download Template</a>
+<div class="alert alert-info" role="alert">
+ <p>You can upload question files the following ways -
+ <li><b><u>Yaml File</u></b>
+ <p>One can upload Yaml file with extensions .yaml or .yml. Please note
+ that you cannot upload files associated to a question. Yaml file can
+ have any name.
+ </p>
+ </li>
+ <li><b><u>Zip File</u></b>
+ <p> One can also upload zip with the following zip structure -
+ <pre>
+ .zip
+ |-- .yaml or .yml
+ |-- .yaml or .yml
+ |-- folder1
+ | |-- Files required by questions
+ |-- folder2
+ | |-- Files required by questions
+ </pre>
+ </li>
+ </p>
+
+ <p>
+ <b> Click <a class="btn btn-success" href="{{URL_ROOT}}/exam/manage/courses/download_yaml_template/"
+>here</a> to download a sample YAML, edit and upload it</b>
+ </p>
+ </div>
<br/>
<h4> Or </h4>
<form action="" method="post" enctype="multipart/form-data">
diff --git a/yaksh/test_models.py b/yaksh/test_models.py
index eaf5bbc..e2795bb 100644
--- a/yaksh/test_models.py
+++ b/yaksh/test_models.py
@@ -434,7 +434,9 @@ class QuestionTestCases(unittest.TestCase):
def test_load_questions_with_all_fields(self):
""" Test load questions into database from Yaml """
question = Question()
- question.load_questions(self.yaml_questions_data, self.user1)
+ question.load_questions(self.yaml_questions_data, self.user1,
+ self.load_tmp_path
+ )
question_data = Question.objects.get(summary="Yaml Demo")
file = FileUpload.objects.get(question=question_data)
test_case = question_data.get_test_cases()
diff --git a/yaksh/test_views.py b/yaksh/test_views.py
index 8592031..edac077 100644
--- a/yaksh/test_views.py
+++ b/yaksh/test_views.py
@@ -25,7 +25,7 @@ from yaksh.models import (
User, Profile, Question, Quiz, QuestionPaper, AnswerPaper, Answer, Course,
AssignmentUpload, McqTestCase, IntegerTestCase, StringTestCase,
FloatTestCase, FIXTURES_DIR_PATH, LearningModule, LearningUnit, Lesson,
- LessonFile, CourseStatus
+ LessonFile, CourseStatus, dict_to_yaml
)
from yaksh.decorators import user_has_profile
@@ -3988,6 +3988,37 @@ class TestShowQuestions(TestCase):
points=1.0, language="python", type="mcq", user=self.user,
active=True
)
+ test_case_upload_data = [{"test_case": "assert fact(3)==6",
+ "test_case_type": "standardtestcase",
+ "test_case_args": "",
+ "weight": 1.0
+ }]
+ question_data_1 = {"snippet": "def fact()", "active": True,
+ "points": 1.0,
+ "description": "factorial of a no",
+ "language": "Python", "type": "Code",
+ "testcase": test_case_upload_data,
+ "summary": "Yaml Demo 2",
+ "tags": ['yaml_demo']
+ }
+
+ question_data_2 = {"snippet": "def fact()", "active": True,
+ "points": 1.0,
+ "description": "factorial of a no",
+ "language": "Python", "type": "Code",
+ "testcase": test_case_upload_data,
+ "summary": "Yaml Demo 3",
+ "tags": ['yaml_demo']
+ }
+ yaml_question_1 = dict_to_yaml(question_data_1)
+ yaml_question_2 = dict_to_yaml(question_data_2)
+ self.yaml_file_1 = SimpleUploadedFile("test1.yaml",
+ yaml_question_1.encode("utf-8")
+ )
+ self.yaml_file_2 = SimpleUploadedFile("test2.yaml",
+ yaml_question_2.encode("utf-8")
+ )
+
def test_show_questions_denies_student(self):
"""
@@ -4050,7 +4081,7 @@ class TestShowQuestions(TestCase):
self.assertTemplateUsed(response, 'yaksh/showquestions.html')
self.assertIn("download", response.context['msg'])
- def test_upload_questions(self):
+ def test_upload_zip_questions(self):
"""
Check for uploading questions zip file
"""
@@ -4090,6 +4121,60 @@ class TestShowQuestions(TestCase):
self.assertTemplateUsed(response, 'yaksh/showquestions.html')
self.assertIn("ZIP file", response.context['message'])
+ def test_upload_yaml_questions(self):
+ """
+ Check for uploading questions yaml file
+ """
+ self.client.login(
+ username=self.user.username,
+ password=self.user_plaintext_pass
+ )
+
+ response = self.client.post(
+ reverse('yaksh:show_questions'),
+ data={'file': self.yaml_file_1,
+ 'upload': 'upload'}
+ )
+ uploaded_ques = Question.objects.filter(
+ active=True, summary="Yaml Demo 2",
+ user=self.user)
+ self.assertEqual(response.status_code, 200)
+ self.assertTemplateUsed(response, 'yaksh/showquestions.html')
+ self.assertEqual(uploaded_ques.count(), 1)
+ uploaded_ques.delete()
+
+ def test_upload_multiple_yaml_zip_questions(self):
+ """
+ Check for uploading questions zip file with
+ multiple yaml files
+ """
+ self.client.login(
+ username=self.user.username,
+ password=self.user_plaintext_pass
+ )
+ zipfile_name = string_io()
+ zip_file = zipfile.ZipFile(zipfile_name, "w")
+ zip_file.writestr("test1.yaml", self.yaml_file_1.read())
+ zip_file.writestr("test2.yaml", self.yaml_file_2.read())
+ zip_file.close()
+ zipfile_name.seek(0)
+ questions_file = SimpleUploadedFile("questions.zip",
+ zipfile_name.read(),
+ content_type="application/zip"
+ )
+ response = self.client.post(
+ reverse('yaksh:show_questions'),
+ data={'file': questions_file,
+ 'upload': 'upload'}
+ )
+ uploaded_ques = Question.objects.filter(
+ active=True, summary="Yaml Demo 2",
+ user=self.user).count()
+ self.assertEqual(response.status_code, 200)
+ self.assertTemplateUsed(response, 'yaksh/showquestions.html')
+ self.assertEqual(uploaded_ques, 1)
+
+
def test_attempt_questions(self):
"""
Check for testing questions