上傳檔案到「/」

-- 指定專案資料夾
cd /employee_votes

-- gitea 初始化
git init 

-- 建立註解
git add . 
git commit -m "Initial commit" 

-- 切換到 main 分支
git branch -M main

-- 上傳檔案到 gitea
git remote add origin https://github.com/91771/<REPO>.git 
git push -u origin main
This commit is contained in:
2025-09-17 15:18:20 +08:00
commit 314474a682
5 changed files with 1251 additions and 0 deletions

391
api_server.py Normal file
View File

@@ -0,0 +1,391 @@
from flask import Flask, request, jsonify, render_template
from flask_cors import CORS
import mysql.connector
from mysql.connector import Error
from datetime import datetime
import re
app = Flask(__name__)
CORS(app) # 啟用CORS允許本機前端訪問
# 資料庫連接設定 - 從DB_connection.txt獲取
DB_CONFIG = {
'host': 'mysql.theaken.com',
'database': 'db_A019',
'user': 'A019',
'password': '9wvKEkxBzVca',
'port': 33306
}
def get_db_connection():
"""建立資料庫連接"""
try:
connection = mysql.connector.connect(**DB_CONFIG)
return connection
except Error as e:
print(f"資料庫連接錯誤: {e}")
return None
def validate_email(email):
"""驗證email格式"""
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
return re.match(pattern, email) is not None
def validate_age(age):
"""驗證年齡範圍"""
try:
age_int = int(age)
return 1 <= age_int <= 120
except ValueError:
return False
@app.route('/v1/menu_items', methods=['GET'])
def get_menu_items():
"""
GET /v1/menu_items - 查詢menu_items資料表
支援查詢參數: ?main_course, ?side_dish, ?addon, ?Order_Date, ?is_active
"""
try:
# 獲取查詢參數
main_course = request.args.get('main_course')
side_dish = request.args.get('side_dish')
addon = request.args.get('addon')
order_date = request.args.get('Order_Date')
is_active = request.args.get('is_active')
connection = get_db_connection()
if connection is None:
return jsonify({
'status': 'error',
'code': 500,
'message': '無法連接資料庫'
}), 500
cursor = connection.cursor(dictionary=True)
# 建立查詢條件
query = "SELECT * FROM menu_items WHERE 1=1"
params = []
if main_course:
query += " AND main_course LIKE %s"
params.append(f"%{main_course}%")
if side_dish:
query += " AND side_dish LIKE %s"
params.append(f"%{side_dish}%")
if addon:
query += " AND addon LIKE %s"
params.append(f"%{addon}%")
if order_date:
query += " AND Order_Date = %s"
params.append(order_date)
if is_active is not None:
query += " AND is_active = %s"
params.append(is_active.lower() in ['true', '1', 'yes'])
# 執行查詢
cursor.execute(query, params)
results = cursor.fetchall()
# 獲取總數用於meta資訊
count_query = "SELECT COUNT(*) as total FROM menu_items WHERE 1=1" + query.split('WHERE 1=1')[1]
cursor.execute(count_query, params)
total_count = cursor.fetchone()['total']
cursor.close()
connection.close()
return jsonify({
'status': 'success',
'code': 200,
'message': '查詢成功',
'data': results,
'meta': {
'total': total_count,
'page': 1,
'per_page': len(results),
'has_more': False
}
})
except Error as e:
return jsonify({
'status': 'error',
'code': 500,
'message': f'資料庫查詢錯誤: {str(e)}'
}), 500
@app.route('/v1/menu_items/<int:item_id>', methods=['GET'])
def get_menu_item(item_id):
"""GET /v1/menu_items/<id> - 根據ID獲取單個menu_item"""
try:
connection = get_db_connection()
if connection is None:
return jsonify({
'status': 'error',
'code': 500,
'message': '無法連接資料庫'
}), 500
cursor = connection.cursor(dictionary=True)
cursor.execute("SELECT * FROM menu_items WHERE Id = %s", (item_id,))
result = cursor.fetchone()
cursor.close()
connection.close()
if result is None:
return jsonify({
'status': 'error',
'code': 404,
'message': '找不到指定的menu_item'
}), 404
return jsonify({
'status': 'success',
'code': 200,
'message': '查詢成功',
'data': result
})
except Error as e:
return jsonify({
'status': 'error',
'code': 500,
'message': f'資料庫查詢錯誤: {str(e)}'
}), 500
@app.route('/v1/menu_items', methods=['POST'])
def create_menu_item():
"""POST /v1/menu_items - 創建新的menu_item"""
try:
data = request.get_json()
# 驗證必要欄位
required_fields = ['name', 'email', 'age']
for field in required_fields:
if field not in data or not data[field]:
return jsonify({
'status': 'error',
'code': 400,
'message': f'缺少必要欄位: {field}'
}), 400
# 驗證email格式
if not validate_email(data['email']):
return jsonify({
'status': 'error',
'code': 400,
'message': 'email格式不正確'
}), 400
# 驗證年齡範圍
if not validate_age(data['age']):
return jsonify({
'status': 'error',
'code': 400,
'message': '年齡必須是1-120之間的數字'
}), 400
connection = get_db_connection()
if connection is None:
return jsonify({
'status': 'error',
'code': 500,
'message': '無法連接資料庫'
}), 500
cursor = connection.cursor()
# 使用參數化查詢避免SQL注入
query = """
INSERT INTO menu_items (main_course, side_dish, addon, Order_Date, is_active)
VALUES (%s, %s, %s, %s, %s)
"""
# 這裡使用範例資料,您可以根據實際需求調整
params = (
data.get('main_course', '預設主餐'),
data.get('side_dish', '預設副餐'),
data.get('addon', '預設湯品'),
datetime.now().strftime('%Y-%m-%d'),
True
)
cursor.execute(query, params)
connection.commit()
# 獲取新創建的資料ID
new_id = cursor.lastrowid
cursor.close()
connection.close()
return jsonify({
'status': 'success',
'code': 201,
'message': '創建成功',
'data': {
'id': new_id,
'main_course': params[0],
'side_dish': params[1],
'addon': params[2],
'Order_Date': params[3],
'is_active': params[4]
}
}), 201
except Error as e:
return jsonify({
'status': 'error',
'code': 500,
'message': f'資料庫操作錯誤: {str(e)}'
}), 500
@app.route('/v1/menu_items/<int:item_id>', methods=['PATCH'])
def update_menu_item(item_id):
"""PATCH /v1/menu_items/<id> - 更新menu_item的任一欄位"""
try:
data = request.get_json()
# 檢查是否有可更新的欄位
allowed_fields = ['main_course', 'side_dish', 'addon', 'Order_Date', 'is_active']
update_fields = {}
for field in allowed_fields:
if field in data:
update_fields[field] = data[field]
if not update_fields:
return jsonify({
'status': 'error',
'code': 400,
'message': '沒有提供可更新的欄位'
}), 400
connection = get_db_connection()
if connection is None:
return jsonify({
'status': 'error',
'code': 500,
'message': '無法連接資料庫'
}), 500
cursor = connection.cursor(dictionary=True)
# 檢查資料是否存在
cursor.execute("SELECT * FROM menu_items WHERE Id = %s", (item_id,))
if cursor.fetchone() is None:
cursor.close()
connection.close()
return jsonify({
'status': 'error',
'code': 404,
'message': '找不到指定的menu_item'
}), 404
# 建立更新查詢
set_clause = ", ".join([f"{field} = %s" for field in update_fields.keys()])
query = f"UPDATE menu_items SET {set_clause} WHERE Id = %s"
params = list(update_fields.values())
params.append(item_id)
cursor.execute(query, params)
connection.commit()
# 獲取更新後的資料
cursor.execute("SELECT * FROM menu_items WHERE Id = %s", (item_id,))
updated_data = cursor.fetchone()
cursor.close()
connection.close()
return jsonify({
'status': 'success',
'code': 200,
'message': '更新成功',
'data': updated_data
})
except Error as e:
return jsonify({
'status': 'error',
'code': 500,
'message': f'資料庫操作錯誤: {str(e)}'
}), 500
@app.route('/v1/menu_items/<int:item_id>', methods=['DELETE'])
def delete_menu_item(item_id):
"""DELETE /v1/menu_items/<id> - 刪除menu_item"""
try:
connection = get_db_connection()
if connection is None:
return jsonify({
'status': 'error',
'code': 500,
'message': '無法連接資料庫'
}), 500
cursor = connection.cursor()
# 檢查資料是否存在
cursor.execute("SELECT * FROM menu_items WHERE Id = %s", (item_id,))
if cursor.fetchone() is None:
cursor.close()
connection.close()
return jsonify({
'status': 'error',
'code': 404,
'message': '找不到指定的menu_item'
}), 404
# 執行刪除
cursor.execute("DELETE FROM menu_items WHERE Id = %s", (item_id,))
connection.commit()
cursor.close()
connection.close()
return '', 204
except Error as e:
return jsonify({
'status': 'error',
'code': 500,
'message': f'資料庫操作錯誤: {str(e)}'
}), 500
@app.errorhandler(404)
def not_found(error):
return jsonify({
'status': 'error',
'code': 404,
'message': 'API端點不存在'
}), 404
@app.errorhandler(500)
def internal_error(error):
return jsonify({
'status': 'error',
'code': 500,
'message': '伺服器內部錯誤'
}), 500
@app.route('/menu-form')
def menu_form():
return render_template('menu_form.html')
if __name__ == '__main__':
print("啟動Flask API伺服器...")
print("可用端點:")
print(" GET /v1/menu_items")
print(" GET /v1/menu_items/<id>")
print(" POST /v1/menu_items")
print(" PATCH /v1/menu_items/<id>")
print(" DELETE /v1/menu_items/<id>")
app.run(debug=True, host='0.0.0.0', port=5000)