From 023c77448be5a60855f8ef9d3f1a1c56841d7729 Mon Sep 17 00:00:00 2001 From: theng Date: Sat, 23 Oct 2021 03:39:24 +0800 Subject: [PATCH 01/18] Complete AuthAPI.py requirements --- Auth/AuthAPI.py | 55 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/Auth/AuthAPI.py b/Auth/AuthAPI.py index b903496..1186ec9 100644 --- a/Auth/AuthAPI.py +++ b/Auth/AuthAPI.py @@ -1,7 +1,60 @@ # Score API here -from flask import Blueprint +from flask import Blueprint, request, current_app, json, jsonify import sys from db import db +import pyjwt sys.path.append("../") auth_api = Blueprint("auth", __name__) + +credsArray = [] +username = request.arg.get("username") +passwordHash = request.arg.get("passwordHash") +token = jwt.encode({'userID': username, 'passwordHash': passwordHash}, current_app.config['SECRET_KEY'], algorithm="HS256") + +@auth_api.route('/register', methods=["POST"]) +def storeCredentials(): + credsArray.append({"username": username, "passwordHash": passwordHash}) + return jsonify({"message": "SUCCESS", "data": {"username": username, "hashedPassword": hashedPassword}}), 200 + + +@auth_api.route('/login', methods=["GET"]) +def loginSuccess(): + testUser = {"username": username, "passwordHash": passwordHash} + if (testUser in credsArray): + token + return jsonify({"message": "success", "token": token}), 200 + + elif (not(testUser in credsArray)): + return jsonify({"message": "failed"}), 401 + + + +try: + username + passwordHash +except ValueError: + print("No username or password input.") +except: + print("An error occurred.") + +@auth_api.route('/login', methods=["GET"]) +def authToken(): + testtoken = request.arg.get("token") + data = jwt.decode(token, current_app.config['SECRET_KEY'], algorithms=["HS256"]) + if (testtoken == "sdlkaskdnalsdnsald"): + if (data in credsArray): + return jsonify({"message": "success"}), 200 + elif (not(data in credsArray)): + return jsonify({"message": "failed"}), 401 + + elif (not(testtoken == "sdlkaskdnalsdnsald")): + return jsonify({"message": "failed"}), 401 + + currentUser = credsArray.User.find_one({'userID': data['userID'], 'passwordHash': data['passwordHash']}) + +jsonify({'token': token}), 200 + + + + From 581e91e5dcb35fd470eab4174526cc3532b6a16e Mon Sep 17 00:00:00 2001 From: theng Date: Sat, 23 Oct 2021 03:39:55 +0800 Subject: [PATCH 02/18] Complete ProfilesAPI.py requirements --- Profiles/ProfilesAPI.py | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/Profiles/ProfilesAPI.py b/Profiles/ProfilesAPI.py index 4467047..ff81dda 100644 --- a/Profiles/ProfilesAPI.py +++ b/Profiles/ProfilesAPI.py @@ -1,7 +1,38 @@ # 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 getProfile(): + NameScore = db[id] + return jsonify({"message": "SUCCESS", "data": NameScore}), 200 + +@profiles_api.route('/profiles', methods=["POST"]) +def addProfile(): + name = request.args.get("name") + db.append({"name": name}) + return jsonify({"message": "SUCCESS"}), 200 + +@profiles_api.route('/', methods=["DELETE"]) +def deleteProfile(): + NameScore = db[id] + del NameScore + return jsonify({"message": "SUCCESS", "data": NameScore}), 200 + +@profiles_api.route('//score?minScore=', methods=["GET"]) +def getMinScore(): + minScore = request.args.get("minScore") + ScoreList = db[id].get("scores") + def aboveMinScore(i): + if i >= minScore: + return i + + ScoresAboveMin = list(filter(aboveMinScore, ScoreList)) + + return jsonify({"message": "SUCCESS", "data": ScoresAboveMin}), 200 + + From 24bf34401f538db6256065efb0c46008f2f7a7d5 Mon Sep 17 00:00:00 2001 From: theng Date: Sat, 23 Oct 2021 03:40:33 +0800 Subject: [PATCH 03/18] Edit for documentation --- README.md | 41 ++++++++++++++++------------------------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 08c35ed..f052347 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,20 @@ # 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. -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 + +GET / - Returns a welcome message at homepage + + In profiles API (/profiles prefix): + +* GET /{id} - retrieves the name and all scores of a profile +* POST /profiles - creates a new profile (name only) +* DELETE /{id} - deletes a profile +* GET /{id}/score?minScore= to retrieve all scores of a profile, above the minimum score + + In authentication API (/auth prefix): + +* POST /register - stores a username and hashedPassword (given as hashed) in a local array +* Login /login - checks if the provided information is valid and return a jwt token + success message if successful, else return a 401 error if failed + From 746d3cb61904481796a940b49b97aed971b57e06 Mon Sep 17 00:00:00 2001 From: theng Date: Sat, 23 Oct 2021 03:40:54 +0800 Subject: [PATCH 04/18] Complete main.py requirements --- main.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/main.py b/main.py index fc7fbd4..25b3477 100644 --- a/main.py +++ b/main.py @@ -2,11 +2,26 @@ from Profiles.ProfilesAPI import profiles_api from flask import Flask from db import db +from creds import * +from gevent.pywsgi import WSGIServer -# Write your flask code here app = Flask(__name__) +app.config['SECRET_KEY'] = AUTH_SECRET_KEY +app.config['PASSWORD_RESET_SECRET'] = AUTH_PASSWORD_RESET_SECRET +app.config['USERNAME'] = DB_USERNAME + +@app.route("/", methods=["GET"]) +def homepage(): + return "Welcome to ExamScore API." + app.register_blueprint(profiles_api, url_prefix="/profiles") app.register_blueprint(auth_api, url_prefix="/auth") + +if __name__ == "__main__": + app.run("localhost", port=1313) + + http_server = WSGIServer(("localhost", 1313), app) + http_server.serve_forever() From bb09d516b1df2f9fa1e56ff15f7b45ff4e5d0da0 Mon Sep 17 00:00:00 2001 From: theng Date: Sat, 4 Dec 2021 22:39:35 +0800 Subject: [PATCH 05/18] Comment out gevent code --- main.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/main.py b/main.py index 25b3477..0a25ca8 100644 --- a/main.py +++ b/main.py @@ -21,7 +21,8 @@ def homepage(): app.register_blueprint(auth_api, url_prefix="/auth") if __name__ == "__main__": - app.run("localhost", port=1313) + app.run("localhost", port=8080) - http_server = WSGIServer(("localhost", 1313), app) - http_server.serve_forever() + # Production + # http_server = WSGIServer(("0.0.0.0", 8080), app) + # http_server.serve_forever() From 0796acb67005551d5b7475bcbd08bc83bc479651 Mon Sep 17 00:00:00 2001 From: theng Date: Sun, 5 Dec 2021 03:16:23 +0800 Subject: [PATCH 06/18] Fix GET profile function --- Profiles/ProfilesAPI.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Profiles/ProfilesAPI.py b/Profiles/ProfilesAPI.py index ff81dda..9152545 100644 --- a/Profiles/ProfilesAPI.py +++ b/Profiles/ProfilesAPI.py @@ -7,16 +7,22 @@ profiles_api = Blueprint("profiles", __name__) @profiles_api.route('/', methods=["GET"]) -def getProfile(): - NameScore = db[id] - return jsonify({"message": "SUCCESS", "data": NameScore}), 200 +def getProfile(id): + try: + profile = db[id] + except IndexError: + return jsonify({"status": "fail", "message": "Profile not found."}) + + return jsonify({"status": "success", "data": profile}) + @profiles_api.route('/profiles', methods=["POST"]) def addProfile(): - name = request.args.get("name") + name = request.form() db.append({"name": name}) return jsonify({"message": "SUCCESS"}), 200 + @profiles_api.route('/', methods=["DELETE"]) def deleteProfile(): NameScore = db[id] From 782f6d71927bbc7f25a9dda03a5bd29d9c4229a1 Mon Sep 17 00:00:00 2001 From: theng Date: Sun, 5 Dec 2021 03:30:45 +0800 Subject: [PATCH 07/18] Fix POST profile function --- Profiles/ProfilesAPI.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Profiles/ProfilesAPI.py b/Profiles/ProfilesAPI.py index 9152545..39648c8 100644 --- a/Profiles/ProfilesAPI.py +++ b/Profiles/ProfilesAPI.py @@ -18,9 +18,10 @@ def getProfile(id): @profiles_api.route('/profiles', methods=["POST"]) def addProfile(): - name = request.form() - db.append({"name": name}) - return jsonify({"message": "SUCCESS"}), 200 + newProfile = request.get_json() + newProfile["scores"] = [] + db.append(newProfile) + return jsonify({"status": "success", "message": "New profile added."}) @profiles_api.route('/', methods=["DELETE"]) From 586b0d2caf42fac2f5b08c33a015755fb009bcc6 Mon Sep 17 00:00:00 2001 From: theng Date: Sun, 5 Dec 2021 03:34:33 +0800 Subject: [PATCH 08/18] Fix DELETE profile function --- Profiles/ProfilesAPI.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Profiles/ProfilesAPI.py b/Profiles/ProfilesAPI.py index 39648c8..29d666f 100644 --- a/Profiles/ProfilesAPI.py +++ b/Profiles/ProfilesAPI.py @@ -26,9 +26,13 @@ def addProfile(): @profiles_api.route('/', methods=["DELETE"]) def deleteProfile(): - NameScore = db[id] - del NameScore - return jsonify({"message": "SUCCESS", "data": NameScore}), 200 + try: + profile = db[id] + except IndexError: + return jsonify({"status": "fail", "message": "Profile not found."}) + + del profile + return jsonify({"message": "SUCCESS", "message": "Profile deleted."}) @profiles_api.route('//score?minScore=', methods=["GET"]) def getMinScore(): From ce870649934a1e4d299f15f2df61ffdbff6fe455 Mon Sep 17 00:00:00 2001 From: theng Date: Sun, 5 Dec 2021 03:40:28 +0800 Subject: [PATCH 09/18] Fix GET min. score function --- Profiles/ProfilesAPI.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Profiles/ProfilesAPI.py b/Profiles/ProfilesAPI.py index 29d666f..6580c87 100644 --- a/Profiles/ProfilesAPI.py +++ b/Profiles/ProfilesAPI.py @@ -34,16 +34,26 @@ def deleteProfile(): del profile return jsonify({"message": "SUCCESS", "message": "Profile deleted."}) -@profiles_api.route('//score?minScore=', methods=["GET"]) +@profiles_api.route('//score', methods=["GET"]) def getMinScore(): + try: + profile = db[id] + except IndexError: + return jsonify({"status": "fail", "message": "Profile not found."}) + minScore = request.args.get("minScore") - ScoreList = db[id].get("scores") + ScoreList = profile.get("scores") + if minScore == None: + minScore == 0 + else: + minScore == int(minScore) + def aboveMinScore(i): if i >= minScore: return i ScoresAboveMin = list(filter(aboveMinScore, ScoreList)) - return jsonify({"message": "SUCCESS", "data": ScoresAboveMin}), 200 + return jsonify({"status": "success", "scores": ScoresAboveMin}) From 628cf668759c172034b58c060ebae25da8aab3f1 Mon Sep 17 00:00:00 2001 From: theng Date: Sun, 5 Dec 2021 03:41:39 +0800 Subject: [PATCH 10/18] Change data key to profile on return of GET profile function --- Profiles/ProfilesAPI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Profiles/ProfilesAPI.py b/Profiles/ProfilesAPI.py index 6580c87..4c497ce 100644 --- a/Profiles/ProfilesAPI.py +++ b/Profiles/ProfilesAPI.py @@ -13,7 +13,7 @@ def getProfile(id): except IndexError: return jsonify({"status": "fail", "message": "Profile not found."}) - return jsonify({"status": "success", "data": profile}) + return jsonify({"status": "success", "profile": profile}) @profiles_api.route('/profiles', methods=["POST"]) From 67bb34b5d6d98db4e894dda7017a68fd83b9b497 Mon Sep 17 00:00:00 2001 From: theng Date: Sun, 5 Dec 2021 04:06:46 +0800 Subject: [PATCH 11/18] Change del to db.pop on DELETE profile function --- Profiles/ProfilesAPI.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Profiles/ProfilesAPI.py b/Profiles/ProfilesAPI.py index 4c497ce..17efc43 100644 --- a/Profiles/ProfilesAPI.py +++ b/Profiles/ProfilesAPI.py @@ -12,7 +12,7 @@ def getProfile(id): profile = db[id] except IndexError: return jsonify({"status": "fail", "message": "Profile not found."}) - + return jsonify({"status": "success", "profile": profile}) @@ -21,6 +21,7 @@ def addProfile(): newProfile = request.get_json() newProfile["scores"] = [] db.append(newProfile) + name = newProfile["name"] return jsonify({"status": "success", "message": "New profile added."}) @@ -31,8 +32,8 @@ def deleteProfile(): except IndexError: return jsonify({"status": "fail", "message": "Profile not found."}) - del profile - return jsonify({"message": "SUCCESS", "message": "Profile deleted."}) + db.pop(id) + return jsonify({"message": "success", "message": "Profile deleted."}) @profiles_api.route('//score', methods=["GET"]) def getMinScore(): From 3fcb64aefe9333b8c4b34840fe2f674cb25faa21 Mon Sep 17 00:00:00 2001 From: theng Date: Sun, 5 Dec 2021 04:12:13 +0800 Subject: [PATCH 12/18] Remove name variable on addProfile() --- Profiles/ProfilesAPI.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Profiles/ProfilesAPI.py b/Profiles/ProfilesAPI.py index 17efc43..7ae5de4 100644 --- a/Profiles/ProfilesAPI.py +++ b/Profiles/ProfilesAPI.py @@ -21,7 +21,6 @@ def addProfile(): newProfile = request.get_json() newProfile["scores"] = [] db.append(newProfile) - name = newProfile["name"] return jsonify({"status": "success", "message": "New profile added."}) From d464cb66fd64ee84494025e125b85ec0b0ec256b Mon Sep 17 00:00:00 2001 From: theng Date: Sun, 5 Dec 2021 04:13:28 +0800 Subject: [PATCH 13/18] Fix endpoint on addProfile() --- Profiles/ProfilesAPI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Profiles/ProfilesAPI.py b/Profiles/ProfilesAPI.py index 7ae5de4..352a276 100644 --- a/Profiles/ProfilesAPI.py +++ b/Profiles/ProfilesAPI.py @@ -16,7 +16,7 @@ def getProfile(id): return jsonify({"status": "success", "profile": profile}) -@profiles_api.route('/profiles', methods=["POST"]) +@profiles_api.route('/', methods=["POST"]) def addProfile(): newProfile = request.get_json() newProfile["scores"] = [] From fe54ecbf85a72318924365832ee42a330c591e65 Mon Sep 17 00:00:00 2001 From: theng Date: Sun, 5 Dec 2021 06:20:53 +0800 Subject: [PATCH 14/18] Add status code 200 --- Profiles/ProfilesAPI.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Profiles/ProfilesAPI.py b/Profiles/ProfilesAPI.py index 352a276..d7454a7 100644 --- a/Profiles/ProfilesAPI.py +++ b/Profiles/ProfilesAPI.py @@ -13,7 +13,7 @@ def getProfile(id): except IndexError: return jsonify({"status": "fail", "message": "Profile not found."}) - return jsonify({"status": "success", "profile": profile}) + return jsonify({"status": "success", "profile": profile}), 200 @profiles_api.route('/', methods=["POST"]) @@ -21,7 +21,7 @@ def addProfile(): newProfile = request.get_json() newProfile["scores"] = [] db.append(newProfile) - return jsonify({"status": "success", "message": "New profile added."}) + return jsonify({"status": "success", "message": "New profile added."}), 200 @profiles_api.route('/', methods=["DELETE"]) @@ -32,7 +32,7 @@ def deleteProfile(): return jsonify({"status": "fail", "message": "Profile not found."}) db.pop(id) - return jsonify({"message": "success", "message": "Profile deleted."}) + return jsonify({"message": "success", "message": "Profile deleted."}), 200 @profiles_api.route('//score', methods=["GET"]) def getMinScore(): @@ -54,6 +54,6 @@ def aboveMinScore(i): ScoresAboveMin = list(filter(aboveMinScore, ScoreList)) - return jsonify({"status": "success", "scores": ScoresAboveMin}) + return jsonify({"status": "success", "scores": ScoresAboveMin}), 200 From d5be8c0d336c863b49f55c8e24d98afe18cee4fe Mon Sep 17 00:00:00 2001 From: theng Date: Sun, 5 Dec 2021 06:23:16 +0800 Subject: [PATCH 15/18] Remove unwanted environmental variables --- main.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/main.py b/main.py index 0a25ca8..9774b3f 100644 --- a/main.py +++ b/main.py @@ -10,8 +10,6 @@ app = Flask(__name__) app.config['SECRET_KEY'] = AUTH_SECRET_KEY -app.config['PASSWORD_RESET_SECRET'] = AUTH_PASSWORD_RESET_SECRET -app.config['USERNAME'] = DB_USERNAME @app.route("/", methods=["GET"]) def homepage(): From b323f093eb8f62c5990287d9eda43517d92fb196 Mon Sep 17 00:00:00 2001 From: theng Date: Sun, 5 Dec 2021 06:38:06 +0800 Subject: [PATCH 16/18] Fix AuthAPI --- Auth/AuthAPI.py | 98 ++++++++++++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 41 deletions(-) diff --git a/Auth/AuthAPI.py b/Auth/AuthAPI.py index 1186ec9..64151b2 100644 --- a/Auth/AuthAPI.py +++ b/Auth/AuthAPI.py @@ -1,59 +1,75 @@ # Score API here from flask import Blueprint, request, current_app, json, jsonify -import sys +import sys, jwt +from creds import * from db import db -import pyjwt sys.path.append("../") auth_api = Blueprint("auth", __name__) credsArray = [] -username = request.arg.get("username") -passwordHash = request.arg.get("passwordHash") -token = jwt.encode({'userID': username, 'passwordHash': passwordHash}, current_app.config['SECRET_KEY'], algorithm="HS256") +secretkey = current_app.config['SECRET_KEY'] @auth_api.route('/register', methods=["POST"]) -def storeCredentials(): - credsArray.append({"username": username, "passwordHash": passwordHash}) - return jsonify({"message": "SUCCESS", "data": {"username": username, "hashedPassword": hashedPassword}}), 200 +def Register(): + newCred = request.get_json() + # check if username is provided + try: + username = newCred["username"] + except KeyError: + return jsonify({"status": "fail", "message": "No username."}) + + # check if password is provided + try: + passwordHash = newCred["passwordHash"] + except KeyError: + return jsonify({"status": "fail", "message": "No password."}) + credsArray.append(newCred) -@auth_api.route('/login', methods=["GET"]) -def loginSuccess(): - testUser = {"username": username, "passwordHash": passwordHash} - if (testUser in credsArray): - token - return jsonify({"message": "success", "token": token}), 200 - - elif (not(testUser in credsArray)): - return jsonify({"message": "failed"}), 401 + return jsonify({"status": "success", "message": "Credentials successfully registered."}), 200 - -try: - username - passwordHash -except ValueError: - print("No username or password input.") -except: - print("An error occurred.") - -@auth_api.route('/login', methods=["GET"]) -def authToken(): - testtoken = request.arg.get("token") - data = jwt.decode(token, current_app.config['SECRET_KEY'], algorithms=["HS256"]) - if (testtoken == "sdlkaskdnalsdnsald"): - if (data in credsArray): - return jsonify({"message": "success"}), 200 - elif (not(data in credsArray)): - return jsonify({"message": "failed"}), 401 - - elif (not(testtoken == "sdlkaskdnalsdnsald")): - return jsonify({"message": "failed"}), 401 - - currentUser = credsArray.User.find_one({'userID': data['userID'], 'passwordHash': data['passwordHash']}) +@auth_api.route('/login', methods=["POST"]) +def Login(): + def checkCred(givenCred): + # check if username is provided + try: + username = givenCred["username"] + except KeyError: + return jsonify({"status": "fail", "message": "No username."}) + + # check if password is provided + try: + passwordHash = givenCred["passwordHash"] + except KeyError: + return jsonify({"status": "fail", "message": "No password."}) + for i in credsArray: + if (username == i["username"] and passwordHash == i["passwordHash"]): + token = jwt.encode({"userID": username, "passwordHash": passwordHash}, secretkey, algorithm="HS256") + return jsonify({"status": "success", "token": token}), 200 + else: + return jsonify({"status": "fail", "message": "Authentication failed."}), 401 -jsonify({'token': token}), 200 + givenCred = request.get_json() + token = request.arg.get("token") + + + def checkToken(): + if (token != None): + try: + data = jwt.decode(token, secretkey, algorithm=["HS256"]) + return checkCred(data) + except: + data = givenCred + try: + return checkToken(data) + except: + return jsonify({"status": "fail", "message": "Bad token"}) + + # no token provided in URL argument (fresh login) + elif (token == None): + return checkCred(givenCred) From b83a60d33bfbb5c94ecd4bf4680c9b7ca2c9c82c Mon Sep 17 00:00:00 2001 From: theng Date: Sun, 5 Dec 2021 06:40:33 +0800 Subject: [PATCH 17/18] Add documentation --- Documentation.md | 265 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 Documentation.md diff --git a/Documentation.md b/Documentation.md new file mode 100644 index 0000000..b621291 --- /dev/null +++ b/Documentation.md @@ -0,0 +1,265 @@ +# Simulated ExamScore API Documentation + +## Profile API + +1. **GET** /profiles/ + + - **Description:** To retrieve the information (name and score) of a profile. + + - **Function used:** getProfile() + + - **Source:** /Profiles/ProfilesAPI.py (Line 9) + + - **Parameter(s):** + + - ```id``` (required, must be an integer), the ID of the desired profile. + + - **Request body:** None, only parameter on endpoint needs to be provided. + + - **Response(s):** + + - Success (200) + + ```python + { + "status": "success", + "profile": + {"name": "Nobel", + "scores": [1, 2, 3, 4, 5] + } + } + ``` + + - Fail + + ```python + { + "status": "fail", + "message": "Profile not found." + } + ``` + +2. **POST** /profiles/ + + - **Description:** To add a new profile into the database. + + - **Function used:** addProfile() + + - **Source:** /Profiles/ProfilesAPI.py (Line 19) + + - **Parameter(s):** None + + - **Request body:** + + ```python + { + "name": "string" + } + ``` + + - **Response(s):** + + - Success (200) + + ```python + { + "status": "success", + "message": "New profile added." + } + ``` + + - Fail + + ```python + { + "status": "fail", + "message": "Profile not found." + } + ``` + +3. **DELETE** /profiles/ + + - **Description:** To remove an existing profile from the database. + + - **Function used:** deleteProfile() + + - **Source:** /Profiles/ProfilesAPI.py (Line 27) + + - **Parameter(s):** + + - ```id``` (required, must be an integer), the ID of the desired profile. + + - **Request body:** None, only parameter on endpoint needs to be provided. + + - **Response(s):** + + - Success (200) + + ```python + { + "status": "success", + "message": "Profile deleted." + } + ``` + + - Fail + + ```python + { + "status": "fail", + "message": "Profile not found." + } + ``` + +4. **GET** /profiles//score + + - **Description:** To retrieve the scores of a profile which are greater or equal to the minimum score provided by the requester. + + - **Function used:** getMinScore() + + - **Source:** /Profiles/ProfilesAPI.py (Line 37) + + - **Parameter(s):** + + - ```id``` (required, must be an integer), the ID of the desired profile. + - ```minScore``` (optional, must be an integer), the minimum score, given as an argument. + + - **Request body:** None, only parameter on endpoint needs to be provided. + + - **Response(s):** + + - Success (200) + + ```python + { + "status": "success", + "scores": [3, 4, 5] + } + ``` + + - Fail + + ```python + { + "status": "fail", + "message": "Profile not found." + } + ``` + +## Authentication API + +1. **POST** /auth/register + + - **Description:** To register a new credential for API access. + + - **Function used:** Register() + + - **Source:** /Auth/AuthAPI.py (Line ) + + - **Parameter(s):** None + + - **Request body:** + + ```python + { + "username": "string" + "passwordHash": "string" + } + ``` + + - **Response(s):** + + - Success (200) + + ```python + { + "status": "success", + "message": "Credentials successfully registered." + } + ``` + + - Fail (no username provided) + + ```python + { + "status": "fail", + "message": "No username." + } + ``` + + - Fail (no password [hash] provided) + + ```python + { + "status": "fail", + "message": "No password." + } + ``` + +2. **POST** /auth/login + + - **Description:** To authorise a credential holder to access the API. + + - **Function used:** Login() + + - **Source:** /Auth/AuthAPI.py (Line ) + + - **Parameter(s):** None + + - **Request body:** + + ```python + { + "username": "string" + "passwordHash": "string" + } + ``` + + - **Response(s):** + + - Success (200) + + ```python + { + "status": "success", + "message": "Login successful." + } + ``` + + - Fail (401 Not authenticated) + + ```python + { + "status": "fail", + "message": "Authentication failed." + } + ``` + + - Fail (No username provided) + + ```python + { + "status": "fail", + "message": "No username." + } + ``` + + - Fail (No password provided) + + ```python + { + "status": "fail", + "message": "No password." + } + ``` + + - Fail (bad token) + + ```python + { + "status": "fail", + "message": "Bad token" + } + ``` + +​ From 47b7bfc07b274e9c8d72511e77a2cc6d8aecb066 Mon Sep 17 00:00:00 2001 From: theng Date: Sun, 5 Dec 2021 06:46:40 +0800 Subject: [PATCH 18/18] Edit documentation --- Documentation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation.md b/Documentation.md index b621291..50ebe21 100644 --- a/Documentation.md +++ b/Documentation.md @@ -154,7 +154,7 @@ - **Function used:** Register() - - **Source:** /Auth/AuthAPI.py (Line ) + - **Source:** /Auth/AuthAPI.py (Line 13) - **Parameter(s):** None @@ -202,7 +202,7 @@ - **Function used:** Login() - - **Source:** /Auth/AuthAPI.py (Line ) + - **Source:** /Auth/AuthAPI.py (Line 33) - **Parameter(s):** None