diff --git a/oer/exercise-formats/choice/multiple/script.js b/oer/exercise-formats/choice/multiple/script.js index 8ac0444..f85116f 100755 --- a/oer/exercise-formats/choice/multiple/script.js +++ b/oer/exercise-formats/choice/multiple/script.js @@ -61,7 +61,7 @@ $(document).ready(function () { submission = {"solution": sol, "slide": window.data.slide, "action": "quiz"}; submission_json = JSON.stringify(submission); - console.log(submission_json) + //console.log(submission_json) $.ajax({ method: "POST", @@ -72,45 +72,16 @@ $(document).ready(function () { .done(function( msg ) { console.log("Job submitted: " + msg ); console.log(msg); - - job_id = msg['id']; - - // really timeout? - // how about handling this directly? - setTimeout(function(){ job.status(action, job_id); }, 1000); - - }); - }; - - job.status = function (type, job_id) { - - console.log(type); - - e = {"blub": "hm"}; - json_data = JSON.stringify(e); - - $.ajax({ - method: "GET", - url: "/api/rest/job/" + job_id + "/", - contentType: 'application/json', - }) - .done(function( msg ) { - console.log("Status received: " + msg ); - console.log(msg); - if ( msg.status == 'SUCCESS' ) { response.show(type, msg, msg.data.output); } else { response.show(type, "processing...", false); setTimeout(function(){ job.status(type, job_id); }, 3000); } - - }); - }; - $("#submit-grade").click(function(event) { + $("#submit-grade").click(function(event) { $("#submit-grade").prop( "disabled", true); job.submit("grade"); }); @@ -123,11 +94,11 @@ $(document).ready(function () { $("#exercise-choices a.list-group-item").click(function(event) { event.preventDefault() //$("#submit-test").prop( "disabled", true); - //job.submit("test"); + //job.submit("test"); + - target = event.target - + if ( $(target).is('input') ) { target = $(event.target).parent()[0] @@ -135,7 +106,7 @@ $(document).ready(function () { // also check/uncheck when clicking surounding } - + //if ( $(target).children("input").attr('type') == 'radio' ) { // $(target).parent().children(".list-group-item-success").removeClass("list-group-item-success"); //} @@ -144,9 +115,8 @@ $(document).ready(function () { $(target).children("input").each(function () { this.checked = !this.checked; console.log(this) }); //$(target).toggleClass("list-group-item-userchoice"); - + }); }); - diff --git a/oer/exercise-formats/program/match-regex-parallel/controller.py b/oer/exercise-formats/program/match-regex-parallel/controller.py index 5bb5f40..c26a89b 100644 --- a/oer/exercise-formats/program/match-regex-parallel/controller.py +++ b/oer/exercise-formats/program/match-regex-parallel/controller.py @@ -21,7 +21,7 @@ def build(ctx): # start subprocess in with work_path as cwd p = subprocess.Popen(allArgs, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=ctx.work_path) msgs,errs = p.communicate() - retval = p.wait() + retval = p.wait() errs = errs.decode("utf-8") msgs = msgs.decode("utf-8") @@ -41,25 +41,23 @@ def execute(ctx): p = subprocess.Popen(allArgs, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=ctx.work_path) msgs,errs = p.communicate() - retval = p.wait() + retval = p.wait() errs = errs.decode("utf-8") msgs = msgs.decode("utf-8") - + ctx.execute_result = (retval, errs, msgs) + #ctx.celery_task.update_state(state='SUBMITTED TO SLURM', meta=response(ctx)) - - ctx.celery_task.update_state(state='SUBMITTED TO SLURM', meta=response(ctx)) - - print("parallel execute(), before sleep", file=sys.stderr) - time.sleep(20) - print("parallel execute(), after sleep", file=sys.stderr) + #print("parallel execute(), before sleep", file=sys.stderr) + #time.sleep(20) + #print("parallel execute(), after sleep", file=sys.stderr) retval = ctx.get_file_content('job.exit') errs = ctx.get_file_content('job.err') msgs = ctx.get_file_content('job.out') - + print( (retval, errs, msgs), file=sys.stderr) return retval, errs, msgs @@ -84,10 +82,10 @@ def grade(ctx): else: return 'FAIL' - + def response(ctx): - + output = "" if ctx.build_result[0] != 0: output = ctx.build_result[1] diff --git a/oer/exercise-formats/program/match-regex/controller.py b/oer/exercise-formats/program/match-regex/controller.py index 81c6cb2..280a388 100755 --- a/oer/exercise-formats/program/match-regex/controller.py +++ b/oer/exercise-formats/program/match-regex/controller.py @@ -10,6 +10,7 @@ import sys import subprocess import re +import time def build(ctx): @@ -36,6 +37,16 @@ def execute(ctx): allArgs = [ctx.programfile] p = subprocess.Popen(allArgs, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=ctx.work_path) + timeout = 1 + poll_period = 0.1 + p.poll() + while p.returncode is None and timeout > 0: + time.sleep(poll_period) + timeout -= poll_period + p.poll() + if timeout <= 0: + p.kill() # timed out + msgs,errs = p.communicate() retval = p.wait() diff --git a/oer/exercise-formats/program/match-regex/script.js b/oer/exercise-formats/program/match-regex/script.js index 208f30e..b5449b1 100755 --- a/oer/exercise-formats/program/match-regex/script.js +++ b/oer/exercise-formats/program/match-regex/script.js @@ -3,7 +3,7 @@ $(document).ready(function () { response = {}; response.show = function (type, msg, output) { - console.log("show issued" + type + msg); + //console.log("show issued" + type + msg); html = ""; @@ -22,17 +22,17 @@ $(document).ready(function () { } } - + console.log(output) if ( output == "" ) { output = " " } if ( output != false) { - console.log("output is not false") + //console.log("output is not false") $("#output-wrapper").show(500); $("#output").html(output); - } + } $("#response").hide().html(html).show(500); @@ -46,13 +46,13 @@ $(document).ready(function () { job = {} job.submit = function (action) { - console.log("Test submission issued.."); - console.log( $("#c-code").val() ); + //console.log("Test submission issued.."); + //console.log( $("#c-code").val() ); submission = {"solution": cEditor.getValue(), "cmd": "run.sh", "action": action, "slide": window.data.slide}; submission_json = JSON.stringify(submission); - console.log(submission_json) + //console.log(submission_json) $.ajax({ method: "POST", @@ -61,18 +61,17 @@ $(document).ready(function () { data: submission_json }) .done(function( msg ) { - console.log("Job submitted: " + msg ); - console.log(msg); + //console.log("Job submitted: " + msg ); + //console.log(msg); job_id = msg['id']; - setTimeout(function(){ job.status(action, job_id); }, 1000); + setTimeout(function(){ job.status(action, job_id); }, 100); - }); + }); }; job.status = function (type, job_id) { - - console.log(type) + //console.log(type) e = {"blub": "hm"}; json_data = JSON.stringify(e); @@ -90,7 +89,7 @@ $(document).ready(function () { response.show(type, msg, msg.data.output); } else { response.show(type, "processing...", false); - setTimeout(function(){ job.status(type, job_id); }, 3000); + setTimeout(function(){ job.status(type, job_id); }, 1000); } }); @@ -100,10 +99,10 @@ $(document).ready(function () { $("#submit-test").click(function(event) { $("#submit-test").prop( "disabled", true); - job.submit("test"); + job.submit("test"); }); - $("#submit-grade").click(function(event) { + $("#submit-grade").click(function(event) { $("#submit-grade").prop( "disabled", true); job.submit("grade"); }); @@ -112,11 +111,11 @@ $(document).ready(function () { $("#exercise-choices a.list-group-item").click(function(event) { event.preventDefault() //$("#submit-test").prop( "disabled", true); - //job.submit("test"); + //job.submit("test"); + - target = event.target - + if ( $(target).is('input') ) { target = $(event.target).parent()[0] @@ -135,4 +134,3 @@ $(document).ready(function () { }); }); - diff --git a/oer/exercise-formats/program/scriptgrade/controller.py b/oer/exercise-formats/program/scriptgrade/controller.py index 6e69a06..bb49c8e 100644 --- a/oer/exercise-formats/program/scriptgrade/controller.py +++ b/oer/exercise-formats/program/scriptgrade/controller.py @@ -9,6 +9,7 @@ import sys import subprocess import re +import time def build(ctx): # Add filenames @@ -18,7 +19,7 @@ def build(ctx): # start subprocess in with work_path as cwd p = subprocess.Popen(allArgs, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=ctx.work_path) msgs,errs = p.communicate() - retval = p.wait() + retval = p.wait() errs = errs.decode("utf-8") msgs = msgs.decode("utf-8") @@ -32,6 +33,16 @@ def execute(ctx): # start subprocess in with work_path as cwd p = subprocess.Popen(allArgs, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=ctx.work_path) + timeout = 1 + poll_period = 0.1 + p.poll() + while p.returncode is None and timeout > 0: + time.sleep(poll_period) + timeout -= poll_period + p.poll() + if timeout <= 0: + p.kill() # timed out + msgs,errs = p.communicate() retval = p.wait() @@ -42,7 +53,7 @@ def execute(ctx): def grade(ctx): - print("GRADING!!", file=sys.stderr) + #print("GRADING!!", file=sys.stderr) # if build failed, return early and set grade to FAIL if ctx.build_result[0] != 0: @@ -55,12 +66,22 @@ def grade(ctx): # start subprocess in with work_path as cwd p = subprocess.Popen(allArgs, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=ctx.work_path) + timeout = 1 + poll_period = 0.1 + p.poll() + while p.returncode is None and timeout > 0: + time.sleep(poll_period) + timeout -= poll_period + p.poll() + if timeout <= 0: + p.kill() # timed out + msgs,errs = p.communicate() - retval = p.wait() + retval = p.wait() errs = errs.decode("utf-8") msgs = msgs.decode("utf-8") - + ctx.execute_result = (retval, errs, msgs) @@ -89,4 +110,3 @@ def response(ctx): grade = ctx.grade_result msg = "" return {'output': output, 'grade': grade, 'msg': msg, 'data': None} - diff --git a/src/frontend/templates/frontend/attribution.html b/src/frontend/templates/frontend/attribution.html index 73f5b6f..0f0df22 100644 --- a/src/frontend/templates/frontend/attribution.html +++ b/src/frontend/templates/frontend/attribution.html @@ -1,73 +1,6 @@ {% load staticfiles %} -{% load cookielaw_tags %} - - - - - - - - - - - - - Teaching - Scientific Computing @ UHH - - - - - - - - - - - - - - - - - - - {% cookielaw_banner %} - - - {% include "frontend/navbar.html" %} - -
-
-
 
-
- - - - - - -
- +{% include "frontend/header.html" %}
- - - - - -
- -

Attribution

In order to ensure a distraction free learning expierence references to work by third parties was ommited where possible. @@ -85,83 +18,6 @@ Please see the project details here.

- - - - - -

Images and Artworks

- -

The colorful header on top of the e.g. the entry page uses artworks created by multiple artists from the Noun Project:

- - - - - -

Software

Several open source software projects enable the platform to operate. This section is dedicated to acknowledge the most important.

@@ -170,14 +26,10 @@
  • The web application is build using Django Web Framework.
  • The code editor for many exercises with syntax highlight is based on CodeMirror.
  • - +

    - - - - -
    - -
    - - - - - - - - - - {% include "frontend/footer.html" %} - - - - - - - - - - - - - - - - - - - - - - - - +{% include "frontend/footer.html" %} diff --git a/src/frontend/templates/frontend/footer.html b/src/frontend/templates/frontend/footer.html index c74fa31..db5dfa2 100644 --- a/src/frontend/templates/frontend/footer.html +++ b/src/frontend/templates/frontend/footer.html @@ -22,3 +22,14 @@ | Attribution + + + + + + + + + + + diff --git a/src/frontend/templates/frontend/header.html b/src/frontend/templates/frontend/header.html new file mode 100644 index 0000000..e7bc41f --- /dev/null +++ b/src/frontend/templates/frontend/header.html @@ -0,0 +1,30 @@ +{% load staticfiles %} +{% load cookielaw_tags %} + + + + + + + + + + + + + Teaching @ HPS + + + + + + + + + + + + {% cookielaw_banner %} + {% include "frontend/navbar.html" %} + +
    diff --git a/src/frontend/templates/frontend/index.html b/src/frontend/templates/frontend/index.html index a7ae6f0..da142e5 100644 --- a/src/frontend/templates/frontend/index.html +++ b/src/frontend/templates/frontend/index.html @@ -1,73 +1,16 @@ {% load staticfiles %} -{% load cookielaw_tags %} - - - - - - - - - - - - - Teaching - Scientific Computing @ UHH - - - - - - - - - - - - - - - - - - - {% cookielaw_banner %} - - - {% include "frontend/navbar.html" %} - -
    -
    -
     
    -
    - -
    +{% include "frontend/header.html" %}
    - -{% for course in courses_list %} -
    -

    {{ course.title }}

    -

    {{ course.description }}

    -

    Take course »

    -
    -{% endfor %} + {% for course in courses_list %} +
    +

    {{ course.title }}

    +

    {{ course.description }}

    +

    Take course »

    +
    + {% endfor %}

    {% include "frontend/footer.html" %} - -
    - - - - - - - - - diff --git a/src/frontend/templates/frontend/navbar.html b/src/frontend/templates/frontend/navbar.html index 55961bf..53640e1 100644 --- a/src/frontend/templates/frontend/navbar.html +++ b/src/frontend/templates/frontend/navbar.html @@ -10,7 +10,7 @@ - Teaching at + Online teaching courses at @@ -60,8 +60,6 @@
  • Login with Twitter
  • Login with Google+
  • Login with Facebook
  • - - diff --git a/src/frontend/templates/frontend/privacy.html b/src/frontend/templates/frontend/privacy.html index e69de29..05b11ad 100644 --- a/src/frontend/templates/frontend/privacy.html +++ b/src/frontend/templates/frontend/privacy.html @@ -0,0 +1,36 @@ +{% load staticfiles %} +{% include "frontend/header.html" %} +
    +

    Privacy

    + +

    Server logs

    +

    + A visit to our website can result in the storage on our server of information about the access (date, time, page accessed). This does not represent any analysis of personal data (e.g., name, address or e-mail address). If personal data are collected, this only occurs – to the extent possible – with the prior consent of the user of the website. Any forwarding of the data to third parties without the express consent of the user shall not take place. +

    + + +

    Uploaded information

    +

    + This platform allows users to submit data for verification purpose like program code and quizes. + For improving the overall quality of the teaching experience, we may store and process the submitted information automatically. + If you are logged in as a user, the user id is also contained in this data. + If you do not like that your id is potentially stored together with the program code, we recommend to not login as a user but use the platform anonymously. +

    + +

    Information about cookies

    + + +

    Contact

    +

    + If you have any questions regarding privacy send an email to: info@oer.hps.vi4io.org +

    + +
    + +{% include "frontend/footer.html" %} diff --git a/src/main/settings.py b/src/main/settings.py index 5eda180..4793a8f 100644 --- a/src/main/settings.py +++ b/src/main/settings.py @@ -23,7 +23,7 @@ SECRET_KEY = 'pxf234t25323vasfk3t202v2232v124' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = False -DEBUG = True +#DEBUG = True ALLOWED_HOSTS = ['localhost', 'oer.hps.vi4io.org'] diff --git a/src/rest/views.py b/src/rest/views.py index c190424..c10ed4e 100644 --- a/src/rest/views.py +++ b/src/rest/views.py @@ -28,6 +28,7 @@ import os import pprint import re import os.path +import shutil from courses.models import Course from courses.models import Section @@ -38,20 +39,32 @@ from courses.models import UserSolution from runner.tasks import compile_and_run import json +import random + def local_execute(dic): - #print("LOCAL EXECUTE") - id = 100 + id = random.randint(1,10000000) + file = "/data/run/jobs/%s/job.json" % (id) + while os.path.isfile(file): + id = random.randint(1,10000000) + file = "/data/run/jobs/%s/job.json" % (id) + ret = compile_and_run(id, dic) print(ret, file=sys.stderr) - return {"status" : 'SUCCESS', "id" : id, "result": ret} + return {"details": "OK", "id" : id, "data": ret} def local_execute_result(id): #return {"status" : 201, "result": {"output" : False, "grade" : "PASS"}} - file = "/data/run/jobs/%s/job.json" % (id) - print("Retrieving: " + file) - if os.path.isfile(file): - with open(file) as json_data: + if not id.isdigit(): + return {"status" : 0, "result": {"output" : False}} + + dir = "/data/run/jobs/%s/" % (id) + print("Retrieving: " + dir) + if os.path.isfile(dir + "job.json"): + with open(dir + "job.json") as json_data: d = json.load(json_data) + # cleanup of outdated directories + shutil.rmtree(dir) + return {"status" : 'SUCCESS', "result": d["response"]} else: return {"status" : 0, "result": {"output" : False}} @@ -248,19 +261,11 @@ def job_new(request): try: #task = celery_task_compile_and_run.delay(job_dic) - task = local_execute(job_dic) - - #print(dir(task), file=sys.stderr) - #print("PREP") - #print(task.id, file=sys.stderr) - #print(task.status, file=sys.stderr) - job_dic["_id"] = task["id"] - #print("DONE") - + data = local_execute(job_dic) #_id = job_col.insert(request.data) #print(_id, file=sys.stderr) #json_docs = json.dumps(data, default=json_util.default) - return JSONResponse({"details": "OK", "id": str(task["id"])}, status=201) + return JSONResponse(data, status=201) except: print(sys.exc_info()[0]) return JSONResponse({"details": "Job submission failed."}, status=400) diff --git a/src/runner/tasks.py b/src/runner/tasks.py index 81d24fb..42d3709 100644 --- a/src/runner/tasks.py +++ b/src/runner/tasks.py @@ -230,6 +230,9 @@ def compile_and_run(id, data): if data['action'] in ["grade", "quiz"]: j.grade() + if data['action'] == "quiz": + return {"grade" : j.grade_result } + #print("Result prepare") ret = j.response() j.response_data = ret