From ace117a5326935ab615ee2003c86bd76504511f3 Mon Sep 17 00:00:00 2001 From: Oluwasanya Olaoluwa Date: Sat, 15 Jun 2024 22:23:46 +1000 Subject: [PATCH 1/8] Update requirements.txt for production --- tracknow/backend/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/tracknow/backend/requirements.txt b/tracknow/backend/requirements.txt index 8e8f6fc..c3efd6b 100644 --- a/tracknow/backend/requirements.txt +++ b/tracknow/backend/requirements.txt @@ -17,6 +17,7 @@ packaging==24.1 pluggy==1.5.0 psycopg2-binary==2.9.9 PyJWT==2.8.0 +gunicorn pytest==8.2.2 python-decouple==3.8 python-dotenv==1.0.1 From 6cde010929a1634cb225515f7f074634c4b2844e Mon Sep 17 00:00:00 2001 From: vantage-ola Date: Sun, 16 Jun 2024 19:06:46 +0100 Subject: [PATCH 2/8] fix swagger cors error. --- tracknow/backend/app.py | 2 ++ tracknow/backend/requirements.txt | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tracknow/backend/app.py b/tracknow/backend/app.py index 9d63608..a71b12e 100644 --- a/tracknow/backend/app.py +++ b/tracknow/backend/app.py @@ -4,6 +4,7 @@ from flask_migrate import Migrate from flask_jwt_extended import JWTManager, jwt_required, create_access_token, get_jwt_identity from flask_swagger_ui import get_swaggerui_blueprint +from flask_cors import CORS # swagger setup SWAGGER_URL="/api/v1/docs" @@ -19,6 +20,7 @@ def create_app(config_class='config.Config'): app = Flask(__name__) + CORS(app) app.config.from_object(config_class) db.init_app(app) diff --git a/tracknow/backend/requirements.txt b/tracknow/backend/requirements.txt index c3efd6b..686ce6b 100644 --- a/tracknow/backend/requirements.txt +++ b/tracknow/backend/requirements.txt @@ -3,11 +3,13 @@ blinker==1.8.2 click==8.1.7 exceptiongroup==1.2.1 Flask==3.0.3 +Flask-Cors==4.0.1 Flask-JWT-Extended==4.6.0 Flask-Migrate==4.0.7 Flask-SQLAlchemy==3.1.1 flask-swagger-ui==4.11.1 greenlet==3.0.3 +gunicorn==22.0.0 iniconfig==2.0.0 itsdangerous==2.2.0 Jinja2==3.1.4 @@ -17,7 +19,6 @@ packaging==24.1 pluggy==1.5.0 psycopg2-binary==2.9.9 PyJWT==2.8.0 -gunicorn pytest==8.2.2 python-decouple==3.8 python-dotenv==1.0.1 From 8189544e312b928d113bf171c756fe11f0c3f286 Mon Sep 17 00:00:00 2001 From: vantage-ola Date: Sun, 16 Jun 2024 19:12:22 +0100 Subject: [PATCH 3/8] +https --- tracknow/backend/static/swagger.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracknow/backend/static/swagger.json b/tracknow/backend/static/swagger.json index 3189c95..258d4f0 100644 --- a/tracknow/backend/static/swagger.json +++ b/tracknow/backend/static/swagger.json @@ -7,7 +7,7 @@ }, "basePath": "/api/v1", "schemes": [ - "http" + "https" ], "paths": { "/hello": { From 3ade7b95279ff8e6b39221308f627ff6ea172605 Mon Sep 17 00:00:00 2001 From: vantage-ola Date: Mon, 24 Jun 2024 17:26:30 +0100 Subject: [PATCH 4/8] refactor, move to routes page. --- tracknow/backend/app.py | 149 ++----------------------------------- tracknow/backend/routes.py | 136 +++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 143 deletions(-) create mode 100644 tracknow/backend/routes.py diff --git a/tracknow/backend/app.py b/tracknow/backend/app.py index a71b12e..6a83a2f 100644 --- a/tracknow/backend/app.py +++ b/tracknow/backend/app.py @@ -1,10 +1,10 @@ -from flask import Flask, request, jsonify, url_for +from flask import Flask from error_handle import * -from models import db, User, Laptime +from models import db from flask_migrate import Migrate -from flask_jwt_extended import JWTManager, jwt_required, create_access_token, get_jwt_identity +from flask_jwt_extended import JWTManager from flask_swagger_ui import get_swaggerui_blueprint -from flask_cors import CORS +from routes import routes # swagger setup SWAGGER_URL="/api/v1/docs" @@ -20,7 +20,6 @@ def create_app(config_class='config.Config'): app = Flask(__name__) - CORS(app) app.config.from_object(config_class) db.init_app(app) @@ -38,146 +37,10 @@ def create_app(config_class='config.Config'): app.register_error_handler(500, handle_internal_server_error) app.register_error_handler(503, handle_service_unavailable) app.register_blueprint(swagger_ui_blueprint, url_prefix=SWAGGER_URL) - - # Hello :) - @app.route('/api/v1/hello', methods=['GET']) - def index(): - return jsonify({"msg": 'Track Now...'}) - - # Create a new user with username and password. - @app.route('/api/v1/users', methods=['POST']) - def new_user(): - new_user = request.get_json() - # { "username" : "your_username", - # "password" : "your_password"} - if new_user['username'] is None or new_user['password'] is None: - return jsonify({"msg" : "Missing requiring fields"}), 400 - - if User.query.filter_by(username=new_user['username']).first() is not None: - return jsonify({"msg" : "User Exists"}), 400 - - user = User(username=new_user['username']) # nationality=new_user['nationality'] - user.hash_password(new_user['password']) - - db.session.add(user) - db.session.commit() - - return (jsonify({'username': user.username}), 201, - {'Location': url_for('get_user', id=user.id, _external=True)}) - - # Login to tracknow with username and password. - @app.route('/api/v1/login', methods=['POST']) - def login_user(): - login_user = request.get_json() - user = User.query.filter_by(username=login_user['username']).first() - # check if user and correct password exists, create a jwt token if successful - if user and user.verify_password(login_user['password']): - access_token = create_access_token(identity=user.id) - return jsonify({'msg': 'Login Sucesss', 'token': access_token}) - else: - return jsonify({'msg': 'Login Failed'}), 401 - - # Route to check someone on the database. - @app.route('/api/v1/users/', methods=['GET']) - @jwt_required() - def get_user(id): - user = User.query.get(id) - if not user: - return jsonify({'msg': "User does not exist."}) - return jsonify({'username': user.username}) - - # Route to list all users - @app.route('/api/v1/users', methods=['GET']) - def get_users(): - users = User.query.filter_by().all() - return jsonify([u.to_dict() for u in users]), 200 - - # Route to check if we are logged in with our unique jwt token. - @app.route('/api/v1/protected', methods=['GET']) - # Include bearer token from login_user() to verify we are logged in and are in session. - @jwt_required() - def get_identity(): - user_id = get_jwt_identity() - user = User.query.filter_by(id=user_id).first() - - # Check if user exists - if user: - return jsonify({'message': 'User found', 'name': user.username}) - else: - return jsonify({'message': 'User not found'}), 404 - - # Logged in user adds laptime. - @app.route('/api/v1/user/laptimes', methods=['POST']) - @jwt_required() - def add_laptime(): - user_id = get_jwt_identity() - loggedin_user = User.query.filter_by(id=user_id).first() - - laptime_data = request.get_json() - - car = laptime_data['car'] - track = laptime_data['track'] - time = laptime_data['time'] - simracing = laptime_data['simracing'] - platform = laptime_data['platform'] - youtube_link = laptime_data['youtube_link'] - comment = laptime_data['comment'] - - if not car or not track or not time: - return jsonify({'msg': 'Missing required fields'}), 400 - - laptime = Laptime( - user_id=user_id, - car=car, - track=track, - time=time, - simracing=simracing, - platform=platform, - youtube_link=youtube_link, - comment=comment - ) - - db.session.add(laptime) - db.session.commit() - - return jsonify({"Laptime Added Successfully": laptime.to_dict(), "by": loggedin_user.username}), 201 - - # Logged in user gets all the laptimes they posted on tracknow. - @app.route('/api/v1/user/laptimes', methods=['GET']) - @jwt_required() - def get_user_laptimes(): - user_id = get_jwt_identity() - laptimes = Laptime.query.filter_by(user_id=user_id).all() - - return jsonify([lt.to_dict() for lt in laptimes]), 200 - - # Logged in user gets one laptime they selected. - @app.route('/api/v1/user/laptimes/', methods=['GET']) - @jwt_required() - def get_user_laptime(id): - user_id = get_jwt_identity() - laptime = Laptime.query.filter_by(id=id, user_id=user_id).first() - return jsonify(laptime.to_dict()), 200 - - # Global - get all laptimes posted around the world. - @app.route('/api/v1/laptimes', methods=['GET']) - def get_laptimes(): - - laptimes = Laptime.query.filter_by().all() - - return jsonify([lt.to_dict() for lt in laptimes]), 200 - - # Global - get one laptime selected. - @app.route('/api/v1/laptimes/', methods=['GET']) - @jwt_required() - def get_laptime(id): - - laptime = Laptime.query.filter_by(id=id).first() - return jsonify(laptime.to_dict()), 200 - + app.register_blueprint(routes) # Register the routes blueprint return app if __name__ == '__main__': app = create_app() - app.run(debug = True) + app.run(debug=True) diff --git a/tracknow/backend/routes.py b/tracknow/backend/routes.py new file mode 100644 index 0000000..4ff1f59 --- /dev/null +++ b/tracknow/backend/routes.py @@ -0,0 +1,136 @@ +from flask import Blueprint, request, jsonify, url_for +from flask_jwt_extended import jwt_required, create_access_token, get_jwt_identity +from models import db, User, Laptime + +routes = Blueprint('routes', __name__) + +# Hello :) +@routes.route('/api/v1/hello', methods=['GET']) +def index(): + return jsonify({"msg": 'Track Now...'}) + +# Create a new user with username and password. +@routes.route('/api/v1/users', methods=['POST']) +def new_user(): + new_user = request.get_json() + # { "username" : "your_username", + #"password" : "your_password"} + if new_user['username'] is None or new_user['password'] is None: + return jsonify({"msg": "Missing required fields"}), 400 + + if User.query.filter_by(username=new_user['username']).first() is not None: + return jsonify({"msg": "User Exists"}), 400 + + user = User(username=new_user['username']) + user.hash_password(new_user['password']) + + db.session.add(user) + db.session.commit() + + return (jsonify({'username': user.username}), 201, + {'Location': url_for('routes.get_user', id=user.id, _external=True)}) + +# Login to tracknow with username and password. +@routes.route('/api/v1/login', methods=['POST']) +def login_user(): + login_user = request.get_json() + user = User.query.filter_by(username=login_user['username']).first() + if user and user.verify_password(login_user['password']): + access_token = create_access_token(identity=user.id) + return jsonify({'msg': 'Login Success', 'token': access_token}) + else: + return jsonify({'msg': 'Login Failed'}), 401 + +# Route to check someone on the database. +@routes.route('/api/v1/users/', methods=['GET']) +@jwt_required() +def get_user(id): + user = User.query.get(id) + if not user: + return jsonify({'msg': "User does not exist."}) + return jsonify({'username': user.username}) + +# Route to list all users +@routes.route('/api/v1/users', methods=['GET']) +def get_users(): + users = User.query.filter_by().all() + return jsonify([u.to_dict() for u in users]), 200 + +# Route to check if we are logged in with our unique jwt token. +@routes.route('/api/v1/protected', methods=['GET']) +# Include bearer token from login_user() to verify we are logged in and are in session. +@jwt_required() +def get_identity(): + user_id = get_jwt_identity() + user = User.query.filter_by(id=user_id).first() + # Check if user exists + if user: + return jsonify({'message': 'User found', 'name': user.username}) + else: + return jsonify({'message': 'User not found'}), 404 + +# Logged in user adds laptime. +@routes.route('/api/v1/user/laptimes', methods=['POST']) +@jwt_required() +def add_laptime(): + user_id = get_jwt_identity() + loggedin_user = User.query.filter_by(id=user_id).first() + + laptime_data = request.get_json() + + car = laptime_data['car'] + track = laptime_data['track'] + time = laptime_data['time'] + simracing = laptime_data['simracing'] + platform = laptime_data['platform'] + youtube_link = laptime_data['youtube_link'] + comment = laptime_data['comment'] + + if not car or not track or not time: + return jsonify({'msg': 'Missing required fields'}), 400 + + laptime = Laptime( + user_id=user_id, + car=car, + track=track, + time=time, + simracing=simracing, + platform=platform, + youtube_link=youtube_link, + comment=comment + ) + + db.session.add(laptime) + db.session.commit() + + return jsonify({"Laptime Added Successfully": laptime.to_dict(), "by": loggedin_user.username}), 201 + +# Logged in user gets all the laptimes they posted on tracknow. +@routes.route('/api/v1/user/laptimes', methods=['GET']) +@jwt_required() +def get_user_laptimes(): + user_id = get_jwt_identity() + laptimes = Laptime.query.filter_by(user_id=user_id).all() + + return jsonify([lt.to_dict() for lt in laptimes]), 200 + +# Logged in user gets one laptime they selected. +@routes.route('/api/v1/user/laptimes/', methods=['GET']) +@jwt_required() +def get_user_laptime(id): + user_id = get_jwt_identity() + laptime = Laptime.query.filter_by(id=id, user_id=user_id).first() + return jsonify(laptime.to_dict()), 200 + +# Global - get all laptimes posted around the world. +@routes.route('/api/v1/laptimes', methods=['GET']) +def get_laptimes(): + laptimes = Laptime.query.filter_by().all() + return jsonify([lt.to_dict() for lt in laptimes]), 200 + +# Global - get one laptime selected. +@routes.route('/api/v1/laptimes/', methods=['GET']) +@jwt_required() +def get_laptime(id): + laptime = Laptime.query.filter_by(id=id).first() + return jsonify(laptime.to_dict()), 200 From 87d08576198a69c202fcead24e5e8676e4c70a59 Mon Sep 17 00:00:00 2001 From: vantage-ola Date: Wed, 26 Jun 2024 10:32:46 +0100 Subject: [PATCH 5/8] + update nationality, *get one user laptime routes. --- tracknow/backend/routes.py | 45 +++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/tracknow/backend/routes.py b/tracknow/backend/routes.py index 4ff1f59..46a84ea 100644 --- a/tracknow/backend/routes.py +++ b/tracknow/backend/routes.py @@ -30,6 +30,31 @@ def new_user(): return (jsonify({'username': user.username}), 201, {'Location': url_for('routes.get_user', id=user.id, _external=True)}) +# update route for nationality. no username or password change right now. +@routes.route('/api/v1/users//update', methods=['PUT']) +@jwt_required() +def update_user_nationality(user_id): + current_user_id = get_jwt_identity() + + # Ensure the user is updating their own information + if current_user_id != user_id: + return jsonify({'msg': 'Permission denied'}), 403 + + data = request.get_json() + nationality = data.get('nationality', None) + + if nationality is None: + return jsonify({'msg': 'No nationality provided'}), 400 + + user = User.query.get(user_id) + if user is None: + return jsonify({'msg': 'User not found'}), 404 + + user.nationality = nationality + db.session.commit() + + return jsonify({'msg': 'Nationality updated successfully', 'user': user.to_dict()}), 200 + # Login to tracknow with username and password. @routes.route('/api/v1/login', methods=['POST']) def login_user(): @@ -115,7 +140,7 @@ def get_user_laptimes(): return jsonify([lt.to_dict() for lt in laptimes]), 200 # Logged in user gets one laptime they selected. -@routes.route('/api/v1/user/laptimes/', methods=['GET']) +@routes.route('/api/v1/user/laptimes/', methods=['GET']) @jwt_required() def get_user_laptime(id): user_id = get_jwt_identity() @@ -128,9 +153,17 @@ def get_laptimes(): laptimes = Laptime.query.filter_by().all() return jsonify([lt.to_dict() for lt in laptimes]), 200 -# Global - get one laptime selected. -@routes.route('/api/v1/laptimes/', methods=['GET']) +# Global - get one user laptime selected. +@routes.route('/api/v1/users//laptimes/', methods=['GET']) @jwt_required() -def get_laptime(id): - laptime = Laptime.query.filter_by(id=id).first() - return jsonify(laptime.to_dict()), 200 +def get_laptime(user_id, laptime_id): + laptime = Laptime.query.filter_by(id=laptime_id, user_id=user_id).first() + + if laptime is None: + return jsonify({'msg': 'Laptime not found'}), 404 + + laptime_data = laptime.to_dict() + user = User.query.filter_by(id=user_id).first() + laptime_data['user'] = user.to_dict() + + return jsonify(laptime_data), 200 \ No newline at end of file From 1fb1567e44c20b7314f030b702ffbc419645cda4 Mon Sep 17 00:00:00 2001 From: vantage-ola Date: Wed, 26 Jun 2024 10:35:20 +0100 Subject: [PATCH 6/8] +update unit tests for updated route changes +update swagger docs. --- tracknow/backend/models.py | 2 +- tracknow/backend/static/swagger.json | 130 +++++++++++++++++++++---- tracknow/backend/tests/test_laptime.py | 14 ++- tracknow/backend/tests/test_user.py | 15 +++ 4 files changed, 138 insertions(+), 23 deletions(-) diff --git a/tracknow/backend/models.py b/tracknow/backend/models.py index 4962a56..9374be9 100644 --- a/tracknow/backend/models.py +++ b/tracknow/backend/models.py @@ -42,7 +42,7 @@ class Laptime(db.Model): platform = db.Column(db.String(100), nullable=True) # if simracing is true, what simracing title do you set that laptime. youtube_link = db.Column(db.String(255), nullable=True) # youtube link or evidence. comment = db.Column(db.String(500), nullable=True) - + # TODO Add date time. def __repr__(self): return f'' diff --git a/tracknow/backend/static/swagger.json b/tracknow/backend/static/swagger.json index 258d4f0..6d9c3ae 100644 --- a/tracknow/backend/static/swagger.json +++ b/tracknow/backend/static/swagger.json @@ -7,7 +7,7 @@ }, "basePath": "/api/v1", "schemes": [ - "https" + "http" ], "paths": { "/hello": { @@ -197,6 +197,82 @@ ] } }, + "/api/v1/users/{user_id}/update": { + "put": { + "summary": "Update user's nationality", + "description": "Allows a user to update their nationality.", + "produces": [ + "application/json" + ], + "consumes": [ + "application/json" + ], + "parameters": [ + { + "name": "user_id", + "in": "path", + "required": true, + "type": "integer", + "description": "User ID" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "nationality": { + "type": "string" + } + } + }, + "description": "New nationality for the user" + } + ], + "responses": { + "200": { + "description": "Nationality updated successfully", + "schema": { + "type": "object", + "properties": { + "msg": { + "type": "string" + }, + "user": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "username": { + "type": "string" + }, + "nationality": { + "type": "string" + } + } + } + } + } + }, + "400": { + "description": "No nationality provided" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "User not found" + } + }, + "security": [ + { + "Bearer": [] + } + ] + } + }, "/protected": { "get": { "summary": "Get identity", @@ -470,14 +546,21 @@ } } }, - "/laptimes/{id}": { + "/users/{user_id}/laptimes/{id}": { "get": { - "summary": "Get laptime by ID", + "summary": "Get laptime by user id and laptime id", "description": "Global - get one laptime selected.", "produces": [ "application/json" ], "parameters": [ + { + "name": "user_id", + "in": "path", + "required": true, + "type": "integer", + "description": "User ID " + }, { "name": "id", "in": "path", @@ -512,25 +595,36 @@ }, "comment": { "type": "string" + }, + "user": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "username": { + "type": "string" + } + } } } - } - } - }, - "security": [ - { - "Bearer": [] + }, + "security": [ + { + "Bearer": [] + } + ] } - ] + } + }, + "securityDefinitions": { + "Bearer": { + "type": "apiKey", + "name": "Authorization", + "in": "header", + "description": " Enter the token with the `Bearer: ` prefix, e.g. Bearer abcde12345." + } } } - }, - "securityDefinitions": { - "Bearer": { - "type": "apiKey", - "name": "Authorization", - "in": "header", - "description": " Enter the token with the `Bearer: ` prefix, e.g. Bearer abcde12345." - } } } \ No newline at end of file diff --git a/tracknow/backend/tests/test_laptime.py b/tracknow/backend/tests/test_laptime.py index 55e6bdd..8c440d6 100644 --- a/tracknow/backend/tests/test_laptime.py +++ b/tracknow/backend/tests/test_laptime.py @@ -58,7 +58,7 @@ def test_logged_in_user_laptime(test_client, init_database): 'Authorization': f'Bearer {token}' } - response = test_client.get('/api/v1/laptimes/1', headers=headers, content_type='application/json') + response = test_client.get('/api/v1/user/laptimes/1', headers=headers, content_type='application/json') assert response.status_code == 200 def test_get_all_laptimes(test_client, init_database): @@ -67,6 +67,12 @@ def test_get_all_laptimes(test_client, init_database): assert len(response.json) == 1 def test_get_one_laptime(test_client, init_database): - response = test_client.get('/api/v1/laptimes', content_type='application/json') - assert response.status_code == 200 - assert "simracing" in response.json[0] \ No newline at end of file + login_response = test_client.post('/api/v1/login', data=json.dumps(user), content_type='application/json') + + token = login_response.json['token'] + headers = { + 'Authorization': f'Bearer {token}' + } + + response = test_client.get('/api/v1/users/1/laptimes/1', headers=headers, content_type='application/json') + assert response.status_code == 200 \ No newline at end of file diff --git a/tracknow/backend/tests/test_user.py b/tracknow/backend/tests/test_user.py index 6b231d5..609a607 100644 --- a/tracknow/backend/tests/test_user.py +++ b/tracknow/backend/tests/test_user.py @@ -47,3 +47,18 @@ def test_login_user_jwt_failure(test_client, init_database): response = test_client.post('/api/v1/login', data=json.dumps(login_user), content_type='application/json') assert response.status_code == 401 assert response.json == {'msg': 'Login Failed'} + +def test_update_user(test_client, init_database): + # nationality update only. + login_response = test_client.post('/api/v1/login', data=json.dumps(user), content_type='application/json') + token = login_response.json['token'] + + headers = { + 'Authorization': f'Bearer {token}' + } + + + nationality = {"nationality":"Nigerian"} + response = test_client.put('/api/v1/users/1/update', data=json.dumps(nationality),headers=headers, content_type='application/json') + assert response.status_code == 200 + assert response.json['msg'] == 'Nationality updated successfully' From 348daabe6f0c246c29f0717880c96cc059ca53f4 Mon Sep 17 00:00:00 2001 From: vantage-ola Date: Wed, 26 Jun 2024 10:52:30 +0100 Subject: [PATCH 7/8] https for production --- tracknow/backend/static/swagger.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracknow/backend/static/swagger.json b/tracknow/backend/static/swagger.json index 6d9c3ae..dfad224 100644 --- a/tracknow/backend/static/swagger.json +++ b/tracknow/backend/static/swagger.json @@ -7,7 +7,7 @@ }, "basePath": "/api/v1", "schemes": [ - "http" + "https" ], "paths": { "/hello": { From 7dbf020f25c7d3d22464fdedbc2b33059e78c150 Mon Sep 17 00:00:00 2001 From: vantage-ola Date: Wed, 3 Jul 2024 17:39:08 +0100 Subject: [PATCH 8/8] fix - include username in laptime.to_dict() --- tracknow/backend/models.py | 4 +++- tracknow/backend/routes.py | 4 +++- tracknow/backend/static/swagger.json | 3 +++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/tracknow/backend/models.py b/tracknow/backend/models.py index 9374be9..dbd6166 100644 --- a/tracknow/backend/models.py +++ b/tracknow/backend/models.py @@ -43,6 +43,7 @@ class Laptime(db.Model): youtube_link = db.Column(db.String(255), nullable=True) # youtube link or evidence. comment = db.Column(db.String(500), nullable=True) # TODO Add date time. + def __repr__(self): return f'' @@ -56,5 +57,6 @@ def to_dict(self): 'simracing': self.simracing, 'platform': self.platform, 'youtube_link': self.youtube_link, - 'comment': self.comment + 'comment': self.comment, + 'by': self.user.username if self.user else None } \ No newline at end of file diff --git a/tracknow/backend/routes.py b/tracknow/backend/routes.py index 46a84ea..7d9462e 100644 --- a/tracknow/backend/routes.py +++ b/tracknow/backend/routes.py @@ -150,7 +150,9 @@ def get_user_laptime(id): # Global - get all laptimes posted around the world. @routes.route('/api/v1/laptimes', methods=['GET']) def get_laptimes(): - laptimes = Laptime.query.filter_by().all() + # TODO introduce randomness, recently added + laptimes = Laptime.query.all() #Laptime.query.filter_by().all() + return jsonify([lt.to_dict() for lt in laptimes]), 200 # Global - get one user laptime selected. diff --git a/tracknow/backend/static/swagger.json b/tracknow/backend/static/swagger.json index dfad224..4304e67 100644 --- a/tracknow/backend/static/swagger.json +++ b/tracknow/backend/static/swagger.json @@ -538,6 +538,9 @@ }, "comment": { "type": "string" + }, + "by": { + "type": "string" } } }