diff --git a/Auth/AuthAPI.py b/Auth/AuthAPI.py index b903496..d5041d2 100644 --- a/Auth/AuthAPI.py +++ b/Auth/AuthAPI.py @@ -1,7 +1,44 @@ -# Score API here from flask import Blueprint +from flask import request, jsonify, current_app import sys from db import db +from db import credentials +import jwt sys.path.append("../") auth_api = Blueprint("auth", __name__) + +@auth_api.route('/register', methods=['POST']) +def register(): + username = request.args.get('username') + pw = request.args.get('passwordHash') + credentials.append({"username": username, "passwordHash": pw}) + return jsonify({'Status': 'Success', 'Message': 'Successfully registered'}) + +@auth_api.route('/login', methods=['POST']) +def login(): + try: + token = request.args.get('token') + if token != None: + try: + user_details = jwt.decode(token, current_app.config['SECRET_KEY'], algorithms="HS256") + except jwt.InvalidSignatureError: + return jsonify({'Status':'Failed', 'Message': 'Invalid token'}) + if user_details in credentials: + return jsonify({'Status':'Success', 'Message': 'Login Successful'}) + else: + return jsonify({'Status':'Failed', 'Message': 'Wrong username or password'}) + + username = request.form.get('username') + pw = request.form.get('passwordHash') + user = { + "username": username, + "passwordHash": pw + } + if user in credentials: + new_token = jwt.encode(user, current_app.config['SECRET_KEY'], algorithm="HS256") + return jsonify({'Status': 'Success', 'token': new_token}) + else: + return jsonify({"Status": "Failed", 'Message': 'Wrong username or password'}) + except Exception as e: + return jsonify({'Status': 'Failed', 'Message':str(e)}) diff --git a/Profiles/ProfilesAPI.py b/Profiles/ProfilesAPI.py index 4467047..22a664e 100644 --- a/Profiles/ProfilesAPI.py +++ b/Profiles/ProfilesAPI.py @@ -1,7 +1,45 @@ -# Profile API here from flask import Blueprint +from flask import Blueprint, jsonify +from flask import request import sys from db import db sys.path.append("../") profiles_api = Blueprint("profiles", __name__) + +@profiles_api.route("/", methods=['GET', 'DELETE']) +def get_details(id): + try: + if request.method == 'GET': + return {"Status": "Success", "Data": db[id]} + else: + temp = db[id] + del db[id] + return jsonify({"Status": "Success", "Deleted": temp}) + except Exception as e: + return jsonify({'Status': 'Failed', "Error": e}) + +@profiles_api.route("/", methods=['POST']) + + +def add_details(): + try: + name = request.form.get('name') + + + db.append({"name": name}) + return jsonify({"Status": "Success", 'Added': db[-1]}) + except Exception as e: + return jsonify({'Status': 'Failed', "Error": e}) + +@profiles_api.route("//score", methods=['GET']) +def get_min_score(id): + try: + min_score = request.form.get('minScore') + display_details = db[id].copy() + if min_score != None: + display_details["scores"] = list(filter(lambda score: score > int(min_score), display_details["scores"])) + return jsonify({'Status': 'Success', 'Data': display_details['scores']}) + except Exception as e: + return jsonify({'Status': 'Failed', "Error": e}) + diff --git a/db.py b/db.py index 777200b..3dd0999 100644 --- a/db.py +++ b/db.py @@ -9,3 +9,6 @@ "name": "Hui Hui", "scores": [9, 29, 34] }] +AUTH_SECRET_KEY = 'bananabonkers' + +credentials = [] \ No newline at end of file diff --git a/main.py b/main.py index fc7fbd4..5743a1c 100644 --- a/main.py +++ b/main.py @@ -2,11 +2,19 @@ from Profiles.ProfilesAPI import profiles_api from flask import Flask from db import db +from db import * # 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") + +@app.route("/") +def hello_world(): + return "Welcome to the database!" + +app.run \ No newline at end of file diff --git a/something.md b/something.md new file mode 100644 index 0000000..d75f9b4 --- /dev/null +++ b/something.md @@ -0,0 +1,211 @@ + RHDEV-BE-2-flask +Homewwork template for BE training lesson 2: Flask and web servers + +Setup a basic API to simulate a website that tracks profiles and scores for exams + +A simulated db is provided. Note that the db will not be updated between runs + In main: +GET / homepage that returns a welcome message + In profiles API (/profiles prefix) +GET /{id} to retrieve the name and all scores of a profile +POST /profiles to create a new profile (name only) +DELETE /{id} to delete a profile +GET /{id}/score?minScore= to retrieve all scores of a profile, above the min score + In authentication API (/auth prefix) +POST /register stores a username and hashedPassword (given as hashed) +Store it in a local array +Login /login checks if the provided information is valid and return a jwt token + success message + +Give a reasonable return format with appropriate status code and messages. +{“message” : “success/fail”, “data”:””} +Also submit a simplified documentation of your API. You can use the format below. + + + +OPTIONALS: +Add environmental variables into the system (for jwt signing secret) +In the login route, check if jwt token is provided and valid +Assume URL argument has token “?token=sdlkaskdnalsdnsald” +See if username and password field arre present +# RHDEV-BE-2-flask Documentation +1. GET / + + Get a welcome message. + + **Function used**: hello_world() + **Source**: /**main.py (line 17)** + *** + **Parameters**: None + *** + **Reponse**: Welcome message + *** + **Example**: / + ``` + Welcome to the database! + ``` + +2. GET /profiles/\ + + Get the name and scores of the profile based on a given ID. + + **Function used**: get_details() + **Source**: /**ProfilesAPI.py (line 11)** + *** + **Parameters**: None + *** + **Response**: JSON object + *** + **Example**: /profiles/1 + ``` json + { + "Data": { + "name": "Richard", + "scores": [ + 5, + 4, + 3, + 2, + 1 + ] + }, + "Status": "Success" + } + ``` +3. POST /profiles/profiles + + Create a new profile with a name only. + + **Function used**: add_details() + **Source**: /**ProfilesAPI.py (line 25)** + *** + **Parameters**: + + name (required) + + Name of profile added + *** + **Response**: String of Response + *** + **Example**: /profiles/profiles + ```json + { + "Added": { + "name": "Govin" + }, + "Status": "Success" + } + ``` + + Otherwise, errors will be given back to user accordingly + +4. DELETE /profiles/\ + + Delete a profile based on the id given. + + **Function used**: get_details() + **Source**: /**ProfilesAPI.py (line 11)** + *** + **Parameters**: None + *** + **Response**: String of response + *** + **Example**: /profiles/1 + ```json + { + "Deleted": { + "name": "Richard", + "scores": [ + 5, + 4, + 3, + 2, + 1 + ] + }, + "Status": "Success" + } + ``` + Otherwise, errors will be given back to user accordingly + +4. GET /profiles/\/score + + Get all of the scores of a profile above a specified minimum score. + + **Function used**: get_min_score() + **Source**: /**ProfilesAPI.py (line 36)** + *** + **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, errors will be given back to user accordingly +6. POST /auth/register + + Stores a username and a hashed password in a list of credentials. + + **Function used**: register() + **Source**: /**AuthAPI.py (line 12)** + *** + **Parameters**: + + username (Required) + + Username of user to register + + passwordHash (Required) + + Password of user + *** + **Response**: String of response + *** + **Example**: /auth/register?username=govin&passwordHash=abcde123 + ```json + { + "Message": "Successfully registered", + "Status": "Success" + } + ``` +7. POST /auth/login + + Checks if credentials are of registered users. + + **Function used**: register() + **Source**: /**AuthAPI.py (line 19)** + *** + **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=govin&passwordHash=abcde123 + ```json + { + "Status": "Success", + "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6Imp1c3RpbiIsInBhc3N3b3JkSGFzaCI6ImFiY2RlZmcxMjMifQ.X7VZq1-kMeyA8UDIFD_pvR5-sKrMR9YLXHVPwEuReek" + } + ``` \ No newline at end of file