summaryrefslogtreecommitdiff
path: root/yaksh
diff options
context:
space:
mode:
Diffstat (limited to 'yaksh')
-rw-r--r--yaksh/forms.py11
-rw-r--r--yaksh/models.py25
-rw-r--r--yaksh/templates/yaksh/ajax_question_filter.html3
-rw-r--r--yaksh/templates/yaksh/showquestions.html22
-rw-r--r--yaksh/tests.py77
-rw-r--r--yaksh/urls.py6
-rw-r--r--yaksh/views.py67
7 files changed, 170 insertions, 41 deletions
diff --git a/yaksh/forms.py b/yaksh/forms.py
index 16f82fb..c5bec4c 100644
--- a/yaksh/forms.py
+++ b/yaksh/forms.py
@@ -152,7 +152,7 @@ class QuestionForm(forms.ModelForm):
class Meta:
model = Question
- fields = '__all__'
+ exclude = ['user']
class RandomQuestionForm(forms.Form):
@@ -165,8 +165,9 @@ class RandomQuestionForm(forms.Form):
class QuestionFilterForm(forms.Form):
def __init__(self, *args, **kwargs):
+ user = kwargs.pop("user")
super(QuestionFilterForm, self).__init__(*args, **kwargs)
- questions = Question.objects.all()
+ questions = Question.objects.filter(user_id=user.id)
points_list = questions.values_list('points', flat=True).distinct()
points_options = [('select', 'Select Marks')]
points_options.extend([(point, point) for point in points_list])
@@ -188,6 +189,7 @@ class CourseForm(forms.ModelForm):
model = Course
fields = ['name', 'active', 'enrollment']
+
class ProfileForm(forms.ModelForm):
""" profile form for students and moderators """
@@ -205,3 +207,8 @@ class ProfileForm(forms.ModelForm):
super(ProfileForm, self).__init__(*args, **kwargs)
self.fields['first_name'].initial = user.first_name
self.fields['last_name'].initial = user.last_name
+
+
+class UploadFileForm(forms.Form):
+ file = forms.FileField()
+
diff --git a/yaksh/models.py b/yaksh/models.py
index 561b334..6e59d7a 100644
--- a/yaksh/models.py
+++ b/yaksh/models.py
@@ -173,6 +173,9 @@ class Question(models.Model):
# Tags for the Question.
tags = TaggableManager(blank=True)
+ # user for particular question
+ user = models.ForeignKey(User, related_name="user")
+
def consolidate_answer_data(self, test_cases, user_answer):
test_case_data_dict = []
question_info_dict = {}
@@ -208,6 +211,26 @@ class Question(models.Model):
return json.dumps(question_info_dict)
+ def dump_into_json(self, question_ids, user):
+ questions = Question.objects.filter(id__in = question_ids, user_id = user.id)
+ questions_dict = []
+ for question in questions:
+ q_dict = {'summary': question.summary, 'description': question.description,
+ 'points': question.points, 'test': question.test,
+ 'ref_code_path': question.ref_code_path,
+ 'options': question.options, 'language': question.language,
+ 'type': question.type, 'active': question.active,
+ 'snippet': question.snippet}
+ questions_dict.append(q_dict)
+
+ return json.dumps(questions_dict, indent=2)
+
+ def load_from_json(self, questions_list, user):
+ questions = json.loads(questions_list)
+ for question in questions:
+ question['user'] = user
+ Question.objects.get_or_create(**question)
+
def __unicode__(self):
return self.summary
@@ -487,7 +510,7 @@ class AnswerPaperManager(models.Manager):
return answerpapers.values_list('user', flat=True).distinct()
def get_latest_attempts(self, questionpaper_id):
- papers = self.get_answerpapers_for_quiz(questionpaper_id)
+ papers = self._get_answerpapers_for_quiz(questionpaper_id)
users = self._get_answerpapers_users(papers)
latest_attempts = []
for user in users:
diff --git a/yaksh/templates/yaksh/ajax_question_filter.html b/yaksh/templates/yaksh/ajax_question_filter.html
index 11bf660..a63354c 100644
--- a/yaksh/templates/yaksh/ajax_question_filter.html
+++ b/yaksh/templates/yaksh/ajax_question_filter.html
@@ -7,7 +7,8 @@
{% for question in questions %}
<li>
<label>
- <input type="checkbox" name="question" data-qid="{{question.id}}">&nbsp;&nbsp;<a href="{{URL_ROOT}}/exam/manage/addquestion/{{ question.id }}">{{ question }}</a><br>
+ <input type="checkbox" name="question" data-qid="{{question.id}}" value=
+ "{{question.id}}">&nbsp;&nbsp;<a href="{{URL_ROOT}}/exam/manage/addquestion/{{ question.id }}">{{ question }}</a><br>
</label>
</li>
{% endfor %}
diff --git a/yaksh/templates/yaksh/showquestions.html b/yaksh/templates/yaksh/showquestions.html
index ca51d1a..ea42797 100644
--- a/yaksh/templates/yaksh/showquestions.html
+++ b/yaksh/templates/yaksh/showquestions.html
@@ -10,6 +10,19 @@
{% endblock %}
{% block manage %}
+
+<h4>Upload json file for adding questions</h4>
+<form action="" method="post" enctype="multipart/form-data">
+{% csrf_token %}
+{{ upload_form.as_p }}
+<button class="btn" type="submit" name="upload" value="upload">Upload File</button>
+</form>
+{% if message %}
+<h4>{{ message }}</h4>
+{% endif %}
+{% if msg %}
+<h4>{{ msg }}</h4>
+{% endif %}
<form name=frm action="" method="post">
{% csrf_token %}
<div class="row" id="selectors">
@@ -31,13 +44,20 @@
</div>
</div>
<br>
+
<div id="filtered-questions">
+{% if questions %}
+<h5 class="highlight"><input id="checkall" class="ignore" type="checkbox"> Select All </h5>
{% for i in questions %}
<input type="checkbox" name="question" value="{{ i.id }}">&nbsp;&nbsp;<a href="{{URL_ROOT}}/exam/manage/addquestion/{{ i.id }}">{{ i }}</a><br>
{% endfor %}
+{% endif %}
</div>
<br>
<button class="btn" type="button" onclick='location.replace("{{URL_ROOT}}/exam/manage/addquestion/");'>Add Question</button>&nbsp;&nbsp;
-<button class="btn" type="submit" onClick="return confirm_delete(frm);" name='delete' value='delete'>Delete Selected</button>
+<button class="btn" type="submit" onClick="return confirm_delete(frm);" name='delete' value='delete'>Delete Selected</button>&nbsp;&nbsp;
+{% if questions %}
+<button class="btn" type="submit" name='download' value='download'>Download Selected</button>
+{% endif %}
</form>
{% endblock %}
diff --git a/yaksh/tests.py b/yaksh/tests.py
index d3ff4fc..58b8518 100644
--- a/yaksh/tests.py
+++ b/yaksh/tests.py
@@ -27,7 +27,7 @@ def setUpModule():
# create 20 questions
for i in range(1, 21):
- Question.objects.create(summary='Q%d' % (i), points=1, type='code')
+ Question.objects.create(summary='Q%d' % (i), points=1, type='code', user=user)
# create a quiz
quiz = Quiz.objects.create(start_date_time=datetime(2015, 10, 9, 10, 8, 15, 0),
@@ -72,13 +72,22 @@ class ProfileTestCases(unittest.TestCase):
class QuestionTestCases(unittest.TestCase):
def setUp(self):
# Single question details
- self.question = Question(summary='Demo question', language='Python',
+ self.user1 = User.objects.get(pk=1)
+ self.user2 = User.objects.get(pk=2)
+ self.question1 = Question(summary='Demo question', language='Python',
type='Code', active=True,
description='Write a function', points=1.0,
- snippet='def myfunc()')
- self.question.save()
- self.question.tags.add('python', 'function')
- self.testcase = TestCase(question=self.question,
+ snippet='def myfunc()', user=self.user1)
+ self.question1.save()
+
+ self.question2 = Question(summary='Demo Json', language='python',
+ type='code', active=True,
+ description='factorial of a no', points=2.0,
+ snippet='def fact()', user=self.user2)
+ self.question2.save()
+
+ self.question1.tags.add('python', 'function')
+ self.testcase = TestCase(question=self.question1,
func_name='def myfunc', kw_args='a=10,b=11',
pos_args='12,13', expected_answer='15')
answer_data = { "test": "",
@@ -90,41 +99,73 @@ class QuestionTestCases(unittest.TestCase):
"kw_args": {"a": "10",
"b": "11"}
}],
- "id": self.question.id,
+ "id": self.question1.id,
"ref_code_path": "",
}
self.answer_data_json = json.dumps(answer_data)
self.user_answer = "demo_answer"
+ questions_data = [{"snippet": "def fact()", "active": True, "points": 1.0,
+ "ref_code_path": "", "description": "factorial of a no",
+ "language": "Python", "test": "", "type": "Code",
+ "options": "", "summary": "Json Demo"}]
+ self.json_questions_data = json.dumps(questions_data)
def test_question(self):
""" Test question """
- self.assertEqual(self.question.summary, 'Demo question')
- self.assertEqual(self.question.language, 'Python')
- self.assertEqual(self.question.type, 'Code')
- self.assertFalse(self.question.options)
- self.assertEqual(self.question.description, 'Write a function')
- self.assertEqual(self.question.points, 1.0)
- self.assertTrue(self.question.active)
- self.assertEqual(self.question.snippet, 'def myfunc()')
+ self.assertEqual(self.question1.summary, 'Demo question')
+ self.assertEqual(self.question1.language, 'Python')
+ self.assertEqual(self.question1.type, 'Code')
+ self.assertFalse(self.question1.options)
+ self.assertEqual(self.question1.description, 'Write a function')
+ self.assertEqual(self.question1.points, 1.0)
+ self.assertTrue(self.question1.active)
+ self.assertEqual(self.question1.snippet, 'def myfunc()')
tag_list = []
- for tag in self.question.tags.all():
+ for tag in self.question1.tags.all():
tag_list.append(tag.name)
self.assertEqual(tag_list, ['python', 'function'])
def test_consolidate_answer_data(self):
""" Test consolidate_answer_data function """
- result = self.question.consolidate_answer_data([self.testcase],
+ result = self.question1.consolidate_answer_data([self.testcase],
self.user_answer)
self.assertEqual(result, self.answer_data_json)
+ def test_dump_questions_into_json(self):
+ """ Test dump questions into json """
+ question = Question()
+ question_id = ['24']
+ questions = json.loads(question.dump_into_json(question_id, self.user1))
+ for q in questions:
+ self.assertEqual(self.question2.summary, q['summary'])
+ self.assertEqual(self.question2.language, q['language'])
+ self.assertEqual(self.question2.type, q['type'])
+ self.assertEqual(self.question2.description, q['description'])
+ self.assertEqual(self.question2.points, q['points'])
+ self.assertTrue(self.question2.active)
+ self.assertEqual(self.question2.snippet, q['snippet'])
+
+ def test_load_questions_from_json(self):
+ """ Test load questions into database from json """
+ question = Question()
+ result = question.load_from_json(self.json_questions_data, self.user1)
+ question_data = Question.objects.get(pk=27)
+ self.assertEqual(question_data.summary, 'Json Demo')
+ self.assertEqual(question_data.language, 'Python')
+ self.assertEqual(question_data.type, 'Code')
+ self.assertEqual(question_data.description, 'factorial of a no')
+ self.assertEqual(question_data.points, 1.0)
+ self.assertTrue(question_data.active)
+ self.assertEqual(question_data.snippet, 'def fact()')
###############################################################################
class TestCaseTestCases(unittest.TestCase):
def setUp(self):
+ self.user = User.objects.get(pk=1)
self.question = Question(summary='Demo question', language='Python',
type='Code', active=True,
description='Write a function', points=1.0,
- snippet='def myfunc()')
+ snippet='def myfunc()', user=self.user)
self.question.save()
self.testcase = TestCase(question=self.question,
func_name='def myfunc', kw_args='a=10,b=11',
diff --git a/yaksh/urls.py b/yaksh/urls.py
index b32bc36..18a64c2 100644
--- a/yaksh/urls.py
+++ b/yaksh/urls.py
@@ -88,5 +88,9 @@ urlpatterns += [
url(r'^manage/searchteacher/(?P<course_id>\d+)/$', views.search_teacher),
url(r'^manage/addteacher/(?P<course_id>\d+)/$', views.add_teacher),
url(r'^manage/allotted_course/$', views.allotted_courses),
- url(r'^manage/remove_teachers/(?P<course_id>\d+)/$', views.remove_teachers)
+ url(r'^manage/remove_teachers/(?P<course_id>\d+)/$', views.remove_teachers),
+ url(r'^manage/download_questions/$', views.show_all_questions),
+ url(r'^manage/upload_questions/$', views.show_all_questions)
]
+
+
diff --git a/yaksh/views.py b/yaksh/views.py
index a91da29..a986d4c 100644
--- a/yaksh/views.py
+++ b/yaksh/views.py
@@ -23,7 +23,7 @@ from yaksh.models import Quiz, Question, QuestionPaper, QuestionSet, Course
from yaksh.models import Profile, Answer, AnswerPaper, User, TestCase
from yaksh.forms import UserRegisterForm, UserLoginForm, QuizForm,\
QuestionForm, RandomQuestionForm, TestCaseFormSet,\
- QuestionFilterForm, CourseForm, ProfileForm
+ QuestionFilterForm, CourseForm, ProfileForm, UploadFileForm
from yaksh.xmlrpc_clients import code_server
from settings import URL_ROOT
from yaksh.models import AssignmentUpload
@@ -166,6 +166,8 @@ def add_question(request, question_id=None):
test_case_formset = add_or_delete_test_form(request.POST, form.save(commit=False))
if 'save_question' in request.POST:
qtn = form.save(commit=False)
+ qtn.user = user
+ qtn.save()
test_case_formset = TestCaseFormSet(request.POST, prefix='test', instance=qtn)
form.save()
question = Question.objects.order_by("-id")[0]
@@ -780,7 +782,8 @@ def show_all_users(request):
def ajax_questions_filter(request):
"""Ajax call made when filtering displayed questions."""
- filter_dict = {}
+ user = request.user
+ filter_dict = {"user_id": user.id}
question_type = request.POST.get('question_type')
marks = request.POST.get('marks')
language = request.POST.get('language')
@@ -806,21 +809,49 @@ def show_all_questions(request):
user = request.user
ci = RequestContext(request)
- if not user.is_authenticated() or not is_moderator(user):
+ context = {}
+ if not is_moderator(user):
raise Http404("You are not allowed to view this page !")
- if request.method == 'POST' and request.POST.get('delete') == 'delete':
- data = request.POST.getlist('question')
- if data is not None:
- for i in data:
- question = Question.objects.get(id=i).delete()
- questions = Question.objects.all()
- form = QuestionFilterForm()
- context = {'papers': [],
- 'question': None,
- 'questions': questions,
- 'form': form
- }
+ if request.method == 'POST':
+ if request.POST.get('delete') == 'delete':
+ data = request.POST.getlist('question')
+ if data is not None:
+ question = Question.objects.filter(id__in=data, user_id=user.id).delete()
+
+ if request.POST.get('upload') == 'upload':
+ form = UploadFileForm(request.POST, request.FILES)
+ if form.is_valid():
+ questions_file = request.FILES['file']
+ if questions_file.name.split('.')[-1] == "json":
+ questions_list = questions_file.read()
+ question = Question()
+ question.load_from_json(questions_list, user)
+ else:
+ message = "Please Upload a JSON file"
+ context['message'] = message
+
+ if request.POST.get('download') == 'download':
+ question_ids = request.POST.getlist('question')
+ if question_ids:
+ question = Question()
+ questions = question.dump_into_json(question_ids, user)
+ response = HttpResponse(questions, content_type='text/json')
+ response['Content-Disposition'] = 'attachment; filename=\
+ "{0}_questions.json"'.format(user)
+ return response
+ else:
+ msg = "Please select atleast one question"
+ context['msg'] = msg
+
+ questions = Question.objects.filter(user_id=user.id)
+ form = QuestionFilterForm(user=user)
+ upload_form = UploadFileForm()
+ context['papers'] = []
+ context['question'] = None
+ context['questions'] = questions
+ context['form'] = form
+ context['upload_form'] = upload_form
return my_render_to_response('yaksh/showquestions.html', context,
context_instance=ci)
@@ -944,9 +975,11 @@ def ajax_questionpaper(request, query):
"""
During question paper creation, ajax call made to get question details.
"""
+
+ user = request.user
if query == 'marks':
question_type = request.POST.get('question_type')
- questions = Question.objects.filter(type=question_type)
+ questions = Question.objects.filter(type=question_type, user=user)
marks = questions.values_list('points').distinct()
return my_render_to_response('yaksh/ajax_marks.html', {'marks': marks})
elif query == 'questions':
@@ -958,7 +991,7 @@ def ajax_questionpaper(request, query):
random_question_list = ",".join(random_questions).split(',')
question_list = fixed_question_list + random_question_list
questions = list(Question.objects.filter(type=question_type,
- points=marks_selected))
+ points=marks_selected, user=user))
questions = [question for question in questions \
if not str(question.id) in question_list]
return my_render_to_response('yaksh/ajax_questions.html',