This commit is contained in:
Julian M. Kunkel 2018-05-06 10:20:32 +01:00
parent 1a0c5af7f7
commit d82609737d
14 changed files with 63 additions and 94 deletions

0
oer/exercise-formats/choice/multiple/script.js Normal file → Executable file
View File

0
oer/exercise-formats/input/text/script.js Normal file → Executable file
View File

View File

View File

6
oer/exercise-formats/program/match-regex/controller.py Normal file → Executable file
View File

@ -20,7 +20,7 @@ def build(ctx):
# start subprocess in with work_path as cwd # start subprocess in with work_path as cwd
p = subprocess.Popen(allArgs, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=ctx.work_path) p = subprocess.Popen(allArgs, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=ctx.work_path)
msgs,errs = p.communicate() msgs,errs = p.communicate()
retval = p.wait() retval = p.wait()
errs = errs.decode("utf-8") errs = errs.decode("utf-8")
msgs = msgs.decode("utf-8") msgs = msgs.decode("utf-8")
@ -37,7 +37,7 @@ def execute(ctx):
p = subprocess.Popen(allArgs, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=ctx.work_path) p = subprocess.Popen(allArgs, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=ctx.work_path)
msgs,errs = p.communicate() msgs,errs = p.communicate()
retval = p.wait() retval = p.wait()
errs = errs.decode("utf-8") errs = errs.decode("utf-8")
msgs = msgs.decode("utf-8") msgs = msgs.decode("utf-8")
@ -62,10 +62,8 @@ def grade(ctx):
else: else:
return 'FAIL' return 'FAIL'
def response(ctx): def response(ctx):
output = "" output = ""
if ctx.build_result[0] != 0: if ctx.build_result[0] != 0:
output = ctx.build_result[1] output = ctx.build_result[1]

0
oer/exercise-formats/program/match-regex/script.js Normal file → Executable file
View File

0
oer/exercise-formats/program/scriptgrade/script.js Normal file → Executable file
View File

0
oer/exercise-formats/text/html/script.js Normal file → Executable file
View File

View File

@ -14,6 +14,8 @@
.sep { color: silver; margin: 0.3em; } .sep { color: silver; margin: 0.3em; }
</style> </style>
<a href="/privacy">Privacy</a>
<span class="sep">|</span>
<a href="https://hps.vi4io.org/impressum">Impressum</a> <a href="https://hps.vi4io.org/impressum">Impressum</a>
<span class="sep">|</span> <span class="sep">|</span>
<a href="https://hps.vi4io.org/research/projects/hamburg/icp">Contact</a> <a href="https://hps.vi4io.org/research/projects/hamburg/icp">Contact</a>

View File

@ -34,6 +34,10 @@ def attribution(request):
data = {} data = {}
return render(request, 'frontend/attribution.html', data) return render(request, 'frontend/attribution.html', data)
def privacy(request):
data = {}
return render(request, 'frontend/privacy.html', data)
def dashboard(request): def dashboard(request):
# only registered users can see their statistics # only registered users can see their statistics
if not request.user.is_authenticated: if not request.user.is_authenticated:

View File

