-
Notifications
You must be signed in to change notification settings - Fork 13
Completed hw #12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Completed hw #12
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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") | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great job here |
||
| 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)}) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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("/<int:id>", methods=['GET', 'DELETE']) | ||
| def get_details(id): | ||
| try: | ||
| if request.method == 'GET': | ||
| return {"Status": "Success", "Data": db[id]} | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens when id is not valid
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens when id is not valid |
||
| 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("/<int:id>/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}) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,3 +9,6 @@ | |
| "name": "Hui Hui", | ||
| "scores": [9, 29, 34] | ||
| }] | ||
| AUTH_SECRET_KEY = 'bananabonkers' | ||
|
|
||
| credentials = [] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This does not do anything. Please look into the correct way to start the app on the notes. app.run is correct but needs more arguments |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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/\<int:id\> | ||
|
|
||
| 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/\<int:id\> | ||
|
|
||
| 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/\<int:id\>/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" | ||
| } | ||
| ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Defensive programming: Check that input is not "" or None to ensure that its a valid input