backend: implement users methods according to frontend
This commit is contained in:
parent
92c76d7155
commit
3f074e895d
@ -1,3 +1,4 @@
|
|||||||
flask==3.0.2
|
flask==3.0.2
|
||||||
mysql-connector-python==9.4.0
|
mysql-connector-python==9.4.0
|
||||||
python_dotenv==1.1.1
|
python_dotenv==1.1.1
|
||||||
|
Flask-CORS==6.0.1
|
||||||
@ -1,93 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
'''
|
|
||||||
car.py is a source for all car endpoints.
|
|
||||||
'''
|
|
||||||
|
|
||||||
from flask import request, jsonify
|
|
||||||
|
|
||||||
def registerCarEndpoints(app, database):
|
|
||||||
@app.route('/car', methods=['GET'])
|
|
||||||
def get_car():
|
|
||||||
if not request.is_json:
|
|
||||||
return jsonify({'error': 'Request must contain JSON data'}), 400
|
|
||||||
|
|
||||||
data = request.get_json()
|
|
||||||
|
|
||||||
if not data.get('name'):
|
|
||||||
return jsonify({'error': 'Request must contain name field'}), 400
|
|
||||||
|
|
||||||
query = f'SELECT * from car WHERE name = %s'
|
|
||||||
output = database.query(query_str=query, params=(data['name'],))
|
|
||||||
if not output:
|
|
||||||
return jsonify({"message": "No car by that name exist"}), 404
|
|
||||||
car = output[0]
|
|
||||||
if len(car) != 3:
|
|
||||||
return jsonify({'error': 'Car data is corrupted'}), 500
|
|
||||||
|
|
||||||
response = {
|
|
||||||
"name": car[0],
|
|
||||||
"car": car[1],
|
|
||||||
"freeCarSpaces": car[2]
|
|
||||||
}
|
|
||||||
return jsonify(response), 200
|
|
||||||
|
|
||||||
@app.route('/car', methods=['POST'])
|
|
||||||
def add_car():
|
|
||||||
if not request.is_json:
|
|
||||||
return jsonify({'error': 'Request must contain JSON data'}), 400
|
|
||||||
|
|
||||||
data = request.get_json()
|
|
||||||
if not data.get('name') or not data.get('car') or data.get('spaces') is None:
|
|
||||||
return jsonify({'error': 'JSON must contain car and name fields'}), 400
|
|
||||||
|
|
||||||
query = 'SELECT * from car WHERE name = %s'
|
|
||||||
output = database.query(query_str=query, params=(data['name'],))
|
|
||||||
if output:
|
|
||||||
return jsonify({'error': 'A person has a car already'}), 409
|
|
||||||
|
|
||||||
query = 'INSERT into car (Name, Car, FreeCarSpaces) VALUES (%s, %s, %s)'
|
|
||||||
output = database.query(query_str=query, params=(data['name'],data['car'],data['spaces']))
|
|
||||||
|
|
||||||
database.commit()
|
|
||||||
return jsonify({"message": "car added", "car": data}), 200
|
|
||||||
|
|
||||||
@app.route('/car', methods=['UPDATE'])
|
|
||||||
def update_car():
|
|
||||||
if not request.is_json:
|
|
||||||
return jsonify({'error': 'Request must contain JSON data'}), 400
|
|
||||||
|
|
||||||
data = request.get_json()
|
|
||||||
if not data.get('name') or not data.get('car') or data.get('spaces') is None:
|
|
||||||
return jsonify({'error': 'JSON must contain car,name,space fields'}), 400
|
|
||||||
|
|
||||||
query = 'SELECT * from car WHERE name = %s'
|
|
||||||
output = database.query(query_str=query, params=(data['name'],))
|
|
||||||
if not output:
|
|
||||||
return jsonify({'error': 'Such car does not exist. Add it first'}), 409
|
|
||||||
|
|
||||||
query = 'UPDATE car SET Name = %s, Car = %s, FreeCarSpaces = %s'
|
|
||||||
output = database.query(query_str=query, params=(data['name'],data['car'],data['spaces']))
|
|
||||||
|
|
||||||
database.commit()
|
|
||||||
return jsonify({"message": "car modified", "car": data}), 200
|
|
||||||
|
|
||||||
@app.route('/car', methods=['DELETE'])
|
|
||||||
def delete_car():
|
|
||||||
if not request.is_json:
|
|
||||||
return jsonify({'error': 'Request must contain JSON data'}), 400
|
|
||||||
|
|
||||||
data = request.get_json()
|
|
||||||
if not data.get('name'):
|
|
||||||
return jsonify({'error': 'JSON must contain persons name whose car to delete'}), 400
|
|
||||||
|
|
||||||
query = 'SELECT * from car WHERE name = %s'
|
|
||||||
output = database.query(query_str=query, params=(data['name'],))
|
|
||||||
if not output:
|
|
||||||
return jsonify({'error': 'Such person does not have a car'}), 409
|
|
||||||
|
|
||||||
query = 'DELETE FROM car WHERE Name = %s'
|
|
||||||
output = database.query(query_str=query, params=(data['name'],))
|
|
||||||
database.commit()
|
|
||||||
return jsonify({"message": "car deleted"}), 200
|
|
||||||
@ -1,11 +1,3 @@
|
|||||||
|
|
||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
'''
|
|
||||||
db_client.py is the module for managing teh Dungeon's database services.
|
|
||||||
'''
|
|
||||||
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
import sys
|
import sys
|
||||||
import mysql.connector
|
import mysql.connector
|
||||||
@ -14,32 +6,20 @@ import os
|
|||||||
STARTUP_TABLE_CREATION_QUERIES = {
|
STARTUP_TABLE_CREATION_QUERIES = {
|
||||||
"users": """CREATE TABLE IF NOT EXISTS users (
|
"users": """CREATE TABLE IF NOT EXISTS users (
|
||||||
Name varchar(255),
|
Name varchar(255),
|
||||||
Attendance varchar(255),
|
Attendance bool,
|
||||||
HasCar bool
|
Password VARCHAR(2048)
|
||||||
);""",
|
);""",
|
||||||
"car": """CREATE TABLE IF NOT EXISTS car (
|
"sessions": """CREATE TABLE IF NOT EXISTS sessions (
|
||||||
Name varchar(255),
|
Token VARCHAR(2048),
|
||||||
Car varchar(255),
|
Name varchar(255)
|
||||||
FreeCarSpaces tinyint(1)
|
|
||||||
);""",
|
|
||||||
"suggestions": """CREATE TABLE IF NOT EXISTS suggestions (
|
|
||||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
|
||||||
Name VARCHAR(255),
|
|
||||||
Suggestion VARCHAR(2048)
|
|
||||||
);""",
|
|
||||||
"passengers": """CREATE TABLE IF NOT EXISTS passengers (
|
|
||||||
Name varchar(255),
|
|
||||||
Car varchar(255)
|
|
||||||
);""",
|
);""",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Severity(Enum):
|
class Severity(Enum):
|
||||||
INFO = "INFO"
|
INFO = "INFO"
|
||||||
WARNING = "WARNING"
|
WARNING = "WARNING"
|
||||||
ERROR = "ERROR"
|
ERROR = "ERROR"
|
||||||
|
|
||||||
|
|
||||||
class DBClient:
|
class DBClient:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.db_server = os.environ.get('DB_SERVER')
|
self.db_server = os.environ.get('DB_SERVER')
|
||||||
@ -48,16 +28,18 @@ class DBClient:
|
|||||||
self.password = os.environ.get('ROOT_PWD')
|
self.password = os.environ.get('ROOT_PWD')
|
||||||
self.database = os.environ.get('DB_NAME')
|
self.database = os.environ.get('DB_NAME')
|
||||||
|
|
||||||
if not self.db_server:
|
self.validate_env_variables() # Check for required environment variables
|
||||||
self.error("Environment variable 'DB_SERVER' is not set.")
|
self.connection = self.open()
|
||||||
if not self.db_port:
|
self.cursor = self.connection.cursor()
|
||||||
self.error("Environment variable 'DB_PORT' is not set.")
|
|
||||||
if not self.password:
|
|
||||||
self.error("Environment variable 'ROOT_PWD' is not set.")
|
|
||||||
if not self.database:
|
|
||||||
self.error("Environment variable 'DB_NAME' is not set.")
|
|
||||||
|
|
||||||
self.connection = mysql.connector.connect(
|
self.initialize_database()
|
||||||
|
|
||||||
|
def validate_env_variables(self):
|
||||||
|
if not self.db_server or not self.db_port or not self.password or not self.database:
|
||||||
|
self.error("Missing one or more environment variables.")
|
||||||
|
|
||||||
|
def open(self):
|
||||||
|
return mysql.connector.connect(
|
||||||
host=self.db_server,
|
host=self.db_server,
|
||||||
port=self.db_port,
|
port=self.db_port,
|
||||||
user=self.user,
|
user=self.user,
|
||||||
@ -65,50 +47,38 @@ class DBClient:
|
|||||||
database=self.database
|
database=self.database
|
||||||
)
|
)
|
||||||
|
|
||||||
self.cursor = self.connection.cursor()
|
|
||||||
self.initialize_database()
|
|
||||||
self.commit()
|
|
||||||
|
|
||||||
def create_database(self, db_name):
|
|
||||||
query = f"CREATE DATABASE IF NOT EXISTS `{db_name}`;"
|
|
||||||
self.cursor.execute(query)
|
|
||||||
|
|
||||||
def switch_database(self, db_name):
|
|
||||||
self.connection.database = db_name
|
|
||||||
|
|
||||||
def initialize_database(self):
|
|
||||||
self.create_database(self.database)
|
|
||||||
self.switch_database(self.database)
|
|
||||||
self.query(STARTUP_TABLE_CREATION_QUERIES['users'])
|
|
||||||
self.query(STARTUP_TABLE_CREATION_QUERIES['car'])
|
|
||||||
self.query(STARTUP_TABLE_CREATION_QUERIES['suggestions'])
|
|
||||||
self.query(STARTUP_TABLE_CREATION_QUERIES['passengers'])
|
|
||||||
|
|
||||||
def query(self, query_str, quiet=False, params=None):
|
|
||||||
self.info(f'Executing query: {query_str}')
|
|
||||||
self.cursor.execute(query_str, params)
|
|
||||||
if quiet:
|
|
||||||
return []
|
|
||||||
return self.cursor.fetchall()
|
|
||||||
|
|
||||||
def commit(self):
|
|
||||||
self.info('Commiting actions to DB')
|
|
||||||
self.connection.commit()
|
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self.cursor.close()
|
self.cursor.close()
|
||||||
self.connection.close()
|
self.connection.close()
|
||||||
|
|
||||||
|
def initialize_database(self):
|
||||||
|
self.query(STARTUP_TABLE_CREATION_QUERIES['users'])
|
||||||
|
self.query(STARTUP_TABLE_CREATION_QUERIES['sessions'])
|
||||||
|
|
||||||
|
def query(self, query_str, params=None):
|
||||||
|
try:
|
||||||
|
self.info(f'Executing query: {query_str}')
|
||||||
|
self.cursor.execute(query_str, params)
|
||||||
|
|
||||||
|
if 'SELECT' in query_str:
|
||||||
|
return self.cursor.fetchall() # Return results for SELECT queries
|
||||||
|
else:
|
||||||
|
self.commit() # Commit if it's a non-SELECT query
|
||||||
|
except Exception as e:
|
||||||
|
self.error(f"Query failed: {str(e)}")
|
||||||
|
|
||||||
|
def commit(self):
|
||||||
|
self.info('Committing actions to DB')
|
||||||
|
self.connection.commit()
|
||||||
|
|
||||||
def info(self, message):
|
def info(self, message):
|
||||||
self.message(severity=Severity.INFO, message=message)
|
self.message(severity=Severity.INFO, message=message)
|
||||||
|
|
||||||
|
|
||||||
def warning(self, message):
|
def warning(self, message):
|
||||||
self.message(severity=Severity.WARNING, message=message)
|
self.message(severity=Severity.WARNING, message=message)
|
||||||
|
|
||||||
def error(self, message):
|
def error(self, message):
|
||||||
self.message(severity=Severity.ERROR, message=message)
|
self.message(severity=Severity.ERROR, message=message)
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
def message(self, severity, message):
|
def message(self, severity, message):
|
||||||
print(f'DBClient [{severity.value}]: {message}')
|
print(f'DBClient [{severity.value}]: {message}')
|
||||||
|
|||||||
@ -6,27 +6,21 @@ server.py is the main source file for the Dungeon's backend service.
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
from flask import Flask, request, jsonify
|
from flask import Flask, request, jsonify
|
||||||
|
from flask_cors import CORS
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from db_client import DBClient
|
from db_client import DBClient
|
||||||
from car import registerCarEndpoints
|
|
||||||
from user import registerUserEndpoints
|
from user import registerUserEndpoints
|
||||||
from suggestions import registerSuggestionsEndpoints
|
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
app.config['JSON_AS_ASCII'] = False # Ensures non-ASCII characters are preserved
|
||||||
|
allowed_origins = [
|
||||||
|
"https://nyipyatki.davydovcloud.com",
|
||||||
|
"https://nyipyatki-dev.davydovcloud.com",
|
||||||
|
]
|
||||||
|
CORS(app, resources={r"*": {"origins": allowed_origins}}) # Only allow example.com
|
||||||
database = DBClient()
|
database = DBClient()
|
||||||
registerCarEndpoints(app=app, database=database)
|
|
||||||
registerUserEndpoints(app=app, database=database)
|
registerUserEndpoints(app=app, database=database)
|
||||||
registerSuggestionsEndpoints(app=app, database=database)
|
|
||||||
|
|
||||||
@app.route('/login', methods=['POST'])
|
|
||||||
def login():
|
|
||||||
if request.is_json:
|
|
||||||
return jsonify({"hello": "user"}), 200
|
|
||||||
else:
|
|
||||||
return jsonify({'error': 'Request must contain JSON data'}), 400
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app.run(debug=True)
|
app.run(debug=True)
|
||||||
@ -6,106 +6,78 @@ user.py is a source for all user endpoints.
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
from flask import request, jsonify
|
from flask import request, jsonify
|
||||||
|
import os
|
||||||
|
|
||||||
def registerUserEndpoints(app, database):
|
def registerUserEndpoints(app, database):
|
||||||
@app.route('/users', methods=['GET'])
|
@app.route('/users/isSet', methods=['GET'])
|
||||||
def get_users():
|
def user_is_set():
|
||||||
query = f'SELECT * from users'
|
user_name = request.args.get('userName')
|
||||||
users = database.query(query_str=query)
|
try:
|
||||||
if not users:
|
query = "SELECT * FROM users WHERE Name=%s"
|
||||||
return jsonify({"message": "No users exist"}), 404
|
result = database.query(query, params=(user_name,))
|
||||||
response = {}
|
return jsonify(bool(result and result[0][2])), 200
|
||||||
for user in users:
|
except mysql.connector.Error as err:
|
||||||
if len(user) != 3:
|
# Log the error or handle it as necessary
|
||||||
return jsonify({'error': 'User data is corrupted'}), 500
|
app.logger.error(f"Error: {err}")
|
||||||
|
return jsonify({"error": "Database error occurred"}), 500
|
||||||
|
except Exception as e:
|
||||||
|
# Handle unexpected errors
|
||||||
|
app.logger.error(f"Unexpected error: {e}")
|
||||||
|
return jsonify({"error": "Internal server error"}), 500 # Check if password exists
|
||||||
|
|
||||||
response.update({
|
@app.route('/users/createPassword', methods=['POST'])
|
||||||
"name": user[0],
|
def create_password():
|
||||||
"attendance": user[1],
|
data = request.json
|
||||||
"has_car": bool(user[2])
|
user_name = data.get('userName')
|
||||||
})
|
password = data.get('password')
|
||||||
return jsonify(response), 200
|
|
||||||
|
|
||||||
@app.route('/user', methods=['GET'])
|
# Check if the user already exists
|
||||||
def get_user():
|
query = "SELECT * FROM users WHERE Name=%s"
|
||||||
if not request.is_json:
|
result = database.query(query, params=(user_name,))
|
||||||
return jsonify({'error': 'Request must contain JSON data'}), 400
|
|
||||||
|
|
||||||
data = request.get_json()
|
if result:
|
||||||
|
return jsonify(success=False, message='Пользователь уже создан'), 400
|
||||||
|
|
||||||
if not data.get('name'):
|
query = "INSERT INTO users (Name, Password) VALUES (%s, %s)"
|
||||||
return jsonify({'error': 'Request must contain name field'}), 400
|
|
||||||
|
|
||||||
query = f'SELECT * from users WHERE name = %s'
|
try:
|
||||||
output = database.query(query_str=query, params=(data['name'],))
|
database.query(query, params=(user_name, password))
|
||||||
if not output:
|
|
||||||
return jsonify({"message": "No user by that name exist"}), 404
|
|
||||||
user = output[0]
|
|
||||||
if len(user) != 3:
|
|
||||||
return jsonify({'error': 'User data is corrupted'}), 500
|
|
||||||
|
|
||||||
response = {
|
# Generate a session token
|
||||||
"name": user[0],
|
token = os.urandom(16).hex()
|
||||||
"attendance": user[1],
|
session_query = "INSERT INTO sessions (Token, Name) VALUES (%s, %s)"
|
||||||
"has_car": bool(user[2])
|
database.query(session_query, params=(token,user_name))
|
||||||
}
|
|
||||||
return jsonify(response), 200
|
|
||||||
|
|
||||||
@app.route('/user', methods=['POST'])
|
return jsonify(success=True, token=token), 201 # Return success with token
|
||||||
def add_user():
|
except Exception as e:
|
||||||
if not request.is_json:
|
return jsonify(success=False, message='Ошибка при создании пароля: ' + str(e)), 500
|
||||||
return jsonify({'error': 'Request must contain JSON data'}), 400
|
|
||||||
|
|
||||||
data = request.get_json()
|
|
||||||
if not data.get('name') or not data.get('attendance') or data.get('has_car') is None:
|
|
||||||
return jsonify({'error': 'JSON must contain user fields'}), 400
|
|
||||||
|
|
||||||
query = 'SELECT * from users WHERE name = %s'
|
@app.route('/login', methods=['POST'])
|
||||||
output = database.query(query_str=query, params=(data['name'],))
|
def login():
|
||||||
if output:
|
data = request.json
|
||||||
return jsonify({'error': 'A person already exists'}), 409
|
user_name = data.get('userName')
|
||||||
|
password = data.get('password')
|
||||||
|
|
||||||
query = 'INSERT into users (Name, Attendance, HasCar) VALUES (%s, %s, %s)'
|
query = "SELECT * FROM users WHERE Name=%s AND Password=%s"
|
||||||
output = database.query(query_str=query, params=(data['name'],data['attendance'],data['has_car']))
|
result = database.query(query, params=(user_name, password))
|
||||||
|
|
||||||
database.commit()
|
if result:
|
||||||
return jsonify({"message": "user added", "user": data}), 200
|
token = os.urandom(16).hex() # Example token generation
|
||||||
|
session_query = "INSERT INTO sessions (Token, Name) VALUES (%s, %s)"
|
||||||
|
database.query(session_query, params=(token, user_name))
|
||||||
|
return jsonify(success=True, token=token), 200
|
||||||
|
|
||||||
@app.route('/user', methods=['UPDATE'])
|
return jsonify(success=False), 401
|
||||||
def update_user():
|
|
||||||
if not request.is_json:
|
|
||||||
return jsonify({'error': 'Request must contain JSON data'}), 400
|
|
||||||
|
|
||||||
data = request.get_json()
|
@app.route('/login/validateToken', methods=['POST'])
|
||||||
if not data.get('name') or not data.get('attendance') or data.get('has_car') is None:
|
def validate_token():
|
||||||
return jsonify({'error': 'JSON must contain user fields'}), 400
|
data = request.json
|
||||||
|
token = data.get('token')
|
||||||
query = 'SELECT * from users WHERE name = %s'
|
user_name = data.get('userName')
|
||||||
output = database.query(query_str=query, params=(data['name'],))
|
query = "SELECT * FROM sessions WHERE Token=%s AND Name=%s"
|
||||||
if not output:
|
try:
|
||||||
return jsonify({'error': 'Such user does not exist. Add it first'}), 409
|
result = database.query(query, params=(token, user_name))
|
||||||
|
return jsonify(tokenValid=bool(result)), 200
|
||||||
query = 'UPDATE user SET Name = %s, Attendance = %s, HasCar = %s'
|
except Exception as e:
|
||||||
output = database.query(query_str=query, params=(data['name'],data['attendance'],data['has_car']))
|
return jsonify(success=False, message=str(e)), 500
|
||||||
|
|
||||||
database.commit()
|
|
||||||
return jsonify({"message": "user modified", "user": data}), 200
|
|
||||||
|
|
||||||
@app.route('/user', methods=['DELETE'])
|
|
||||||
def delete_user():
|
|
||||||
if not request.is_json:
|
|
||||||
return jsonify({'error': 'Request must contain JSON data'}), 400
|
|
||||||
|
|
||||||
data = request.get_json()
|
|
||||||
if not data.get('name'):
|
|
||||||
return jsonify({'error': 'JSON must contain persons name to delete'}), 400
|
|
||||||
|
|
||||||
query = 'SELECT * from users WHERE name = %s'
|
|
||||||
output = database.query(query_str=query, params=(data['name'],))
|
|
||||||
if not output:
|
|
||||||
return jsonify({'error': 'Such person does not exist'}), 409
|
|
||||||
|
|
||||||
query = 'DELETE FROM users WHERE Name = %s'
|
|
||||||
output = database.query(query_str=query, params=(data['name'],))
|
|
||||||
database.commit()
|
|
||||||
return jsonify({"message": "user deleted"}), 200
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user