From 62a0ca398103eb1347e4d84be902217ba0d3c545 Mon Sep 17 00:00:00 2001 From: Shufan Li Date: Wed, 19 Feb 2020 11:10:10 -0800 Subject: [PATCH 1/2] Added API endpoints for Future Frontend development --- manage.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 manage.py diff --git a/manage.py b/manage.py new file mode 100644 index 0000000..3f31a64 --- /dev/null +++ b/manage.py @@ -0,0 +1,35 @@ +from flask import Flask, request, jsonify +from flask_script import Manager +from analyzer import get_problems, Comment +from finalizing import grade as f_grade + +app = Flask(__name__) +manager = Manager(app) + +HTTPEXCEPTIONS = { + 1:"BAD REQUEST:No 'code' field", + 2:"BAD REQUEST:Code Execution Error", + 3: "BAD REQUEST:No 'comment' field" +} + +def illegal_request(id): + return HTTPEXCEPTIONS.get(id),400 + +@app.route('/get_comment/', methods=['POST']) +def get_comment(): + if "code" not in request.json: + return illegal_request(1) + code = request.json.get("code") + result = get_problems(code) + return jsonify(result) + +@app.route('/grade/', methods=['POST']) +def grade(): + if "comment" not in request.json: + return illegal_request(3) + comment = request.json.get("comment") + result = f_grade(comment) + return jsonify(result) + +if __name__ == "__main__": + manager.run() From fdb6242c945ba0c0acd6891e258f7ffb0b09c82c Mon Sep 17 00:00:00 2001 From: Shufan Li Date: Tue, 10 Mar 2020 15:21:32 -0700 Subject: [PATCH 2/2] added API endpoints --- analyzer.py | 53 +++++++++++++++++++++++++-------------- manage.py | 66 +++++++++++++++++++++++++++++++++++++++++-------- ok_interface.py | 2 +- 3 files changed, 91 insertions(+), 30 deletions(-) diff --git a/analyzer.py b/analyzer.py index 52144d9..f2c60a7 100644 --- a/analyzer.py +++ b/analyzer.py @@ -5,9 +5,21 @@ #TODO: update PROBLEMS declaration to match project PROBLEMS = { - "roll_dice": ["def roll_dice", "def free_bacon"], - "play": ["def play", "#######################"], - "max_scoring_num_rolls": ["def max_scoring_num_rolls", "def winner"], + "hog":{ + "roll_dice": ["def roll_dice", "def free_bacon"], + "play": ["def play", "#######################"], + "max_scoring_num_rolls": ["def max_scoring_num_rolls", "def winner"]}, + "typing":{ + "accuracy": ["def accuracy", "def wpm"], + "autocorrect": ["def autocorrect", "def swap_diff"] + }, + "ants":{ + "Short and LongThrowers": ["class ShortThrower", "class FireAnt"], + "ThrowerAnt": ["class ThrowerAnt", "def throw_at"], + "FireAnt": ["class FireAnt", "class HungryAnt"], + "BodyguardAnt - Ant": ["class BodyguardAnt", "class TankAnt"], + "BodyguardAnt - Place": ["def add_insect", "def remove_insect"], + } } # PROBLEMS = { @@ -61,34 +73,37 @@ def comments(self) -> Generator[Comment, None, None]: TARGETED_CHECKERS: Dict[str, List[Type[Checker]]] = {} -def get_problems(code: str): +def get_problems(code,problem_name="hog"): out = {} - for name, (start, end) in PROBLEMS.items(): + for name, (start, end) in PROBLEMS[problem_name].items(): start_index = code.index(start) end_index = code.index(end) initial_line_number = code[:start_index].count("\n") + 1 func_code = code[start_index:end_index].strip() - comments = [] - - tree = ast.parse(func_code) - for checker in CHECKERS + TARGETED_CHECKERS.get(name, []): - checker = checker(func_code) - checker.visit(tree) - for comment in checker.comments(): - comments.append( - Comment( - comment.line_num + initial_line_number - 1, - comment.comment, - comment.fields, - ) - ) + comments=check_problem(func_code,name) comments.sort(key=lambda x: x.line_num) out[name] = Problem(func_code, initial_line_number, comments) return out +def check_problem(func_code,name,initial_line_number=0): + comments = [] + + tree = ast.parse(func_code) + for checker in CHECKERS + TARGETED_CHECKERS.get(name, []): + checker = checker(func_code) + checker.visit(tree) + for comment in checker.comments(): + comments.append( + Comment( + comment.line_num + initial_line_number - 1, + comment.comment, + comment.fields, + ) + ) + return comments # @checker class VariableNotNeededChecker(Checker): diff --git a/manage.py b/manage.py index 3f31a64..b565242 100644 --- a/manage.py +++ b/manage.py @@ -1,7 +1,11 @@ from flask import Flask, request, jsonify from flask_script import Manager -from analyzer import get_problems, Comment +from analyzer import get_problems, Comment, PROBLEMS,check_problem from finalizing import grade as f_grade +from ok_interface import get_backup_ids as f_get_backup_ids, submit_comment +import requests +import auth +from ok_interface import ACCESS_TOKEN app = Flask(__name__) manager = Manager(app) @@ -9,27 +13,69 @@ HTTPEXCEPTIONS = { 1:"BAD REQUEST:No 'code' field", 2:"BAD REQUEST:Code Execution Error", - 3: "BAD REQUEST:No 'comment' field" + 3: "BAD REQUEST:No 'comment' field", + 4:"BAD REQUEST: Illegal Files" } def illegal_request(id): return HTTPEXCEPTIONS.get(id),400 -@app.route('/get_comment/', methods=['POST']) +@app.route('/api/get_backup_ids', methods=['GET']) +def get_backup_ids(): + id = request.args.get('id',default = -1, type = int) + print ("THIS is: ",id) + return "x" + +@app.route('/api/get_backup_problems', methods=['GET']) +def get_backup_problems(): + id = request.args.get('id', default="", type=str) + print ("THIS is: ", id) + params = {"access_token": ACCESS_TOKEN} + r = requests.get(f"https://okpy.org/api/v3/backups/{id}", params=params) + messages = r.json()["data"]["messages"][0] + out = [] + print("MESSEGSES:", messages) + for proj_name in PROBLEMS: + print(proj_name+".py") + if proj_name+".py" in messages["contents"]: + problems = PROBLEMS[proj_name] + project = proj_name + code = messages["contents"][proj_name+".py"] + break + else: + return illegal_request(4) + for name, (start, end) in problems.items(): + start_index = code.index(start) + end_index = code.index(end) + initial_line_number = code[:start_index].count("\n") + 1 + func_code = code[start_index:end_index].strip() + out.append({"problem_name":name,"problem_body":func_code,"initial_line_number":initial_line_number}) + + return jsonify(out) + +@app.route('/get_potential_comments', methods=['POST']) def get_comment(): - if "code" not in request.json: + try: + code = request.json.get("problem_body") + problem = request.json.get("problem_name") + init_line = request.json.get("initial_line_number") + except: return illegal_request(1) - code = request.json.get("code") - result = get_problems(code) + result = check_problem(code,problem,init_line) return jsonify(result) -@app.route('/grade/', methods=['POST']) +@app.route('/submit_comment/', methods=['POST']) def grade(): - if "comment" not in request.json: + try: + id = request.json.get("id") + comments = request.json.get("comments") + except: return illegal_request(3) - comment = request.json.get("comment") - result = f_grade(comment) + result = f_grade(comments) + for comment in comments: + submit_comment(id,comment["line_num"],comment["comment"]) return jsonify(result) + if __name__ == "__main__": manager.run() diff --git a/ok_interface.py b/ok_interface.py index 80f63ed..f0ce92d 100644 --- a/ok_interface.py +++ b/ok_interface.py @@ -14,7 +14,7 @@ def get_backup_ids(file="raw_queue.txt", completed_file="completed"): Keyword arguments: file -- the file path to the list of submission URLs (default "raw_queue.txt") - This file can just contain the HTML source code of the grading queue on OKpy. + This file can just contain the HTML source code of the grading queue on OKpy. The links will be automatically extracted and the file updated. completed_file -- the file path to the list of completed submission IDs (default "completed") """