From 5990fc92df32a88810e758510820474c24f950bd Mon Sep 17 00:00:00 2001 From: Eugene Tan Date: Tue, 12 Oct 2021 10:28:14 +0800 Subject: [PATCH] Completed HW --- .gitignore | 2 + Auth/AuthAPI.py | 74 ++++++- Profiles/ProfilesAPI.py | 57 +++++- .../__pycache__/ProfilesAPI.cpython-38.pyc | Bin 289 -> 1789 bytes __pycache__/db.cpython-38.pyc | Bin 292 -> 399 bytes db.py | 10 + documentation.md | 183 ++++++++++++++++++ main.py | 14 +- 8 files changed, 336 insertions(+), 4 deletions(-) create mode 100644 .gitignore create mode 100644 documentation.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ca14ccf --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +secretkeys.py +*.pyc \ No newline at end of file diff --git a/Auth/AuthAPI.py b/Auth/AuthAPI.py index b903496..1868677 100644 --- a/Auth/AuthAPI.py +++ b/Auth/AuthAPI.py @@ -1,7 +1,77 @@ # Score API here -from flask import Blueprint +from flask import Blueprint, current_app import sys -from db import db +import jwt + +from flask.globals import request +from flask.json import jsonify +from db import * + sys.path.append("../") auth_api = Blueprint("auth", __name__) + +@auth_api.route("/register", methods=["POST"]) +def register(): + + try: + if request.form.get("username") != None: + data = request.form + elif request.args.get("username") != None: + data = request.args + except: + return jsonify({"message": "bad request", "status": "failure"}) + + username = data["username"] + password = data["passwordHash"] + credentials.append({"username": username, "password": password}) + + return jsonify({"message": "registered", "status": "success"}) + + +@auth_api.route("/login", methods=["POST"]) +def login(): + + if request.args.get("token") != None: + #check if valid user + login_method = "token" + token = request.args.get("token") + try: + data = jwt.decode(token, current_app.config['SECRET_KEY'], algorithms=["HS256"]) + except: + return jsonify({"status": "failure", "message": "Token Not Valid"}) + username = data["userID"] + passwordHash = data["passwordHash"] + else: + login_method = "normal" + if request.form.get("username") != None: + data = request.form + elif request.args.get("username") != None: + data = request.args + username = data["username"] + passwordHash = data["passwordHash"] + + # checking if valid user + valid = False + for username_pw_dict in credentials: + if username == username_pw_dict["username"] and passwordHash in username_pw_dict["password"]: + valid = True + break + + if not valid: + if login_method == "token": + return jsonify({"status": "failure", "message": "Token Not Valid"}) + else: + return jsonify({"status": "failure", "message": "User not found"}) + + if login_method == "token": + return jsonify({"message": "logged in", "status": "success"}) + else: + + token = jwt.encode({'userID': username, + 'passwordHash': passwordHash + }, current_app.config['SECRET_KEY'], algorithm="HS256") + + return jsonify({'token': token, "status": "success"}) + + \ No newline at end of file diff --git a/Profiles/ProfilesAPI.py b/Profiles/ProfilesAPI.py index 4467047..209efd3 100644 --- a/Profiles/ProfilesAPI.py +++ b/Profiles/ProfilesAPI.py @@ -1,7 +1,62 @@ # Profile API here -from flask import Blueprint +from flask import Blueprint, json, request, jsonify import sys from db import db sys.path.append("../") profiles_api = Blueprint("profiles", __name__) + +@profiles_api.route("/", methods=["GET"]) +def get_id(id): + try: + if id > len(db) -1 : + return jsonify({"status": "error", "message" : "index out of range"}) + return jsonify({"data" : db[id], "status": "success"}) + except: + return jsonify({"status": "error"}) + + +@profiles_api.route("/create_profile", methods=["POST"]) +def add_new_profile(): + try: + data = request.form + new_profile = { "name": data["name"], "scores" : []} + db.append(new_profile) + return jsonify({"added": new_profile, "status": "success"}) + except: + return jsonify({"status": "error"}) + + +@profiles_api.route("/", methods=["DELETE"]) +def delete_profile(id): + + if id > len(db) - 1: + return jsonify({"status": "error", "message" : "index out of range"}) + + del db[id] + return jsonify({"deleted": db[id], "status": "success"}) + + +@profiles_api.route("//score", methods=["GET"]) +def get_scores_above_min(id): + + + if id > len(db) - 1: + return jsonify({"status": "error", "message" : "index out of range"}) + data = request.args + scores = db[id]["scores"] + + if data.get("minScore") == None: + return jsonify({"data" : scores, "status": "success" }) + else: + scores_greater_than_min = list(filter(lambda x : x > int(data["minScore"]), scores)) + return jsonify({"data" : scores_greater_than_min, "status": "success" }) + + + + + + + + + diff --git a/Profiles/__pycache__/ProfilesAPI.cpython-38.pyc b/Profiles/__pycache__/ProfilesAPI.cpython-38.pyc index f47262d95729440c17d40a0cd2cfafdeb3726cf7..edc05e0f5ac81251fd380e40ae7cf8f0fe838ec9 100644 GIT binary patch literal 1789 zcmah}OK%%D5GJ`#$+GM?PGYw}ng(c50ks7bK@Wv%G^vHQfZ-ak)5l&GYmt)I-iJz3 zZ7j$q6=-_sKghwk6!2f-wWpxR-g4>;wQ`g?KzFgT+~+}`^6(GFYrOs|nb4?V^$WaF=@)s^>K7~frAoidZ&-cP>Q}DLxye_p zeu=XK(z^8$d?hW{)E;F+F_3AYjeDZX!UR(MG!#mk0H-OZm2OzUmx;QIHFLTyoW=cy{&R7(gRm!lxdC7(EyhO*EZQPS?n(EAMN@ z8F#q*oK5KW6ok&?s0#nqXb{D3^+?+uTOpi%O3z%2qxTniPsoUNLk8PD`~;S z(|hGm-z$6fWK#6SB{RO#i5@ESQmLdbOrVC{E{tK#<%v$@BAj8xrDL2-6cYWG9*9do zAmx`t-iFDmhwUdyNYxg@z9@uFiuR6Br@9=pAAh~m`EKJ;XXBHNUY4lS_I`!d)!^a& zH=Bbq%CX1*(fcUjsGRGj5UOqQ&Gpa5muAEu~O$ z2_`LOyo7VXUt=b*Mp~Z4VlZy6l(~h^_{m@(3T|P9qi(=*v`~m&W^q|ar{WH7U4nDt zx%Hc%R80^Fkx!en4ln^o@1e23)7kADcCHZ)ov?)a6bApH+ueD(0oj0RpI@UKkSf@d zm>wIKT)+_~stP{}xX6T_0kDEAt0<5lbI~-XX0u@L!m0{E5NDY-8HDjZj3L*vQfga} z--yQn3*;dFl?L%Y@i-^$?=~tdpmlOipOFj5?+ePwDU-XJ0S5veVqrn_z7BpPJ!-p5 zIHnWOo-?q)LaS_Si7mVxjd#Hx6Xt1gfaI{?$Ys#I5dqdFX2hlvS22QTmZKAT>H^km zPu>ST^biMn3jFBPOKQ0?hh?~xCHWCgwjY4$Kk$*!hge2aUdG8$`Ll?@mCdcJ>?WDo zhQV}0E0lQm>w2zOn#jH~4xC}!EQOBeLub=Mwj6m2%`v#>PIY|WR-=sdaZ=zdQ^!6) zJImYEx4H5WEGvwdxR7t4ZG$x-@3*P^7<8>=Gq) zcT5<^Sd(#V8nZ?mCxg^@61ttRox@g!<(0i;j**s|*4c0?FZnPN+jz0UezQhH+5q?J M;9$K5Uw!)j7yYY+&Hw-a literal 289 zcmYjLyH3O~5VV~KIh6Yc+7twd5+Ow3kf1qEoQ@*0WEpt_Ax>i1x#DOk_zfueCAU=k z0u`GRAXeJhnbnSFSJUY(!K#{T`GWIf6#pwgafL+J<4aU~pFnMbpIlH)B j^27aY3}5^N|B+&Gm79%Ej@w?XHJprpxELX&2~F8IuqjO8 diff --git a/__pycache__/db.cpython-38.pyc b/__pycache__/db.cpython-38.pyc index 1970f4237665fe2a8571f911f49fcfe909ac43c2..808267ec99748b8c686849d9ea93d3964ea49263 100644 GIT binary patch delta 240 zcmZ3&)X&Tp%FD~e00dt5QWCWoC-TWKI!)BJk delta 148 zcmeBYUc$r|%FD~e00iH%{S!|xOyrYcw3?`G$(F(s%%I6Tu}FjQ*2LKwnSPp#x0q6r zRx%Xv0M&wtU;55gF`>n&Ma40G`AMlc3XXZ{F)pda*(Lb}F+m + + Get the name and scores associated with that profile based on a given ID. + + **Function used**: get_id() + **Source**: /**ProfilesAPI.py (line 10)** + *** + **Parameters**: + *** + **Response**: JSON object + *** + **Example**: /profiles/1 + ``` json + { + "data": { + "name": "Richard", + "scores": [ + 5, + 4, + 3, + 2, + 1 + ] + }, + "status": "success" + } + ``` +3. POST /profiles/create_profile + + Create a new profile with name only. + + **Function used**: add_new_profile() + **Source**: /**ProfilesAPI.py (line 20)** + *** + **Parameters**: + + name (required) + + Name of profile added + *** + **Response**: String of Response + *** + **Example**: /profiles/create_profile + ```json + { + "added": { + "name": "Eugene", + "scores" : [], + }, + "Status": "success" + } + ``` + + Otherwise, error will be thrown accordingly + +4. DELETE /profiles/\ + + Delete profile based on id. + + **Function used**: delete_profile() + **Source**: /**ProfilesAPI.py (line 31)** + *** + **Parameters**: + *** + **Response**: String of response + *** + **Example**: /profiles/1 + ```json + { + "deleted": { + "name": "Richard", + "scores": [ + 5, + 4, + 3, + 2, + 1 + ] + }, + "status": "success" + } + ``` + Otherwise, error will be thrown accordingly + +4. GET /profiles/\/score + + Get all of the scores of a profile above a specified minimum score. + + **Function used**: get_scores_above_min() + **Source**: /**ProfilesAPI.py (line 41)** + *** + **Parameters**: + + minScore + + Get scores of the specified profile based on the given id above minScore. If minScore is not specified, returns all scores. + *** + **Response**: List of scores + *** + **Example**: /profiles/1/score?minScore=3 + ```json + { + "data": [ + 5, + 4 + ], + "status": "success" + } + ``` + Otherwise, error will be thrown accordingly +6. POST /auth/register + + Stores a username and hashedPassword in an array of credentials. + + **Function used**: register() + **Source**: /**AuthAPI.py (line 15)** + *** + **Parameters**: + + username (Required) + + Username of user to register + + passwordHash (Required) + + Password of user + *** + **Response**: String of response + *** + **Example**: /auth/register?username=eugene&passwordHash=abcdefg123 + ```json + { + "message": "registered", + "status": "success" + } + ``` +7. POST /auth/login + + Checks if credentials are of registered users. + + **Function used**: login() + **Source**: /**AuthAPI.py (line 33)** + *** + **Parameters**: + + username + + Username of user to register + + passwordHash + + Password of user + + token + + JWT token to verify login + *** + **Response**: If JWT token is not provided, returns JWT token. In other cases, returns string of response + *** + **Example**: auth/login?username=eugene&passwordHash=abcdefg123 + ```json + { + "status": "success", + "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySUQiOiJCb2IiLCJwYXNzd29yZEhhc2giOiJ5ZXN3ZWNhbiJ9.iG_2s4dHaiDRdWTDRoawtZ8tv_lW8hb7niAzlTmB8n4", + } + ``` \ No newline at end of file diff --git a/main.py b/main.py index fc7fbd4..ff3c2a8 100644 --- a/main.py +++ b/main.py @@ -1,12 +1,24 @@ from Auth.AuthAPI import auth_api from Profiles.ProfilesAPI import profiles_api from flask import Flask -from db import db +from db import * +import jwt # Write your flask code here app = Flask(__name__) +app.config['SECRET_KEY'] = auth_secret_key app.register_blueprint(profiles_api, url_prefix="/profiles") app.register_blueprint(auth_api, url_prefix="/auth") + +# Endpoints +@app.route("/", methods=["GET"]) +def hello(): + return "Welcome Message" + +# Start the server (developement) +if __name__ == "__main__": + app.run("localhost", port=8080) #Testing on own computer + #app.run("0.0.0.0", port=8080) #Deploying \ No newline at end of file