summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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."""