Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 38 additions & 1 deletion Auth/AuthAPI.py
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})
Copy link
Owner

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

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")
Copy link
Owner

Choose a reason for hiding this comment

The 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)})
40 changes: 39 additions & 1 deletion Profiles/ProfilesAPI.py
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]}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens when id is not valid

Copy link
Owner

Choose a reason for hiding this comment

The 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})

3 changes: 3 additions & 0 deletions db.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@
"name": "Hui Hui",
"scores": [9, 29, 34]
}]
AUTH_SECRET_KEY = 'bananabonkers'

credentials = []
8 changes: 8 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Owner

Choose a reason for hiding this comment

The 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

211 changes: 211 additions & 0 deletions something.md
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"
}
```