Compare commits
2 Commits
10261cab65
...
c579028007
Author | SHA1 | Date | |
---|---|---|---|
c579028007 | |||
8b777f57ad |
738
api_server.py
738
api_server.py
@@ -1,533 +1,363 @@
|
||||
|
||||
import mysql.connector
|
||||
from flask import Flask, request, jsonify
|
||||
from flask_cors import CORS
|
||||
import mysql.connector
|
||||
from mysql.connector import pooling
|
||||
import os
|
||||
|
||||
# --- Database Configuration ---
|
||||
DB_HOST = "mysql.theaken.com"
|
||||
DB_PORT = 33306
|
||||
DB_NAME = "db_A027"
|
||||
DB_USER = "A027"
|
||||
DB_PASSWORD = "E1CelfxqlKoj"
|
||||
|
||||
# --- Create a connection pool ---
|
||||
try:
|
||||
db_pool = pooling.MySQLConnectionPool(
|
||||
pool_name="api_pool",
|
||||
pool_size=5,
|
||||
host=DB_HOST,
|
||||
port=DB_PORT,
|
||||
database=DB_NAME,
|
||||
user=DB_USER,
|
||||
password=DB_PASSWORD
|
||||
)
|
||||
print("Database connection pool created successfully.")
|
||||
except mysql.connector.Error as err:
|
||||
print(f"Error creating connection pool: {err}")
|
||||
exit()
|
||||
|
||||
# --- Flask App Initialization ---
|
||||
app = Flask(__name__)
|
||||
CORS(app) # Enable CORS for all routes
|
||||
CORS(app) # Enable CORS for all routes
|
||||
|
||||
# Database configuration
|
||||
db_config = {
|
||||
'host': 'mysql.theaken.com',
|
||||
'port': 33306,
|
||||
'user': 'A027',
|
||||
'password': 'E1CelfxqlKoj',
|
||||
'database': 'db_A027'
|
||||
}
|
||||
|
||||
# --- Helper Functions ---
|
||||
def get_db_connection():
|
||||
"""Get a connection from the pool."""
|
||||
"""Establishes a new database connection."""
|
||||
try:
|
||||
return db_pool.get_connection()
|
||||
conn = mysql.connector.connect(**db_config)
|
||||
return conn
|
||||
except mysql.connector.Error as err:
|
||||
print(f"Error getting connection from pool: {err}")
|
||||
print(f"Database connection error: {err}")
|
||||
return None
|
||||
|
||||
def make_response(status, code, message, data=None):
|
||||
"""Standardized response format."""
|
||||
def make_success_response(data, code, message="Success"):
|
||||
"""Wrapper for a successful API response."""
|
||||
response = {
|
||||
"status": status,
|
||||
"status": "success",
|
||||
"code": code,
|
||||
"message": message
|
||||
"message": message,
|
||||
}
|
||||
if data is not None:
|
||||
response["data"] = data
|
||||
return jsonify(response), code
|
||||
|
||||
# --- Error Handlers ---
|
||||
@app.errorhandler(404)
|
||||
def not_found(error):
|
||||
return make_response("error", 404, "The requested resource was not found.")
|
||||
def make_error_response(message, code):
|
||||
"""Wrapper for an error API response."""
|
||||
return jsonify({
|
||||
"status": "error",
|
||||
"code": code,
|
||||
"message": message
|
||||
}), code
|
||||
|
||||
@app.errorhandler(500)
|
||||
def internal_server_error(error):
|
||||
return make_response("error", 500, "An internal server error occurred.")
|
||||
def query_to_dict(cursor, data):
|
||||
"""Converts query result to a list of dictionaries."""
|
||||
columns = [desc[0] for desc in cursor.description]
|
||||
return [dict(zip(columns, row)) for row in data]
|
||||
|
||||
# --- Employee API Endpoints ---
|
||||
# --- Orders API Endpoints ---
|
||||
|
||||
@app.route('/v1/employee', methods=['GET'])
|
||||
def get_employees():
|
||||
conn = get_db_connection()
|
||||
if not conn:
|
||||
return make_response("error", 503, "Database service unavailable.")
|
||||
cursor = conn.cursor(dictionary=True)
|
||||
|
||||
query = "SELECT * FROM employee WHERE 1=1"
|
||||
params = []
|
||||
|
||||
if 'id' in request.args:
|
||||
query += " AND id = %s"
|
||||
params.append(request.args['id'])
|
||||
if 'name' in request.args:
|
||||
query += " AND name LIKE %s"
|
||||
params.append(f"%{request.args['name']}%")
|
||||
|
||||
try:
|
||||
cursor.execute(query, tuple(params))
|
||||
employees = cursor.fetchall()
|
||||
return make_response("success", 200, "Employees retrieved successfully.", {"employees": employees, "meta": {"total": len(employees)}})
|
||||
except mysql.connector.Error as err:
|
||||
return make_response("error", 500, str(err))
|
||||
finally:
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
@app.route('/v1/employee/<string:emp_id>', methods=['GET'])
|
||||
def get_employee(emp_id):
|
||||
conn = get_db_connection()
|
||||
if not conn:
|
||||
return make_response("error", 503, "Database service unavailable.")
|
||||
cursor = conn.cursor(dictionary=True)
|
||||
|
||||
try:
|
||||
cursor.execute("SELECT * FROM employee WHERE id = %s", (emp_id,))
|
||||
employee = cursor.fetchone()
|
||||
if employee:
|
||||
return make_response("success", 200, "Employee found.", employee)
|
||||
else:
|
||||
return make_response("error", 404, "Employee not found.")
|
||||
except mysql.connector.Error as err:
|
||||
return make_response("error", 500, str(err))
|
||||
finally:
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
@app.route('/v1/employee', methods=['POST'])
|
||||
def create_employee():
|
||||
data = request.get_json()
|
||||
if not data or 'id' not in data or 'name' not in data:
|
||||
return make_response("error", 400, "Missing required fields: id, name.")
|
||||
|
||||
conn = get_db_connection()
|
||||
if not conn:
|
||||
return make_response("error", 503, "Database service unavailable.")
|
||||
cursor = conn.cursor(dictionary=True)
|
||||
|
||||
try:
|
||||
cursor.execute("INSERT INTO employee (id, name) VALUES (%s, %s)", (data['id'], data['name']))
|
||||
conn.commit()
|
||||
cursor.execute("SELECT * FROM employee WHERE id = %s", (data['id'],))
|
||||
new_employee = cursor.fetchone()
|
||||
return make_response("success", 201, "Employee created successfully.", new_employee)
|
||||
except mysql.connector.Error as err:
|
||||
conn.rollback()
|
||||
return make_response("error", 500, str(err))
|
||||
finally:
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
@app.route('/v1/employee/<string:emp_id>', methods=['PATCH'])
|
||||
def update_employee(emp_id):
|
||||
@app.route('/v1/orders', methods=['POST'])
|
||||
def create_order():
|
||||
data = request.get_json()
|
||||
if not data:
|
||||
return make_response("error", 400, "No update data provided.")
|
||||
return make_error_response("Invalid JSON", 400)
|
||||
|
||||
required_fields = ['emp_id', 'emp_name', 'menu_item_id', 'main_course', 'order_date', 'order_qty']
|
||||
if not all(field in data for field in required_fields):
|
||||
return make_error_response(f"Missing required fields: {required_fields}", 400)
|
||||
|
||||
sql = """
|
||||
INSERT INTO orders (emp_id, emp_name, menu_item_id, main_course, order_date, order_qty)
|
||||
VALUES (%(emp_id)s, %(emp_name)s, %(menu_item_id)s, %(main_course)s, %(order_date)s, %(order_qty)s)
|
||||
"""
|
||||
|
||||
conn = get_db_connection()
|
||||
if not conn:
|
||||
return make_response("error", 503, "Database service unavailable.")
|
||||
cursor = conn.cursor(dictionary=True)
|
||||
|
||||
updates = []
|
||||
params = []
|
||||
if 'name' in data:
|
||||
updates.append("name = %s")
|
||||
params.append(data['name'])
|
||||
|
||||
if not updates:
|
||||
return make_response("error", 400, "No valid fields to update.")
|
||||
|
||||
params.append(emp_id)
|
||||
query = f"UPDATE employee SET {', '.join(updates)} WHERE id = %s"
|
||||
|
||||
try:
|
||||
cursor.execute(query, tuple(params))
|
||||
conn.commit()
|
||||
if cursor.rowcount == 0:
|
||||
return make_response("error", 404, "Employee not found or data is the same.")
|
||||
return make_error_response("Database connection failed", 500)
|
||||
|
||||
cursor.execute("SELECT * FROM employee WHERE id = %s", (emp_id,))
|
||||
updated_employee = cursor.fetchone()
|
||||
return make_response("success", 200, "Employee updated successfully.", updated_employee)
|
||||
try:
|
||||
cursor = conn.cursor(dictionary=True)
|
||||
cursor.execute(sql, data)
|
||||
conn.commit()
|
||||
new_id = cursor.lastrowid
|
||||
cursor.execute("SELECT * FROM orders WHERE id = %s", (new_id,))
|
||||
new_order = cursor.fetchone()
|
||||
return make_success_response(new_order, 201, "Order created successfully.")
|
||||
except mysql.connector.Error as err:
|
||||
conn.rollback()
|
||||
return make_response("error", 500, str(err))
|
||||
return make_error_response(f"Database error: {err}", 500)
|
||||
finally:
|
||||
cursor.close()
|
||||
conn.close()
|
||||
if conn.is_connected():
|
||||
conn.close()
|
||||
|
||||
@app.route('/v1/employee/<string:emp_id>', methods=['DELETE'])
|
||||
def delete_employee(emp_id):
|
||||
@app.route('/v1/orders/<int:order_id>', methods=['GET'])
|
||||
def get_order_by_id(order_id):
|
||||
conn = get_db_connection()
|
||||
if not conn:
|
||||
return make_response("error", 503, "Database service unavailable.")
|
||||
cursor = conn.cursor()
|
||||
return make_error_response("Database connection failed", 500)
|
||||
|
||||
try:
|
||||
cursor = conn.cursor(dictionary=True)
|
||||
cursor.execute("SELECT * FROM orders WHERE id = %s", (order_id,))
|
||||
order = cursor.fetchone()
|
||||
if order:
|
||||
return make_success_response(order, 200)
|
||||
else:
|
||||
return make_error_response("Order not found", 404)
|
||||
except mysql.connector.Error as err:
|
||||
return make_error_response(f"Database error: {err}", 500)
|
||||
finally:
|
||||
if conn.is_connected():
|
||||
conn.close()
|
||||
|
||||
@app.route('/v1/orders', methods=['GET'])
|
||||
def get_orders():
|
||||
query_params = request.args.to_dict()
|
||||
|
||||
sql = "SELECT * FROM orders"
|
||||
conditions = []
|
||||
params = {}
|
||||
|
||||
for key, value in query_params.items():
|
||||
# Basic filtering, can be expanded
|
||||
conditions.append(f"{key} = %({key})s")
|
||||
params[key] = value
|
||||
|
||||
if conditions:
|
||||
sql += " WHERE " + " AND ".join(conditions)
|
||||
|
||||
conn = get_db_connection()
|
||||
if not conn:
|
||||
return make_error_response("Database connection failed", 500)
|
||||
|
||||
try:
|
||||
# Note: Deleting an employee might fail if they have existing votes due to foreign key constraints.
|
||||
# This should be handled by the application logic (e.g., delete votes first or prevent deletion).
|
||||
cursor.execute("DELETE FROM employee WHERE id = %s", (emp_id,))
|
||||
conn.commit()
|
||||
if cursor.rowcount == 0:
|
||||
return make_response("error", 404, "Employee not found.")
|
||||
return make_response("success", 204, "Employee deleted successfully.")
|
||||
cursor = conn.cursor(dictionary=True)
|
||||
cursor.execute(sql, params)
|
||||
orders = cursor.fetchall()
|
||||
|
||||
meta = {
|
||||
"total_items": len(orders),
|
||||
"query_params": query_params
|
||||
}
|
||||
data = {
|
||||
"orders": orders,
|
||||
"meta": meta
|
||||
}
|
||||
return make_success_response(data, 200)
|
||||
except mysql.connector.Error as err:
|
||||
conn.rollback()
|
||||
# Check for foreign key constraint violation
|
||||
if err.errno == 1451:
|
||||
return make_response("error", 409, "Cannot delete employee with existing votes. Please remove their votes first.")
|
||||
return make_response("error", 500, str(err))
|
||||
return make_error_response(f"Database error: {err}", 500)
|
||||
finally:
|
||||
cursor.close()
|
||||
conn.close()
|
||||
if conn.is_connected():
|
||||
conn.close()
|
||||
|
||||
|
||||
@app.route('/v1/orders/<int:order_id>', methods=['PATCH'])
|
||||
def update_order(order_id):
|
||||
data = request.get_json()
|
||||
if not data:
|
||||
return make_error_response("Invalid JSON", 400)
|
||||
|
||||
set_clauses = []
|
||||
params = {}
|
||||
for key, value in data.items():
|
||||
set_clauses.append(f"{key} = %({key})s")
|
||||
params[key] = value
|
||||
|
||||
if not set_clauses:
|
||||
return make_error_response("No fields to update", 400)
|
||||
|
||||
params['id'] = order_id
|
||||
sql = f"UPDATE orders SET {', '.join(set_clauses)} WHERE id = %(id)s"
|
||||
|
||||
conn = get_db_connection()
|
||||
if not conn:
|
||||
return make_error_response("Database connection failed", 500)
|
||||
|
||||
try:
|
||||
cursor = conn.cursor(dictionary=True)
|
||||
cursor.execute("SELECT * FROM orders WHERE id = %s", (order_id,))
|
||||
if not cursor.fetchone():
|
||||
return make_error_response("Order not found", 404)
|
||||
|
||||
cursor.execute(sql, params)
|
||||
conn.commit()
|
||||
|
||||
cursor.execute("SELECT * FROM orders WHERE id = %s", (order_id,))
|
||||
updated_order = cursor.fetchone()
|
||||
return make_success_response(updated_order, 200, "Order updated successfully.")
|
||||
except mysql.connector.Error as err:
|
||||
return make_error_response(f"Database error: {err}", 500)
|
||||
finally:
|
||||
if conn.is_connected():
|
||||
conn.close()
|
||||
|
||||
@app.route('/v1/orders/<int:order_id>', methods=['DELETE'])
|
||||
def delete_order(order_id):
|
||||
conn = get_db_connection()
|
||||
if not conn:
|
||||
return make_error_response("Database connection failed", 500)
|
||||
|
||||
try:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SELECT * FROM orders WHERE id = %s", (order_id,))
|
||||
if not cursor.fetchone():
|
||||
return make_error_response("Order not found", 404)
|
||||
|
||||
cursor.execute("DELETE FROM orders WHERE id = %s", (order_id,))
|
||||
conn.commit()
|
||||
return make_success_response(None, 204, "Order deleted successfully.")
|
||||
except mysql.connector.Error as err:
|
||||
return make_error_response(f"Database error: {err}", 500)
|
||||
finally:
|
||||
if conn.is_connected():
|
||||
conn.close()
|
||||
|
||||
# --- Menu Items API Endpoints ---
|
||||
|
||||
@app.route('/v1/menu_items', methods=['GET'])
|
||||
def get_menu_items():
|
||||
conn = get_db_connection()
|
||||
if not conn:
|
||||
return make_response("error", 503, "Database service unavailable.")
|
||||
cursor = conn.cursor(dictionary=True)
|
||||
|
||||
query = "SELECT * FROM menu_items WHERE 1=1"
|
||||
params = []
|
||||
|
||||
if 'id' in request.args:
|
||||
query += " AND id = %s"
|
||||
params.append(request.args['id'])
|
||||
if 'main_course' in request.args:
|
||||
query += " AND main_course LIKE %s"
|
||||
params.append(f"%{request.args['main_course']}%")
|
||||
if 'side_dish' in request.args:
|
||||
query += " AND side_dish LIKE %s"
|
||||
params.append(f"%{request.args['side_dish']}%")
|
||||
if 'addon' in request.args:
|
||||
query += " AND addon LIKE %s"
|
||||
params.append(f"%{request.args['addon']}%")
|
||||
if 'menu_date' in request.args:
|
||||
query += " AND menu_date = %s"
|
||||
params.append(request.args['menu_date'])
|
||||
|
||||
try:
|
||||
cursor.execute(query, tuple(params))
|
||||
items = cursor.fetchall()
|
||||
return make_response("success", 200, "Menu items retrieved successfully.", {"menu_items": items, "meta": {"total": len(items)}})
|
||||
except mysql.connector.Error as err:
|
||||
return make_response("error", 500, str(err))
|
||||
finally:
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
@app.route('/v1/menu_items/<int:item_id>', methods=['GET'])
|
||||
def get_menu_item(item_id):
|
||||
conn = get_db_connection()
|
||||
if not conn:
|
||||
return make_response("error", 503, "Database service unavailable.")
|
||||
cursor = conn.cursor(dictionary=True)
|
||||
|
||||
try:
|
||||
cursor.execute("SELECT * FROM menu_items WHERE id = %s", (item_id,))
|
||||
item = cursor.fetchone()
|
||||
if item:
|
||||
return make_response("success", 200, "Menu item found.", item)
|
||||
else:
|
||||
return make_response("error", 404, "Menu item not found.")
|
||||
except mysql.connector.Error as err:
|
||||
return make_response("error", 500, str(err))
|
||||
finally:
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
@app.route('/v1/menu_items', methods=['POST'])
|
||||
def create_menu_item():
|
||||
data = request.get_json()
|
||||
if not data or not all(k in data for k in ['main_course', 'side_dish', 'addon', 'menu_date']):
|
||||
return make_response("error", 400, "Missing required fields: main_course, side_dish, addon, menu_date.")
|
||||
|
||||
if not data:
|
||||
return make_error_response("Invalid JSON", 400)
|
||||
|
||||
required_fields = ['main_course', 'menu_date']
|
||||
if not all(field in data for field in required_fields):
|
||||
return make_error_response(f"Missing required fields: {required_fields}", 400)
|
||||
|
||||
sql = """
|
||||
INSERT INTO menu_items (main_course, side_dish, addon, menu_date)
|
||||
VALUES (%(main_course)s, %(side_dish)s, %(addon)s, %(menu_date)s)
|
||||
"""
|
||||
|
||||
conn = get_db_connection()
|
||||
if not conn:
|
||||
return make_response("error", 503, "Database service unavailable.")
|
||||
cursor = conn.cursor(dictionary=True)
|
||||
return make_error_response("Database connection failed", 500)
|
||||
|
||||
try:
|
||||
cursor = conn.cursor(dictionary=True)
|
||||
cursor.execute(sql, data)
|
||||
conn.commit()
|
||||
new_id = cursor.lastrowid
|
||||
cursor.execute("SELECT * FROM menu_items WHERE id = %s", (new_id,))
|
||||
new_item = cursor.fetchone()
|
||||
return make_success_response(new_item, 201, "Menu item created successfully.")
|
||||
except mysql.connector.Error as err:
|
||||
return make_error_response(f"Database error: {err}", 500)
|
||||
finally:
|
||||
if conn.is_connected():
|
||||
conn.close()
|
||||
|
||||
@app.route('/v1/menu_items/<int:item_id>', methods=['GET'])
|
||||
def get_menu_item_by_id(item_id):
|
||||
conn = get_db_connection()
|
||||
if not conn:
|
||||
return make_error_response("Database connection failed", 500)
|
||||
|
||||
try:
|
||||
cursor = conn.cursor(dictionary=True)
|
||||
cursor.execute("SELECT * FROM menu_items WHERE id = %s", (item_id,))
|
||||
item = cursor.fetchone()
|
||||
if item:
|
||||
return make_success_response(item, 200)
|
||||
else:
|
||||
return make_error_response("Menu item not found", 404)
|
||||
except mysql.connector.Error as err:
|
||||
return make_error_response(f"Database error: {err}", 500)
|
||||
finally:
|
||||
if conn.is_connected():
|
||||
conn.close()
|
||||
|
||||
@app.route('/v1/menu_items', methods=['GET'])
|
||||
def get_menu_items():
|
||||
query_params = request.args.to_dict()
|
||||
|
||||
sql = "SELECT * FROM menu_items"
|
||||
conditions = []
|
||||
params = {}
|
||||
|
||||
for key, value in query_params.items():
|
||||
conditions.append(f"{key} = %({key})s")
|
||||
params[key] = value
|
||||
|
||||
if conditions:
|
||||
sql += " WHERE " + " AND ".join(conditions)
|
||||
|
||||
conn = get_db_connection()
|
||||
if not conn:
|
||||
return make_error_response("Database connection failed", 500)
|
||||
|
||||
try:
|
||||
sql = "INSERT INTO menu_items (main_course, side_dish, addon, menu_date) VALUES (%s, %s, %s, %s)"
|
||||
params = (data['main_course'], data['side_dish'], data['addon'], data['menu_date'])
|
||||
cursor = conn.cursor(dictionary=True)
|
||||
cursor.execute(sql, params)
|
||||
new_item_id = cursor.lastrowid
|
||||
conn.commit()
|
||||
items = cursor.fetchall()
|
||||
|
||||
cursor.execute("SELECT * FROM menu_items WHERE id = %s", (new_item_id,))
|
||||
new_item = cursor.fetchone()
|
||||
return make_response("success", 201, "Menu item created successfully.", new_item)
|
||||
meta = {
|
||||
"total_items": len(items),
|
||||
"query_params": query_params
|
||||
}
|
||||
data = {
|
||||
"menu_items": items,
|
||||
"meta": meta
|
||||
}
|
||||
return make_success_response(data, 200)
|
||||
except mysql.connector.Error as err:
|
||||
conn.rollback()
|
||||
return make_response("error", 500, str(err))
|
||||
return make_error_response(f"Database error: {err}", 500)
|
||||
finally:
|
||||
cursor.close()
|
||||
conn.close()
|
||||
if conn.is_connected():
|
||||
conn.close()
|
||||
|
||||
@app.route('/v1/menu_items/<int:item_id>', methods=['PATCH'])
|
||||
def update_menu_item(item_id):
|
||||
data = request.get_json()
|
||||
if not data:
|
||||
return make_response("error", 400, "No update data provided.")
|
||||
return make_error_response("Invalid JSON", 400)
|
||||
|
||||
set_clauses = []
|
||||
params = {}
|
||||
for key, value in data.items():
|
||||
set_clauses.append(f"{key} = %({key})s")
|
||||
params[key] = value
|
||||
|
||||
if not set_clauses:
|
||||
return make_error_response("No fields to update", 400)
|
||||
|
||||
params['id'] = item_id
|
||||
sql = f"UPDATE menu_items SET {', '.join(set_clauses)} WHERE id = %(id)s"
|
||||
|
||||
conn = get_db_connection()
|
||||
if not conn:
|
||||
return make_response("error", 503, "Database service unavailable.")
|
||||
cursor = conn.cursor(dictionary=True)
|
||||
|
||||
updates = []
|
||||
params = []
|
||||
for key in ['main_course', 'side_dish', 'addon', 'menu_date']:
|
||||
if key in data:
|
||||
updates.append(f"{key} = %s")
|
||||
params.append(data[key])
|
||||
|
||||
if not updates:
|
||||
return make_response("error", 400, "No valid fields to update.")
|
||||
|
||||
params.append(item_id)
|
||||
query = f"UPDATE menu_items SET {', '.join(updates)} WHERE id = %s"
|
||||
return make_error_response("Database connection failed", 500)
|
||||
|
||||
try:
|
||||
cursor.execute(query, tuple(params))
|
||||
cursor = conn.cursor(dictionary=True)
|
||||
cursor.execute("SELECT * FROM menu_items WHERE id = %s", (item_id,))
|
||||
if not cursor.fetchone():
|
||||
return make_error_response("Menu item not found", 404)
|
||||
|
||||
cursor.execute(sql, params)
|
||||
conn.commit()
|
||||
if cursor.rowcount == 0:
|
||||
return make_response("error", 404, "Menu item not found or data is the same.")
|
||||
|
||||
cursor.execute("SELECT * FROM menu_items WHERE id = %s", (item_id,))
|
||||
updated_item = cursor.fetchone()
|
||||
return make_response("success", 200, "Menu item updated successfully.", updated_item)
|
||||
return make_success_response(updated_item, 200, "Menu item updated successfully.")
|
||||
except mysql.connector.Error as err:
|
||||
conn.rollback()
|
||||
return make_response("error", 500, str(err))
|
||||
return make_error_response(f"Database error: {err}", 500)
|
||||
finally:
|
||||
cursor.close()
|
||||
conn.close()
|
||||
if conn.is_connected():
|
||||
conn.close()
|
||||
|
||||
@app.route('/v1/menu_items/<int:item_id>', methods=['DELETE'])
|
||||
def delete_menu_item(item_id):
|
||||
conn = get_db_connection()
|
||||
if not conn:
|
||||
return make_response("error", 503, "Database service unavailable.")
|
||||
cursor = conn.cursor()
|
||||
return make_error_response("Database connection failed", 500)
|
||||
|
||||
try:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SELECT * FROM menu_items WHERE id = %s", (item_id,))
|
||||
if not cursor.fetchone():
|
||||
return make_error_response("Menu item not found", 404)
|
||||
|
||||
cursor.execute("DELETE FROM menu_items WHERE id = %s", (item_id,))
|
||||
conn.commit()
|
||||
if cursor.rowcount == 0:
|
||||
return make_response("error", 404, "Menu item not found.")
|
||||
return make_response("success", 204, "Menu item deleted successfully.")
|
||||
return make_success_response(None, 204, "Menu item deleted successfully.")
|
||||
except mysql.connector.Error as err:
|
||||
conn.rollback()
|
||||
if err.errno == 1451:
|
||||
return make_response("error", 409, "Cannot delete menu item that has been voted on.")
|
||||
return make_response("error", 500, str(err))
|
||||
return make_error_response(f"Database error: {err}", 500)
|
||||
finally:
|
||||
cursor.close()
|
||||
conn.close()
|
||||
if conn.is_connected():
|
||||
conn.close()
|
||||
|
||||
|
||||
# --- Employee Votes API Endpoints ---
|
||||
|
||||
@app.route('/v1/employee_votes', methods=['GET'])
|
||||
def get_employee_votes():
|
||||
conn = get_db_connection()
|
||||
if not conn:
|
||||
return make_response("error", 503, "Database service unavailable.")
|
||||
cursor = conn.cursor(dictionary=True)
|
||||
|
||||
query = """
|
||||
SELECT v.*, e.name
|
||||
FROM employee_votes v
|
||||
JOIN employee e ON v.emp_id = e.id
|
||||
WHERE 1=1
|
||||
"""
|
||||
params = []
|
||||
|
||||
if 'id' in request.args:
|
||||
query += " AND v.id = %s"
|
||||
params.append(request.args['id'])
|
||||
if 'emp_id' in request.args:
|
||||
query += " AND v.emp_id = %s"
|
||||
params.append(request.args['emp_id'])
|
||||
if 'name' in request.args: # Search by employee name
|
||||
query += " AND e.name LIKE %s"
|
||||
params.append(f"%{request.args['name']}%")
|
||||
if 'order_date' in request.args:
|
||||
query += " AND v.order_date = %s"
|
||||
params.append(request.args['order_date'])
|
||||
if 'menu_item_id' in request.args:
|
||||
query += " AND v.menu_item_id = %s"
|
||||
params.append(request.args['menu_item_id'])
|
||||
if 'order_qty' in request.args:
|
||||
query += " AND v.order_qty = %s"
|
||||
params.append(request.args['order_qty'])
|
||||
|
||||
try:
|
||||
cursor.execute(query, tuple(params))
|
||||
votes = cursor.fetchall()
|
||||
return make_response("success", 200, "Employee votes retrieved successfully.", {"employee_votes": votes, "meta": {"total": len(votes)}})
|
||||
except mysql.connector.Error as err:
|
||||
return make_response("error", 500, str(err))
|
||||
finally:
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
@app.route('/v1/employee_votes/<int:vote_id>', methods=['GET'])
|
||||
def get_employee_vote(vote_id):
|
||||
conn = get_db_connection()
|
||||
if not conn:
|
||||
return make_response("error", 503, "Database service unavailable.")
|
||||
cursor = conn.cursor(dictionary=True)
|
||||
|
||||
try:
|
||||
cursor.execute("""
|
||||
SELECT v.*, e.name
|
||||
FROM employee_votes v
|
||||
JOIN employee e ON v.emp_id = e.id
|
||||
WHERE v.id = %s
|
||||
""", (vote_id,))
|
||||
vote = cursor.fetchone()
|
||||
if vote:
|
||||
return make_response("success", 200, "Employee vote found.", vote)
|
||||
else:
|
||||
return make_response("error", 404, "Employee vote not found.")
|
||||
except mysql.connector.Error as err:
|
||||
return make_response("error", 500, str(err))
|
||||
finally:
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
@app.route('/v1/employee_votes', methods=['POST'])
|
||||
def create_employee_vote():
|
||||
data = request.get_json()
|
||||
required_fields = ['emp_id', 'order_date', 'menu_item_id', 'order_qty']
|
||||
if not data or not all(k in data for k in required_fields):
|
||||
return make_response("error", 400, f"Missing required fields: {', '.join(required_fields)}.")
|
||||
|
||||
conn = get_db_connection()
|
||||
if not conn:
|
||||
return make_response("error", 503, "Database service unavailable.")
|
||||
cursor = conn.cursor(dictionary=True)
|
||||
|
||||
try:
|
||||
sql = "INSERT INTO employee_votes (emp_id, order_date, menu_item_id, order_qty) VALUES (%s, %s, %s, %s)"
|
||||
params = (data['emp_id'], data['order_date'], data['menu_item_id'], data['order_qty'])
|
||||
cursor.execute(sql, params)
|
||||
new_vote_id = cursor.lastrowid
|
||||
conn.commit()
|
||||
|
||||
cursor.execute("""
|
||||
SELECT v.*, e.name
|
||||
FROM employee_votes v
|
||||
JOIN employee e ON v.emp_id = e.id
|
||||
WHERE v.id = %s
|
||||
""", (new_vote_id,))
|
||||
new_vote = cursor.fetchone()
|
||||
return make_response("success", 201, "Employee vote created successfully.", new_vote)
|
||||
except mysql.connector.Error as err:
|
||||
conn.rollback()
|
||||
if err.errno == 1452: # Foreign key constraint fails
|
||||
return make_response("error", 400, "Invalid emp_id or menu_item_id. The specified employee or menu item does not exist.")
|
||||
return make_response("error", 500, str(err))
|
||||
finally:
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
@app.route('/v1/employee_votes/<int:vote_id>', methods=['PATCH'])
|
||||
def update_employee_vote(vote_id):
|
||||
data = request.get_json()
|
||||
if not data:
|
||||
return make_response("error", 400, "No update data provided.")
|
||||
|
||||
conn = get_db_connection()
|
||||
if not conn:
|
||||
return make_response("error", 503, "Database service unavailable.")
|
||||
cursor = conn.cursor(dictionary=True)
|
||||
|
||||
updates = []
|
||||
params = []
|
||||
for key in ['emp_id', 'order_date', 'menu_item_id', 'order_qty']:
|
||||
if key in data:
|
||||
updates.append(f"{key} = %s")
|
||||
params.append(data[key])
|
||||
|
||||
if not updates:
|
||||
return make_response("error", 400, "No valid fields to update.")
|
||||
|
||||
params.append(vote_id)
|
||||
query = f"UPDATE employee_votes SET {', '.join(updates)} WHERE id = %s"
|
||||
|
||||
try:
|
||||
cursor.execute(query, tuple(params))
|
||||
conn.commit()
|
||||
if cursor.rowcount == 0:
|
||||
return make_response("error", 404, "Employee vote not found or data is the same.")
|
||||
|
||||
cursor.execute("""
|
||||
SELECT v.*, e.name
|
||||
FROM employee_votes v
|
||||
JOIN employee e ON v.emp_id = e.id
|
||||
WHERE v.id = %s
|
||||
""", (vote_id,))
|
||||
updated_vote = cursor.fetchone()
|
||||
return make_response("success", 200, "Employee vote updated successfully.", updated_vote)
|
||||
except mysql.connector.Error as err:
|
||||
conn.rollback()
|
||||
if err.errno == 1452:
|
||||
return make_response("error", 400, "Invalid emp_id or menu_item_id. The specified employee or menu item does not exist.")
|
||||
return make_response("error", 500, str(err))
|
||||
finally:
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
@app.route('/v1/employee_votes/<int:vote_id>', methods=['DELETE'])
|
||||
def delete_employee_vote(vote_id):
|
||||
conn = get_db_connection()
|
||||
if not conn:
|
||||
return make_response("error", 503, "Database service unavailable.")
|
||||
cursor = conn.cursor()
|
||||
|
||||
try:
|
||||
cursor.execute("DELETE FROM employee_votes WHERE id = %s", (vote_id,))
|
||||
conn.commit()
|
||||
if cursor.rowcount == 0:
|
||||
return make_response("error", 404, "Employee vote not found.")
|
||||
return make_response("success", 204, "Employee vote deleted successfully.")
|
||||
except mysql.connector.Error as err:
|
||||
conn.rollback()
|
||||
return make_response("error", 500, str(err))
|
||||
finally:
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
# --- Main Execution ---
|
||||
if __name__ == '__main__':
|
||||
# To run this server:
|
||||
# 1. Make sure you have Flask, Flask-Cors, and mysql-connector-python installed:
|
||||
# pip install Flask Flask-Cors mysql-connector-python
|
||||
# 2. Run the script:
|
||||
# python api_server.py
|
||||
# The server will start on http://127.0.0.1:5000
|
||||
app.run(debug=True, host='0.0.0.0', port=5000)
|
||||
app.run(host='0.0.0.0', port=5000, debug=True)
|
@@ -1,44 +0,0 @@
|
||||
請產生一支可直接執行的 Flask API 伺服器,需求:
|
||||
- 使用 mysql.connector 連線
|
||||
|
||||
資料庫資訊:
|
||||
DB_HOST = mysql.theaken.com
|
||||
DB_PORT = 33306
|
||||
DB_NAME = db_A027
|
||||
DB_USER = A027
|
||||
DB_PASSWORD = E1CelfxqlKoj
|
||||
|
||||
TABLE = employee
|
||||
- 路由:
|
||||
- GET /v1/employee:支援 ?Id、?main_course、?side_dish、?addon、?is_active,要多回傳 {meta}
|
||||
- GET /v1/employee/<id>:找不到回 404
|
||||
- POST /v1/employee:接收 JSON {ID,main_course,side_dish,addon,is_active},欄位驗證,成功回 201 並回新資料
|
||||
- PATCH /v1/employee/<id>:可更新任一欄位(ID/main_course/side_dish/addon/is_active),成功回 200 回更新後資料
|
||||
- DELETE /v1/employee/<id>:成功回 204
|
||||
|
||||
TABLE = employee_votes
|
||||
- 路由:
|
||||
- GET /v1/employee_votes:支援 ?Id、?emp_id、?name、?order_date、?menu_item_id、?order_qty,要多回傳 {meta}
|
||||
- GET /v1/employee_votes/<id>:找不到回 404
|
||||
- POST /v1/employee_votes:接收 JSON {Id,emp_id,name,order_date,menu_item_id,order_qty},欄位驗證,成功回 201 並回新資料
|
||||
- PATCH /v1/employee_votes/<id>:可更新任一欄位(Id/emp_id/name/order_date/menu_item_id/order_qty),成功回 200 回更新後資料
|
||||
- DELETE /v1/employee_votes/<id>:成功回 204
|
||||
|
||||
|
||||
TABLE = menu_items
|
||||
- 路由:
|
||||
- GET /v1/menu_items:支援 ?Id、?main_course、?side_dish、?addon、?is_active,要多回傳 {meta}
|
||||
- GET /v1/menu_items/<id>:找不到回 404
|
||||
- POST /v1/menu_items:接收 JSON {ID,main_course,side_dish,addon,is_active},欄位驗證,成功回 201 並回新資料
|
||||
- PATCH /v1/menu_items/<id>:可更新任一欄位(ID/main_course/side_dish/addon/is_active),成功回 200 回更新後資料
|
||||
- DELETE /v1/menu_items/<id>:成功回 204
|
||||
|
||||
|
||||
|
||||
- 所有寫入請用參數化查詢避免 SQL 注入
|
||||
|
||||
- 統一格式 { status,code,message,data }
|
||||
|
||||
- 統一錯誤格式 {status:"error", code, message}
|
||||
|
||||
- 啟用 CORS(允許本機前端)
|
@@ -1,29 +0,0 @@
|
||||
請根據以下需求幫我產生一段 Python 程式碼,能夠連線到資料庫並建立三張employee、 menu_items、employee_votes 資料表。
|
||||
|
||||
資料庫資訊:
|
||||
DB_HOST = mysql.theaken.com
|
||||
DB_PORT = 33306
|
||||
DB_NAME = db_A027
|
||||
DB_USER = A027
|
||||
DB_PASSWORD = E1CelfxqlKoj
|
||||
|
||||
需求:
|
||||
1. 使用 mysql.connector 套件。
|
||||
2. 建立三張名稱為employee、 menu_items、employee_votes 的資料表,包含以下欄位:
|
||||
2.1 TABLE名稱 employee(員工檔)
|
||||
-id : 員工工號(NVARCHAR)
|
||||
-name : 員工姓名(NVARCHAR)
|
||||
|
||||
2.2 menu_items(菜色基本資料)
|
||||
-id : NUMBER(自動編號)
|
||||
-main_course : 主餐(NVARCHAR)
|
||||
-side_dish : 副餐(NVARCHAR)
|
||||
-addon : 湯品/甜點(NVARCHAR)
|
||||
-menu_date :當天菜色(DATE)
|
||||
|
||||
2.3 employee_votes(餐點訂購檔)
|
||||
-id : NUMBER(自動編號)
|
||||
-emp_id : 工號(NVARCHAR)
|
||||
-order_date : 訂餐日期(DATE)
|
||||
-menu_item_id: 投票選擇的餐點(NUMBER)
|
||||
-order_qty : 訂餐份數(NUMBER)
|
@@ -1,70 +0,0 @@
|
||||
|
||||
import mysql.connector
|
||||
|
||||
# Database connection details
|
||||
DB_HOST = "mysql.theaken.com"
|
||||
DB_PORT = 33306
|
||||
DB_NAME = "db_A027"
|
||||
DB_USER = "A027"
|
||||
DB_PASSWORD = "E1CelfxqlKoj"
|
||||
|
||||
try:
|
||||
# Establish the connection
|
||||
conn = mysql.connector.connect(
|
||||
host=DB_HOST,
|
||||
port=DB_PORT,
|
||||
database=DB_NAME,
|
||||
user=DB_USER,
|
||||
password=DB_PASSWORD
|
||||
)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# SQL statements to create tables
|
||||
create_employee_table = """
|
||||
CREATE TABLE IF NOT EXISTS employee (
|
||||
id NVARCHAR(255) PRIMARY KEY,
|
||||
name NVARCHAR(255)
|
||||
)
|
||||
"""
|
||||
|
||||
create_menu_items_table = """
|
||||
CREATE TABLE IF NOT EXISTS menu_items (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
main_course NVARCHAR(255),
|
||||
side_dish NVARCHAR(255),
|
||||
addon NVARCHAR(255),
|
||||
menu_date DATE
|
||||
)
|
||||
"""
|
||||
|
||||
create_employee_votes_table = """
|
||||
CREATE TABLE IF NOT EXISTS employee_votes (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
emp_id NVARCHAR(255),
|
||||
order_date DATE,
|
||||
menu_item_id INT,
|
||||
order_qty INT,
|
||||
FOREIGN KEY (emp_id) REFERENCES employee(id),
|
||||
FOREIGN KEY (menu_item_id) REFERENCES menu_items(id)
|
||||
)
|
||||
"""
|
||||
|
||||
# Execute the create table statements
|
||||
cursor.execute(create_employee_table)
|
||||
print("Table 'employee' created successfully.")
|
||||
|
||||
cursor.execute(create_menu_items_table)
|
||||
print("Table 'menu_items' created successfully.")
|
||||
|
||||
cursor.execute(create_employee_votes_table)
|
||||
print("Table 'employee_votes' created successfully.")
|
||||
|
||||
except mysql.connector.Error as err:
|
||||
print(f"Error: {err}")
|
||||
|
||||
finally:
|
||||
# Close the connection
|
||||
if 'conn' in locals() and conn.is_connected():
|
||||
cursor.close()
|
||||
conn.close()
|
||||
print("MySQL connection is closed.")
|
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
Reference in New Issue
Block a user