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 f47262d..edc05e0 100644 Binary files a/Profiles/__pycache__/ProfilesAPI.cpython-38.pyc and b/Profiles/__pycache__/ProfilesAPI.cpython-38.pyc differ diff --git a/__pycache__/db.cpython-38.pyc b/__pycache__/db.cpython-38.pyc index 1970f42..808267e 100644 Binary files a/__pycache__/db.cpython-38.pyc and b/__pycache__/db.cpython-38.pyc differ diff --git a/db.py b/db.py index 777200b..d75f18d 100644 --- a/db.py +++ b/db.py @@ -1,4 +1,7 @@ # Simulated db + + + db = [{ "name": "Nobel", "scores": [1, 2, 3, 4, 5] @@ -9,3 +12,10 @@ "name": "Hui Hui", "scores": [9, 29, 34] }] + +credentials = [] + +auth_secret_key = "425j2jkjdjfk3*38bjb3#*@!)Buibidj2j90$(Tbuiwurbirbjkkjbfkjadkjsf" + + + diff --git a/documentation.md b/documentation.md new file mode 100644 index 0000000..71f6971 --- /dev/null +++ b/documentation.md @@ -0,0 +1,183 @@ +# RHDEV-BE-2-flask Documentation +1. GET / + + Get a welcome message. + + **Function used**: hello() + **Source**: /**main.py (line 18)** + *** + **Parameters**: None + *** + **Reponse**: Welcome Message + *** + **Example**: / + ``` + Welcome! + ``` + +2. GET /profiles/\ + + 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