summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimotej Lazar <timotej.lazar@fri.uni-lj.si>2019-02-19 23:52:49 +0100
committerTimotej Lazar <timotej.lazar@fri.uni-lj.si>2019-02-19 23:52:49 +0100
commitd0c2fc09b6dc0c51167f15361d5a4a4c2050f205 (patch)
tree114e086681c9788570749639fc96edc11bdfe43f
parent6063a9c657a0adcd99bfcd6d5c2a457ae154caed (diff)
First try for token-based params and results requests
-rwxr-xr-xkpov_judge/add_task.py2
-rwxr-xr-xkpov_judge/test_task.py70
-rwxr-xr-xkpov_judge/web/kpov_judge/kpov_judge.py79
3 files changed, 101 insertions, 50 deletions
diff --git a/kpov_judge/add_task.py b/kpov_judge/add_task.py
index aab5e46..066efed 100755
--- a/kpov_judge/add_task.py
+++ b/kpov_judge/add_task.py
@@ -16,7 +16,7 @@ def task_check(results, params):
'results': json.dumps(results),
'params': json.dumps(params)
}).encode()
- req = urllib.request.Request('{task_url}/{task_name}/results.json'.format(task_url=task_url, task_name=task_name), data)
+ req = urllib.request.Request('{task_url}/{task_name}/results-token.json'.format(task_url=task_url, task_name=task_name), data)
response = urllib.request.urlopen(req)
response_dict = json.loads(response.read().decode())
hints = response_dict.get('hints', [])
diff --git a/kpov_judge/test_task.py b/kpov_judge/test_task.py
index d3dcec7..28fc513 100755
--- a/kpov_judge/test_task.py
+++ b/kpov_judge/test_task.py
@@ -91,14 +91,9 @@ def locate_task(params, argparser, quiet=False):
params['task_url'] = args.task_url
if not quiet:
params = get_params(params, url_meta)
- # then the student's ID (and password if neccessarry)
- fetch_params_meta = collections.OrderedDict({
- 'username': {'descriptions': {'si': 'Uporabniško ime', 'en': 'Username'}},
- })
- if params.get('task_url', '').startswith('http'):
- fetch_params_meta['password'] = {'descriptions': {'si': 'Geslo', 'en': 'Password'}, 'masked': True}
+
# and finally, the name of the task
- fetch_params_meta['task_name'] = {'descriptions': {'si': 'Ime naloge', 'en': 'Task name'}, }
+ fetch_params_meta = collections.OrderedDict({'task_name': {'descriptions': {'si': 'Ime naloge', 'en': 'Task name'}}})
add_meta_to_argparser(argparser, meta=fetch_params_meta, defaults=params)
args, unknown_args = argparser.parse_known_args()
# update params with the now known args
@@ -106,6 +101,7 @@ def locate_task(params, argparser, quiet=False):
params[k] = vars(args).get(k, params.get(k, None))
if not quiet:
params = get_params(params, fetch_params_meta)
+ print()
return params
def load_params(filename):
@@ -113,7 +109,8 @@ def load_params(filename):
return yaml.load(open(filename))
except:
return {}
-
+
+
if __name__ == '__main__':
# get the parameters needed to get to the task, such as the URLs, the name of the task and optionally an ID from the student
# start with the the parameters needed for the dialog gui to work
@@ -124,7 +121,7 @@ if __name__ == '__main__':
help='disable prompts')
argparser.add_argument('-g', '--generate_params', action='store_true',
help='generate initial values for the task parameters')
- argparser.add_argument('-pf','--params_file', nargs='?', default=PARAMS_FILE,
+ argparser.add_argument('-pf', '--params_file', nargs='?', default=PARAMS_FILE,
help='a local file containing saved param values')
basic_args, unknown_args = argparser.parse_known_args()
@@ -143,34 +140,59 @@ if __name__ == '__main__':
try:
task_url = params['task_url']
task_name = params['task_name']
- if task_url.startswith('http'):
- http_auth(task_url, params['username'], params['password'])
- print("Fetching {task_url}/{task_name}/task.py…".format(**params))
+
source = urllib.request.urlopen("{task_url}/{task_name}/task.py".format(**params))
task, task_check, task_params_meta, gen_params = load_task(source)
except Exception as e:
- print(str(e))
- print()
- for k, v in params.items():
- if k not in ('password', 'task_params'):
- print('{}: {}'.format(k, v))
+ import traceback
+ traceback.print_exc()
with open(basic_args.params_file, 'w') as f:
yaml.dump(params, f)
exit(1)
- # get task parameters
+ # get stored task parameters
params['task_params'] = params.get('task_params', {})
- params['task_params'][params['task_name']] = params['task_params'].get(params['task_name'], {})
- task_params = params['task_params'][params['task_name']]
+ task_params = params['task_params'].setdefault(task_name, {})
+
+ # ensure we have a submission token
+ if task_url.startswith('http'):
+ # check if existing token is valid
+ if task_params.get('token'):
+ response = urllib.request.urlopen(
+ '{task_url}/{task_name}/params-token.json'.format(**params),
+ data=urllib.parse.urlencode({'params': json.dumps(task_params)}).encode())
+ response = json.load(io.TextIOWrapper(response))
+ if response:
+ # got a good token
+ task_params.update(response)
+ else:
+ # did not get a token, try again with password
+ del task_params['token']
+
+ # authenticate to get a new token
+ if not task_params.get('token'):
+ # get the student's ID and password
+ # TODO clunky, should refactor all argument-getting stuff
+ fetch_params_meta = {'username': {'descriptions': {'si': 'Uporabniško ime', 'en': 'Username'}}}
+ params = get_params(params, fetch_params_meta, params['language'])
+ fetch_pass_meta = {'password': {'descriptions': {'si': 'Geslo', 'en': 'Password'}, 'masked': True}}
+ params_pass = get_params({}, fetch_pass_meta, params['language'])
+
+ try:
+ http_auth(task_url, params['username'], params_pass['password'])
+ response = urllib.request.urlopen('{task_url}/{task_name}/params.json'.format(**params))
+ response = json.load(io.TextIOWrapper(response))
+ if response:
+ task_params.update(response)
+ except Exception as ex:
+ print(ex)
+ exit(2)
+
if basic_args.generate_params:
#prejema lahko samo stringe in ne številk (potrebno je str(int)
# print ("params before: {} {}".format(params, task_params))
task_params.update(gen_params(params['username'], task_params_meta))
# print ("params after: {} {}".format(params, task_params))
- if task_url.startswith('http'):
- response = urllib.request.urlopen('{task_url}/{task_name}/params.json'.format(**params))
- web_task_params = json.load(io.TextIOWrapper(response))
- task_params.update(web_task_params)
task_argparser = argparse.ArgumentParser(parents=[argparser], conflict_handler='resolve', add_help=True)
add_meta_to_argparser(task_argparser, task_params_meta, defaults=task_params)
diff --git a/kpov_judge/web/kpov_judge/kpov_judge.py b/kpov_judge/web/kpov_judge/kpov_judge.py
index 95d7199..ddef16d 100755
--- a/kpov_judge/web/kpov_judge/kpov_judge.py
+++ b/kpov_judge/web/kpov_judge/kpov_judge.py
@@ -6,6 +6,7 @@ import json
import random
import settings
import traceback
+import uuid
from kpov_draw_setup import draw_setup
import kpov_util
@@ -70,10 +71,15 @@ def class_tasks(class_id):
return render_template('class_tasks.html', student_id=student_id, tasks=task_list, clas=clas)
-def results_post(class_id, task_id, results):
+def results_post(class_id, task_id, token, results):
student_id = flask.app.request.environ.get('REMOTE_USER', 'Nobody')
db = g.db
- params = db.task_params.find_one({'class_id': class_id, 'task_id': task_id, 'student_id': student_id})['params']
+ #params = db.task_params.find_one({'class_id': class_id, 'task_id': task_id, 'student_id': student_id})['params']
+ print(class_id, task_id, token)
+ params = db.task_params.find_one({'class_id': class_id, 'task_id': task_id, 'params.token': token})['params']
+ if not params:
+ raise Exception('Invalid token.')
+
if params is None:
# params = {}
#else:
@@ -104,10 +110,14 @@ def results_post(class_id, task_id, results):
return {'result': res, 'hints': hints, 'status': res_status}
-def results_dict(class_id, task_id):
- student_id = flask.app.request.environ.get('REMOTE_USER', 'Nobody')
+def results_dict(class_id, task_id, token):
db = g.db
try:
+ task_params = db.task_params.find_one({'class_id': class_id, 'task_id': task_id, 'token': token})
+ if not task_params:
+ raise Exception('Invalid token.')
+ #student_id = flask.app.request.environ.get('REMOTE_USER')
+ student_id = task_params['student_id']
entry = db.results.find_one(
{'$query': {'class_id': class_id, 'task_id': task_id, 'student_id': student_id}, # vsi uporabniki brez nastavljenega REMOTE_USER (i.e. Apache basic auth) imajo skupne rezultate, napaka?
'$orderby': {'time': -1}},
@@ -122,9 +132,11 @@ def results_dict(class_id, task_id):
@app.route('/tasks/<class_id>/<task_id>/results.json', methods=['GET', 'POST'])
def results_json(class_id, task_id):
if flask.app.request.method == 'POST':
- return json.dumps(results_post(class_id, task_id,
- json.loads(flask.app.request.form['results'])))
- return json.dumps(results_dict(class_id, task_id))
+ return json.dumps(
+ results_post(class_id, task_id,
+ json.loads(flask.app.request.form['params']).get('token'),
+ json.loads(flask.app.request.form['results'])))
+ return json.dumps(results_dict(class_id, task_id, request.args.get('token')))
@app.route('/tasks/<class_id>/<task_id>/<lang>/setup.<ending>', methods=['GET'])
@@ -156,11 +168,20 @@ def task_html(class_id, task_id):
return render_template('task.html', task=task_source(class_id, task_id))
+def make_token(student_id):
+ # TODO need nginx support, in version 1.11.3, not yet in debian stable
+ #import jwt
+ #message = {'student_id': student_id}
+ #return jwt.encode(message, app.config['JWT_SECRET'], algorithm='HS512').decode('utf-8')
+ return str(uuid.uuid4())
+
def get_params(class_id, task_id, student_id, db):
try:
meta = db.task_params_meta.find_one({'class_id': class_id, 'task_id': task_id})['params']
+ meta['token'] = {'public': True, 'generated': True, 'type': 'password', 'w': False}
except Exception:
return {'mama': 'ZAKVAJ?'}, {'mama': {'public': True}}
+
params = db.task_params.find_one({'class_id': class_id, 'task_id': task_id, 'student_id': student_id})
if params is None:
try:
@@ -281,29 +302,37 @@ def task_greeting(class_id, task_id, lang):
**{p['name']: p['value'] for p in public_params})
-@app.route('/tasks/<class_id>/<task_id>/params.json', methods=['GET', 'POST'])
-def params_json(class_id, task_id):
- student_id = flask.app.request.environ.get('REMOTE_USER', 'Nobody')
+@app.route('/tasks/<class_id>/<task_id>/params.json')
+def params_json(class_id, task_id, student_id=None):
+ if not student_id:
+ student_id = flask.app.request.environ.get('REMOTE_USER', 'Nobody')
db = g.db
params, meta = get_params(class_id, task_id, student_id, db)
shown_params = {}
- if flask.app.request.method == 'POST':
- try:
- new_params = json.loads(flask.app.request.form['params'])
- except Exception:
- new_params = {}
- for name in params.items():
- if meta.get(name, {'w': False}).get('w', False) and k in new_params:
- params[name] = new_params[name]
- if meta.get(name, {'public': False})['public']:
- shown_params[name] = params[name]
- db.task_params.update({'class_id': class_id, 'task_id': task_id, 'student_id': student_id}, {'$set': {'params': params}})
- else:
- for name, param in params.items():
- if meta.get(name, {'public': False})['public']:
- shown_params[name] = param
+ for name, param in params.items():
+ if meta.get(name, {'public': False})['public']:
+ shown_params[name] = param
return json.dumps(shown_params)
+@app.route('/tasks/<class_id>/<task_id>/params-token.json', methods=['POST'])
+def params_token_json(class_id, task_id):
+ db = g.db
+ token = json.loads(flask.app.request.form['params']).get('token', '')
+ record = db.task_params.find_one({'class_id': class_id, 'task_id': task_id, 'params.token': token})
+ if not record:
+ return json.dumps({})
+ return params_json(record['class_id'], record['task_id'], record['student_id'])
+
+@app.route('/tasks/<class_id>/<task_id>/results-token.json', methods=['GET', 'POST'])
+def results_token_json(class_id, task_id):
+ db = g.db
+ token = json.loads(flask.app.request.form['params']).get('token', '')
+ record = db.task_params.find_one({'class_id': class_id, 'task_id': task_id, 'params.token': token})
+ if not record:
+ return json.dumps({})
+ return results_json(class_id, task_id)
+
+
if __name__ == '__main__':
app.run(host='0.0.0.0')