summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorprathamesh2017-08-14 12:10:42 +0530
committerprathamesh2017-08-14 12:10:42 +0530
commitce995e06e3509a1340061c51dfa08a65c69eef66 (patch)
treed270ccf9792bd2dbbc833e2f08aee4b407356cb9
parent1a6006b457a68e6db51315a83a97ec0d9eb631d4 (diff)
downloadonline_test-ce995e06e3509a1340061c51dfa08a65c69eef66.tar.gz
online_test-ce995e06e3509a1340061c51dfa08a65c69eef66.tar.bz2
online_test-ce995e06e3509a1340061c51dfa08a65c69eef66.zip
Front-end modification for improved code server
Added JQuery to handle request. Sends ajax request and gets json as response. json contains token i.e uid which is answer id. Using uid, an ajax request is sent after every 2 secs till the server gives the desire result. If the code result has error then html is written on the document. If the result has correct answer then next question is displayed. *includes function for string will not work for older browers. Will substitute with a different function in next commit.
-rwxr-xr-x[-rw-r--r--]yaksh/code_server.py2
-rw-r--r--yaksh/models.py11
-rw-r--r--yaksh/static/yaksh/js/question.js12
-rw-r--r--yaksh/static/yaksh/js/requesthandler.js90
-rw-r--r--yaksh/templates/yaksh/question.html51
-rw-r--r--yaksh/urls.py1
-rw-r--r--yaksh/views.py79
7 files changed, 155 insertions, 91 deletions
diff --git a/yaksh/code_server.py b/yaksh/code_server.py
index 7bacc7f..d74d35b 100644..100755
--- a/yaksh/code_server.py
+++ b/yaksh/code_server.py
@@ -208,7 +208,7 @@ def get_result(url, uid, block=False):
'''
def _get_data():
r = requests.get(urllib.parse.urljoin(url, str(uid)))
- return json.loads(r.content)
+ return json.loads(r.content.decode('utf-8'))
data = _get_data()
if block:
while data.get('status') != 'done':
diff --git a/yaksh/models.py b/yaksh/models.py
index 87e6260..9b3cabe 100644
--- a/yaksh/models.py
+++ b/yaksh/models.py
@@ -24,7 +24,7 @@ import zipfile
import tempfile
from textwrap import dedent
from .file_utils import extract_files, delete_files
-from yaksh.xmlrpc_clients import code_server
+from yaksh.code_server import submit, SERVER_POOL_PORT
from django.conf import settings
@@ -1266,7 +1266,7 @@ class AnswerPaper(models.Model):
if question.type == 'code':
return self.answers.filter(question=question).order_by('-id')
- def validate_answer(self, user_answer, question, json_data=None):
+ def validate_answer(self, user_answer, question, json_data=None, uid=None):
"""
Checks whether the answer submitted by the user is right or wrong.
If right then returns correct = True, success and
@@ -1327,10 +1327,9 @@ class AnswerPaper(models.Model):
elif question.type == 'code' or question.type == "upload":
user_dir = self.user.profile.get_user_dir()
- json_result = code_server.run_code(
- question.language, json_data, user_dir
- )
- result = json.loads(json_result)
+ url = 'http://localhost:%s' % SERVER_POOL_PORT
+ submit(url, uid, json_data, user_dir)
+ result = {'uid': uid, 'state': 'running'}
return result
def regrade(self, question_id):
diff --git a/yaksh/static/yaksh/js/question.js b/yaksh/static/yaksh/js/question.js
deleted file mode 100644
index 96ff3de..0000000
--- a/yaksh/static/yaksh/js/question.js
+++ /dev/null
@@ -1,12 +0,0 @@
-function submitCode()
-{
- document.forms["code"].submit();
- var x = document.getElementById("status");
- x.innerHTML = "<strong>Checking answer ...</strong>";
- x = document.getElementById("check");
- x.disabled = true;
- x.value = "Checking Answer ...";
- if (document.getElementById("skip")!=null) {
- document.getElementById("skip").disabled = true;
- }
-}
diff --git a/yaksh/static/yaksh/js/requesthandler.js b/yaksh/static/yaksh/js/requesthandler.js
new file mode 100644
index 0000000..9d023cc
--- /dev/null
+++ b/yaksh/static/yaksh/js/requesthandler.js
@@ -0,0 +1,90 @@
+request_status = "initial"
+function submitRequest(){
+ document.forms["code"].submit();
+}
+
+function check_state(state, uid, success) {
+ if (state == "running") {
+ setTimeout(get_result(uid), 2000);
+ }
+}
+
+function get_result(uid){
+ $.ajax({
+ method: "GET",
+ url: "/exam/get_results/"+uid+"/",
+ dataType: "html", // Your server can response html, json, xml format.
+ success: function(data, status, xhr) {
+ content_type = xhr.getResponseHeader("content-type");
+ if(content_type.includes("text/html")) {
+ request_status = "initial";
+ document.open();
+ document.write(data);
+ document.close();
+ } else if(content_type.includes("application/json")) {
+ res = JSON.parse(data);
+ request_status = res.status;
+ check_state(request_status, uid, res.success);
+ }
+ }
+ });
+}
+
+var global_editor = {};
+$(document).ready(function(){
+ // Codemirror object, language modes and initial content
+ // Get the textarea node
+ var textarea_node = document.querySelector('#answer');
+
+ var mode_dict = {
+ 'python': 'python',
+ 'c': 'text/x-csrc',
+ 'cpp': 'text/x-c++src',
+ 'java': 'text/x-java',
+ 'bash': 'text/x-sh',
+ 'scilab': 'text/x-csrc'
+ }
+
+ // Code mirror Options
+ var options = {
+ mode: mode_dict[lang],
+ gutter: true,
+ lineNumbers: true,
+ onChange: function (instance, changes) {
+ render();
+ }
+ };
+
+ // Initialize the codemirror editor
+ global_editor.editor = CodeMirror.fromTextArea(textarea_node, options);
+
+ // Setting code editors initial content
+ global_editor.editor.setValue(init_val);
+
+ function reset_editor() {
+ global_editor.editor.setValue(init_val);
+ global_editor.editor.clearHistory();
+ }
+ $('#code').submit(function(e) {
+ $.ajax({
+ type: 'POST',
+ url: $(this).attr("action"),
+ data: $(this).serializeArray(),
+ dataType: "html", // Your server can response html, json, xml format.
+ success: function(data, status, xhr) {
+ content_type = xhr.getResponseHeader("content-type");
+ if(content_type.includes("text/html")) {
+ document.open();
+ document.write(data);
+ document.close();
+ } else if(content_type.includes("application/json")) {
+ res = JSON.parse(data);
+ var uid = res.uid;
+ request_status = res.state;
+ check_state(request_status, uid, false);
+ }
+ }
+ });
+ e.preventDefault(); // To stop the default form submission.
+ });
+});
diff --git a/yaksh/templates/yaksh/question.html b/yaksh/templates/yaksh/question.html
index ee33523..9df2fef 100644
--- a/yaksh/templates/yaksh/question.html
+++ b/yaksh/templates/yaksh/question.html
@@ -15,7 +15,7 @@
{% endblock %}
{% block script %}
-<script src="{{ URL_ROOT }}/static/yaksh/js/question.js"></script>
+<script src="{{ URL_ROOT }}/static/yaksh/js/requesthandler.js"></script>
<script src="{{ URL_ROOT }}/static/yaksh/js/codemirror/lib/codemirror.js"></script>
<script src="{{ URL_ROOT }}/static/yaksh/js/codemirror/mode/python/python.js"></script>
<script src="{{ URL_ROOT }}/static/yaksh/js/codemirror/mode/clike/clike.js"></script>
@@ -79,7 +79,7 @@ function validate(){
}
else
{
- return true;
+ send_request();
}
}
@@ -89,47 +89,8 @@ function call_skip(url)
form.action = url
form.submit();
}
-</script>
-<script>
-
- var init_val = '{{ last_attempt|escape_quotes|safe }}';
- var global_editor = {};
- $(document).ready(function(){
- // Codemirror object, language modes and initial content
- // Get the textarea node
- var textarea_node = document.querySelector('#answer');
-
- var lang = "{{ question.language }}"
- var mode_dict = {
- 'python': 'python',
- 'c': 'text/x-csrc',
- 'cpp': 'text/x-c++src',
- 'java': 'text/x-java',
- 'bash': 'text/x-sh',
- 'scilab': 'text/x-csrc'
- }
-
- // Code mirror Options
- var options = {
- mode: mode_dict[lang],
- gutter: true,
- lineNumbers: true,
- onChange: function (instance, changes) {
- render();
- }
- };
-
- // Initialize the codemirror editor
- global_editor.editor = CodeMirror.fromTextArea(textarea_node, options);
-
- // Setting code editors initial content
- global_editor.editor.setValue(init_val);
-
- function reset_editor() {
- global_editor.editor.setValue(init_val);
- global_editor.editor.clearHistory();
- }
- });
+init_val = '{{ last_attempt|escape_quotes|safe }}';
+lang = "{{ question.language }}"
</script>
{% endblock script %}
@@ -239,13 +200,13 @@ function call_skip(url)
<div class="from-group">
{% if question.type == "mcq" or "mcc" or "integer" or "float" or "string" %}
- <br><button class="btn btn-primary" type="submit" name="check" id="check">Submit Answer</button>&nbsp;&nbsp;<br/>
+ <br><button class="btn btn-primary" type="submit" name="check" id="check" >Submit Answer</button>&nbsp;&nbsp;<br/>
{% elif question.type == "upload" %}
<br><button class="btn btn-primary" type="submit" name="check" id="check" onClick="return validate();">Upload</button>&nbsp;&nbsp;
{% else %}
{% if question in paper.get_questions_unanswered %}
- <button class="btn btn-primary" type="submit" name="check" id="check" onClick="submitCode();">Check Answer <span class="glyphicon glyphicon-cog"></span></button>&nbsp;&nbsp;
+ <button class="btn btn-primary" type="submit" name="check" id="check" >Check Answer <span class="glyphicon glyphicon-cog"></span></button>&nbsp;&nbsp;
{% endif %}
{% endif %}
diff --git a/yaksh/urls.py b/yaksh/urls.py
index 5270068..6daaf46 100644
--- a/yaksh/urls.py
+++ b/yaksh/urls.py
@@ -20,6 +20,7 @@ urlpatterns = [
views.complete),
url(r'^register/$', views.user_register, name="register"),
url(r'^(?P<q_id>\d+)/check/$', views.check),
+ url(r'^get_results/(?P<uid>\d+)/$', views.get_results),
url(r'^(?P<q_id>\d+)/check/(?P<attempt_num>\d+)/(?P<questionpaper_id>\d+)/$',\
views.check),
url(r'^(?P<q_id>\d+)/skip/(?P<attempt_num>\d+)/(?P<questionpaper_id>\d+)/$',
diff --git a/yaksh/views.py b/yaksh/views.py
index c10ba6a..f6243a7 100644
--- a/yaksh/views.py
+++ b/yaksh/views.py
@@ -4,7 +4,7 @@ import os
from datetime import datetime, timedelta
import collections
import csv
-from django.http import HttpResponse
+from django.http import HttpResponse, JsonResponse
from django.core.urlresolvers import reverse
from django.contrib.auth import login, logout, authenticate
from django.shortcuts import render_to_response, get_object_or_404, redirect
@@ -30,6 +30,7 @@ try:
except ImportError:
from io import BytesIO as string_io
# Local imports.
+from yaksh.code_server import get_result, SERVER_POOL_PORT
from yaksh.models import get_model_class, Quiz, Question, QuestionPaper, QuestionSet, Course
from yaksh.models import Profile, Answer, AnswerPaper, User, TestCase, FileUpload,\
has_profile, StandardTestCase, McqTestCase,\
@@ -539,6 +540,7 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None):
new_answer = Answer(question=current_question, answer=user_answer,
correct=False, error=json.dumps([]))
new_answer.save()
+ uid = new_answer.id
paper.answers.add(new_answer)
# If we were not skipped, we were asked to check. For any non-mcq
# questions, we obtain the results via XML-RPC with the code executed
@@ -547,38 +549,61 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None):
if current_question.type == 'code' or \
current_question.type == 'upload' else None
result = paper.validate_answer(user_answer, current_question,
- json_data
+ json_data, uid
)
- if result.get('success'):
- new_answer.marks = (current_question.points * result['weight'] /
- current_question.get_maximum_test_case_weight()) \
- if current_question.partial_grading and \
- current_question.type == 'code' or current_question.type == 'upload' \
- else current_question.points
- new_answer.correct = result.get('success')
- error_message = None
- new_answer.error = json.dumps(result.get('error'))
- next_question = paper.add_completed_question(current_question.id)
+ if current_question.type in ['code', 'upload']:
+ return JsonResponse(result)
else:
- new_answer.marks = (current_question.points * result['weight'] /
- current_question.get_maximum_test_case_weight()) \
- if current_question.partial_grading and \
- current_question.type == 'code' or current_question.type == 'upload' \
- else 0
- error_message = result.get('error') if current_question.type == 'code' \
- or current_question.type == 'upload' else None
- new_answer.error = json.dumps(result.get('error'))
- next_question = current_question if current_question.type == 'code' \
- or current_question.type == 'upload' \
- else paper.add_completed_question(current_question.id)
- new_answer.save()
- paper.update_marks('inprogress')
- paper.set_end_time(timezone.now())
- return show_question(request, next_question, paper, error_message)
+ next_question, error_message, paper = _update_paper(request, uid, result)
+ return show_question(request, next_question, paper, error_message)
else:
return show_question(request, current_question, paper)
+@csrf_exempt
+def get_results(request, uid):
+ url = 'http://localhost:%s' % SERVER_POOL_PORT
+ result_state = get_result(url, uid)
+ result = json.loads(result_state.get('result'))
+ next_question, error_message, paper = _update_paper(request, uid, result)
+ result['status'] = result_state.get('status')
+ if result['status']== 'done':
+ return show_question(request, next_question, paper, error_message)
+ return JsonResponse(result)
+
+
+def _update_paper(request, uid, result):
+ new_answer = Answer.objects.get(id=uid)
+ current_question = new_answer.question
+ paper = new_answer.answerpaper_set.first()
+
+ if result.get('success'):
+ new_answer.marks = (current_question.points * result['weight'] /
+ current_question.get_maximum_test_case_weight()) \
+ if current_question.partial_grading and \
+ current_question.type == 'code' or current_question.type == 'upload' \
+ else current_question.points
+ new_answer.correct = result.get('success')
+ error_message = None
+ new_answer.error = json.dumps(result.get('error'))
+ next_question = paper.add_completed_question(current_question.id)
+ else:
+ new_answer.marks = (current_question.points * result['weight'] /
+ current_question.get_maximum_test_case_weight()) \
+ if current_question.partial_grading and \
+ current_question.type == 'code' or current_question.type == 'upload' \
+ else 0
+ error_message = result.get('error') if current_question.type == 'code' \
+ or current_question.type == 'upload' else None
+ new_answer.error = json.dumps(result.get('error'))
+ next_question = current_question if current_question.type == 'code' \
+ or current_question.type == 'upload' \
+ else paper.add_completed_question(current_question.id)
+ new_answer.save()
+ paper.update_marks('inprogress')
+ paper.set_end_time(timezone.now())
+ return next_question, error_message, paper
+
def quit(request, reason=None, attempt_num=None, questionpaper_id=None):
"""Show the quit page when the user logs out."""