@ -29,6 +29,7 @@ urlpatterns = [
url(r'^dashboard/$', frontend.views.dashboard, name='dashboard'), url(r'^dashboard/$', frontend.views.dashboard, name='dashboard'),
url(r'^settings/$', frontend.views.settings, name='settings'), url(r'^settings/$', frontend.views.settings, name='settings'),
url(r'^attribution/$', frontend.views.attribution, name='attribution'), url(r'^attribution/$', frontend.views.attribution, name='attribution'),
url(r'^privacy/$', frontend.views.privacy, name='privacy'),
# Courses # Courses
url(r'^courses/', include('courses.urls', namespace='courses')), url(r'^courses/', include('courses.urls', namespace='courses')),

View File

@ -27,6 +27,7 @@ import sys
import os import os
import pprint import pprint
import re import re
import os.path
from courses.models import Course from courses.models import Course
from courses.models import Section from courses.models import Section
@ -34,14 +35,26 @@ from courses.models import Slide
from courses.models import UserCourse from courses.models import UserCourse
from courses.models import UserSolution from courses.models import UserSolution
from runner.tasks import compile_and_run
import json
def local_execute(dic): def local_execute(dic):
print("LOCAL EXECUTE") #print("LOCAL EXECUTE")
print(dic) id = 100
return {"id" : 100} ret = compile_and_run(id, dic)
print(ret, file=sys.stderr)
return {"status" : 'SUCCESS', "id" : id, "result": ret}
def local_execute_result(id): def local_execute_result(id):
print("Retrieving: " + id) #return {"status" : 201, "result": {"output" : False, "grade" : "PASS"}}
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:
d = json.load(json_data)
return {"status" : 'SUCCESS', "result": d["response"]}
else:
return {"status" : 0, "result": {"output" : False}}
# helpers # helpers
class JSONResponse(HttpResponse): class JSONResponse(HttpResponse):
@ -178,7 +191,6 @@ def job_status(request, jid):
#data = JSONParser().parse(json_docs) #data = JSONParser().parse(json_docs)
return JSONResponse(data) return JSONResponse(data)
return HttpResponse("huh", status=401) return HttpResponse("huh", status=401)

View File

@ -1,34 +1,23 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from runner.celery import app #from runner.celery import app
import subprocess import subprocess
import os import os
import sys import sys
import shutil import shutil
import json import json
import importlib.machinery import importlib.machinery
WORK_DIR = "/data/run/jobs"
# To conserve resources consider using the ignore result decorator, when the result is not used by someone else OER_FORMATS_PATH = "/data/oer/exercise-formats/"
#@app.task(ignore_result=True)
###############################################################################
# Settings
###############################################################################
WORK_DIR = os.path.expanduser(os.environ["WORKER_DIR"])
OER_FORMATS_PATH = os.path.expanduser(os.environ["WORKER_OER_DIR"] + "/exercise-formats/")
###############################################################################
def load_handler(path): def load_handler(path):
handler = {'name': None, 'loader': None, 'mod': None}
handler = {'name': None, 'loader': None, 'mod': None}
#print(path, file=sys.stderr)
for root, dirs, files in os.walk(path): for root, dirs, files in os.walk(path):
#print(root, file=sys.stderr)
#print(dirs, file=sys.stderr) #print(dirs, file=sys.stderr)
#print(files, file=sys.stderr) #print(files, file=sys.stderr)
if 'controller.py' in files: if 'controller.py' in files:
@ -50,7 +39,7 @@ def load_handler(path):
class Job(object): class Job(object):
""" """
The job class for tasks implements some default behaivior for every The job class for tasks implements some default behaivior for every
format and tries to call special event handlers when they are defined format and tries to call special event handlers when they are defined
for the formats or exercises. for the formats or exercises.
@ -66,8 +55,8 @@ class Job(object):
""" """
def __init__(self, job, celery_task=None): def __init__(self, job):
print("Job.__init__()", file=sys.stderr) #print("Job.__init__()", file=sys.stderr)
self.data = job self.data = job
self.work_path = WORK_DIR + '/' + str(job['_id']) + '/' self.work_path = WORK_DIR + '/' + str(job['_id']) + '/'
self.handler_format = {'name': None, 'loader': None, 'mod': None} self.handler_format = {'name': None, 'loader': None, 'mod': None}
@ -78,31 +67,22 @@ class Job(object):
self.grade_result = 'FAIL' self.grade_result = 'FAIL'
self.response_data = {} self.response_data = {}
# allow controllers to manipulate celery task
# e.g. to set meta data after submitting slurm jobs
self.celery_task = celery_task
def import_handlers(self): def import_handlers(self):
print("Job.init_handlers()", file=sys.stderr) print("Job.init_handlers()", file=sys.stderr)
# find exercise specific and default handler for exercise format # find exercise specific and default handler for exercise format
self.handler_format = load_handler("%s/%s" % (OER_FORMATS_PATH, self.data['type'])) self.handler_format = load_handler("%s/%s" % (OER_FORMATS_PATH, self.data['type']))
self.handler_exercise = load_handler( self.data['source_path']) self.handler_exercise = load_handler(self.data['source_path'])
if self.handler_format != None: if self.handler_format != None:
print("INFO: Format handler found ;", file=sys.stderr) print("INFO: Format handler found ;", file=sys.stderr)
if self.handler_exercise != None: if self.handler_exercise != None:
print("INFO: Exercise handlers found ;", file=sys.stderr) print("INFO: Exercise handlers found ;", file=sys.stderr)
def extract(self): def extract(self):
print("Job.extract()", file=sys.stderr) #print("Job.extract()", file=sys.stderr)
# creates workdir and files # creates workdir and files
print(self.data['source_path'], file=sys.stderr) print(self.data['source_path'], file=sys.stderr)
print(self.work_path, file=sys.stderr) print(self.work_path, file=sys.stderr)
@ -111,7 +91,7 @@ class Job(object):
src = self.data['source_path'] src = self.data['source_path']
dst = self.work_path dst = self.work_path
shutil.copytree(src, dst) shutil.copytree(src, dst)
self.sourcefile = self.work_path + 'program.c' self.sourcefile = self.work_path + 'program.c'
self.programfile = self.work_path + 'program' self.programfile = self.work_path + 'program'
@ -121,14 +101,6 @@ class Job(object):
source.close() source.close()
pass
def build(self): def build(self):
print("Job.build()", file=sys.stderr) print("Job.build()", file=sys.stderr)
@ -208,11 +180,8 @@ class Job(object):
fp = open(self.jobfile, 'w') fp = open(self.jobfile, 'w')
json.dump({"job": self.data, "response": self.response_data}, fp) json.dump({"job": self.data, "response": self.response_data}, fp)
fp.close() fp.close()
# into mongodb # into mongodb
def get_file_content(self, filename): def get_file_content(self, filename):
try: try:
with open(self.work_path + '/' + filename, 'r') as f: with open(self.work_path + '/' + filename, 'r') as f:
@ -228,60 +197,43 @@ class Job(object):
@app.task(time_limit=20) #@app.task(time_limit=20)
def timelimited_task(): #def timelimited_task():
try: # try:
return do_work() # return do_work()
except SoftTimeLimitExceeded: # except SoftTimeLimitExceeded:
cleanup_in_a_hurry() # cleanup_in_a_hurry()
#
@app.task #@app.task
def compile(): #def compile():
return True # return True
@app.task(bind=True) #@app.task(bind=True)
def compile_and_run(self, data): def compile_and_run(id, data):
#print(data, file=sys.stderr)
print(data, file=sys.stderr) #print(data['type'], file=sys.stderr)
print(self.request.id, file=sys.stderr) #print(data['action'], file=sys.stderr)
#print(data['source_path'], file=sys.stderr)
print(data['type'], file=sys.stderr) data['_id'] = id
print(data['action'], file=sys.stderr)
print(data['source_path'], file=sys.stderr)
data['_id'] = self.request.id
# create job object and call the different handlers # create job object and call the different handlers
j = Job(data, celery_task=self) j = Job(data)
j.import_handlers() j.import_handlers()
if data['action'] not in ["quiz"]: if data['action'] not in ["quiz"]:
j.extract() j.extract()
j.build() j.build()
if data['action'] in ["test", "execute", "run"]: if data['action'] in ["test", "execute", "run"]:
j.execute() j.execute()
if data['action'] in ["grade", "quiz"]: if data['action'] in ["grade", "quiz"]:
j.grade() j.grade()
print("Result prepare") #print("Result prepare")
ret = j.response() ret = j.response()
j.response_data = ret
j.store_result() j.store_result()
print("Result sent!") #print("Result sent!")
return ret return ret
# self.update_state(state='SUBMITTED TO SLURM', meta={})
# Convienence task definitions for programming assignments
@app.task
def compile_run_and_grade():
# start the celeryropriete subtasks
return True