Spaces:
Sleeping
Sleeping
""" | |
MySQL ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ๋ฐ ์ต๋๋ฌผ ๋ฐ์ดํฐ ์กฐํ ๋ชจ๋ | |
""" | |
import os | |
import logging | |
import traceback | |
import pymysql | |
from pymysql.cursors import DictCursor | |
from contextlib import contextmanager | |
# ๋ก๊น ์ค์ | |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') | |
logger = logging.getLogger(__name__) | |
# ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ์ค์ | |
DB_CONFIG = { | |
'host': os.getenv('DB_HOST', 'localhost'), | |
'port': int(os.getenv('DB_PORT', 3306)), | |
'user': os.getenv('DB_USER', 'username'), | |
'password': os.getenv('DB_PASSWORD', 'password'), | |
'db': os.getenv('DB_NAME', 'foundlost'), | |
'charset': 'utf8mb4', | |
'cursorclass': DictCursor | |
} | |
def get_db_connection(): | |
""" | |
๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ์ ์ ๊ณตํ๋ ์ปจํ ์คํธ ๋งค๋์ | |
Yields: | |
pymysql.connections.Connection: ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ๊ฐ์ฒด | |
""" | |
connection = None | |
try: | |
connection = pymysql.connect(**DB_CONFIG) | |
logger.info("๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ์ฑ๊ณต") | |
yield connection | |
except Exception as e: | |
logger.error(f"๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ์ค๋ฅ: {str(e)}") | |
logger.error(traceback.format_exc()) | |
raise | |
finally: | |
if connection: | |
connection.close() | |
logger.debug("๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ์ข ๋ฃ") | |
async def fetch_found_items(limit=100, offset=0): | |
""" | |
MySQL ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ต๋๋ฌผ ๋ฐ์ดํฐ๋ฅผ ์กฐํ | |
Args: | |
limit (int): ์กฐํํ ์ต๋ ํญ๋ชฉ ์ (๊ธฐ๋ณธ๊ฐ: 100) | |
offset (int): ์กฐํ ์์ ์์น (๊ธฐ๋ณธ๊ฐ: 0) | |
Returns: | |
list: ์ต๋๋ฌผ ๋ฐ์ดํฐ ๋ชฉ๋ก | |
""" | |
found_items = [] | |
try: | |
with get_db_connection() as connection: | |
with connection.cursor() as cursor: | |
query = """ | |
SELECT f.id, f.user_id, f.item_category_id, f.name as title, f.color, | |
f.detail as content, f.location, f.image, f.status, f.found_at as lost_at, | |
f.created_at, f.management_id, f.stored_at, | |
ic.name as category_name, | |
ic.level as majorCategory, # major_category ๋์ level ์ฌ์ฉ | |
ic.name as minorCategory | |
FROM found_item f | |
LEFT JOIN item_category ic ON f.item_category_id = ic.id | |
WHERE f.status IN ('STORED', 'RECEIVED', 'TRANSFERRED') | |
ORDER BY f.created_at DESC | |
LIMIT %s OFFSET %s | |
""" | |
cursor.execute(query, (limit, offset)) | |
rows = cursor.fetchall() | |
# ์กฐํ ๊ฒฐ๊ณผ๋ฅผ API ์๋ต ํ์์ ๋ง๊ฒ ๋ณํ | |
for row in rows: | |
found_item = { | |
"id": row["id"], | |
"user_id": row["user_id"], | |
"item_category_id": row["item_category_id"], | |
"title": row["title"], # name ์ปฌ๋ผ์ title๋ก ๋งคํ | |
"color": row["color"], | |
"content": row["content"], # detail ์ปฌ๋ผ์ content๋ก ๋งคํ | |
"location": row["location"], | |
"image": row["image"], | |
"status": row["status"], | |
"lost_at": row["lost_at"], | |
"stored_at": row["stored_at"], | |
"management_id": row["management_id"], | |
"category": row["category_name"], # ์นดํ ๊ณ ๋ฆฌ๋ช ์ถ๊ฐ | |
"majorCategory": row["majorCategory"], | |
"minorCategory": row["minorCategory"] | |
} | |
found_items.append(found_item) | |
logger.info(f"{len(found_items)}๊ฐ์ ์ต๋๋ฌผ ๋ฐ์ดํฐ ์กฐํ ์๋ฃ") | |
except Exception as e: | |
logger.error(f"์ต๋๋ฌผ ๋ฐ์ดํฐ ์กฐํ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}") | |
logger.error(traceback.format_exc()) | |
return found_items | |
# ์ต๋๋ฌผ ๋ฐ์ดํฐ ๊ฐ์ ์กฐํ ํจ์ | |
async def count_found_items(): | |
""" | |
MySQL ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ต๋๋ฌผ ๋ฐ์ดํฐ์ ์ด ๊ฐ์๋ฅผ ์กฐํ | |
Returns: | |
int: ์ต๋๋ฌผ ๋ฐ์ดํฐ ์ด ๊ฐ์ | |
""" | |
try: | |
with get_db_connection() as connection: | |
with connection.cursor() as cursor: | |
# status๊ฐ 'STORED'์ธ ํญ๋ชฉ๋ง ์กฐํ | |
query = "SELECT COUNT(*) as total FROM found_item WHERE status IN ('STORED', 'RECEIVED', 'TRANSFERRED')" | |
cursor.execute(query) | |
result = cursor.fetchone() | |
total_count = result["total"] | |
logger.info(f"์ด ์ต๋๋ฌผ ๋ฐ์ดํฐ ๊ฐ์: {total_count}") | |
return total_count | |
except Exception as e: | |
logger.error(f"์ต๋๋ฌผ ๋ฐ์ดํฐ ๊ฐ์ ์กฐํ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}") | |
logger.error(traceback.format_exc()) | |
return 0 | |
# ๋ถ์ค๋ฌผ ๋ชฉ๋ก์ ๊ฐ์ ธ์ค๋ ํจ์ | |
async def fetch_lost_items(limit=100, offset=0): | |
""" | |
๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๋ถ์ค๋ฌผ ๋ชฉ๋ก์ ๊ฐ์ ธ์ค๋ ํจ์ | |
Args: | |
limit (int): ์กฐํํ ์ต๋ ํญ๋ชฉ ์ (๊ธฐ๋ณธ๊ฐ: 100) | |
offset (int): ์กฐํ ์์ ์์น (๊ธฐ๋ณธ๊ฐ: 0) | |
Returns: | |
list: ๋ถ์ค๋ฌผ ๋ฐ์ดํฐ ๋ชฉ๋ก | |
""" | |
try: | |
# ํ๊ฒฝ๋ณ์ ํ์ธ - ํ ์คํธ ๋ชจ๋์ธ ๊ฒฝ์ฐ ์ํ ๋ฐ์ดํฐ ๋ฐํ | |
if os.getenv('APP_ENV') == 'test': | |
logger.info("ํ ์คํธ ๋ชจ๋: ์ํ ๋ฐ์ดํฐ ์ฌ์ฉ") | |
# ์์ ๋ฐ์ดํฐ - ํ ์คํธ์ฉ | |
sample_lost_items = [ | |
{ | |
"id": 1, | |
"item_category_id": 1, | |
"title": "๊ฒ์ ๊ฐ์ฃฝ ์ง๊ฐ", | |
"color": "๊ฒ์ ์", | |
"content": "๊ฐ๋จ์ญ ๊ทผ์ฒ์์ ๊ฒ์ ์ ๊ฐ์ฃฝ ์ง๊ฐ์ ์์ด๋ฒ๋ ธ์ต๋๋ค.", | |
"location": "๊ฐ๋จ์ญ", | |
"image": None, | |
"category": "์ง๊ฐ" | |
}, | |
{ | |
"id": 2, | |
"item_category_id": 1, | |
"title": "๊ฐ์ ๊ฐ์ฃฝ ์ง๊ฐ", | |
"color": "๊ฐ์", | |
"content": "์์ธ๋์ ๊ตฌ์ญ ๊ทผ์ฒ์์ ๊ฐ์ ๊ฐ์ฃฝ ์ง๊ฐ์ ์์ด๋ฒ๋ ธ์ต๋๋ค.", | |
"location": "์์ธ๋์ ๊ตฌ์ญ", | |
"image": None, | |
"category": "์ง๊ฐ" | |
} | |
] | |
return sample_lost_items | |
# ์ค์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๋ฐ์ดํฐ ์กฐํ | |
logger.info(f"๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๋ถ์ค๋ฌผ ๋ฐ์ดํฐ ์กฐํ ์ค (limit: {limit}, offset: {offset})...") | |
with get_db_connection() as connection: | |
with connection.cursor() as cursor: | |
# lost_item ํ ์ด๋ธ์์ ๋ถ์ค๋ฌผ ๋ฐ์ดํฐ ์กฐํ (l.stored_at ์ปฌ๋ผ ์ ๊ฑฐ) | |
query = """ | |
SELECT l.id, l.user_id, l.item_category_id, l.title, l.color, | |
l.lost_at, l.location, l.detail as content, l.image, | |
l.status, | |
ic.level as majorCategory, | |
ic.name as minorCategory | |
FROM lost_item l | |
LEFT JOIN item_category ic ON l.item_category_id = ic.id | |
WHERE l.status = 'LOST' | |
ORDER BY l.id DESC | |
LIMIT %s OFFSET %s | |
""" | |
cursor.execute(query, (limit, offset)) | |
result = cursor.fetchall() # DictCursor๋ฅผ ์ฌ์ฉํ๋ฏ๋ก ๋์ ๋๋ฆฌ๋ก ๋ฐํ๋จ | |
logger.info(f"๋ฐ์ดํฐ๋ฒ ์ด์ค์์ {len(result)}๊ฐ์ ๋ถ์ค๋ฌผ ๋ฐ์ดํฐ ์กฐํ ์๋ฃ") | |
return result | |
except Exception as e: | |
logger.error(f"๋ถ์ค๋ฌผ ๋ฐ์ดํฐ ์กฐํ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}") | |
logger.error(traceback.format_exc()) | |
# ์ค๋ฅ ๋ฐ์ ์ ๋น ๋ชฉ๋ก ๋ฐํ | |
return [] | |
# ๋ถ์ค๋ฌผ ์ด ๊ฐ์๋ฅผ ์กฐํํ๋ ํจ์ | |
async def count_lost_items(): | |
""" | |
๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ถ์ค๋ฌผ ์ด ๊ฐ์๋ฅผ ์กฐํํ๋ ํจ์ | |
Returns: | |
int: ์ด ๋ถ์ค๋ฌผ ์ | |
""" | |
try: | |
# ํ ์คํธ ๋ชจ๋์ธ ๊ฒฝ์ฐ ์ํ ๋ฐ์ดํฐ ๊ฐ์ ๋ฐํ | |
if os.getenv('APP_ENV') == 'test': | |
return 2 # ์ํ ๋ฐ์ดํฐ ๊ฐ์ | |
# ์ค์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๋ฐ์ดํฐ ๊ฐ์ ์กฐํ | |
with get_db_connection() as connection: | |
with connection.cursor() as cursor: | |
query = "SELECT COUNT(*) as total FROM lost_item WHERE status = 'LOST'" | |
cursor.execute(query) | |
result = cursor.fetchone() | |
# DictCursor๋ฅผ ์ฌ์ฉํ๋ฏ๋ก ๋์ ๋๋ฆฌ๋ก ๋ฐํ๋จ | |
count = result["total"] | |
return count | |
except Exception as e: | |
logger.error(f"๋ถ์ค๋ฌผ ๋ฐ์ดํฐ ๊ฐ์ ์กฐํ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}") | |
logger.error(traceback.format_exc()) | |
# ์ค๋ฅ ๋ฐ์ ์ 0 ๋ฐํ | |
return 0 | |
# ํน์ ID์ ์ต๋๋ฌผ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ํจ์ - ์๋ก ์ถ๊ฐ | |
async def get_found_item_info(found_item_id): | |
""" | |
ํน์ ์ต๋๋ฌผ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ํจ์ | |
""" | |
try: | |
if os.getenv('APP_ENV') == 'test': | |
return { | |
"id": found_item_id, | |
"item_category_id": 1, | |
"name": "๊ฒ์ ๊ฐ์ฃฝ ์ง๊ฐ", | |
"color": "๊ฒ์ ์", | |
"detail": "๊ฐ๋จ์ญ ๊ทผ์ฒ์์ ๊ฒ์ ์ ๊ฐ์ฃฝ ์ง๊ฐ์ ๋ฐ๊ฒฌํ์ต๋๋ค.", | |
"location": "๊ฐ๋จ์ญ" | |
} | |
with get_db_connection() as connection: | |
with connection.cursor() as cursor: | |
query = """ | |
SELECT f.id, f.user_id, f.item_category_id, f.name, f.color, | |
f.found_at, f.location, f.detail, f.image, | |
f.status, f.stored_at, f.management_id, | |
ic.major_category AS majorCategory, | |
ic.name AS minorCategory | |
FROM found_item f | |
LEFT JOIN item_category ic ON f.item_category_id = ic.id | |
WHERE f.id = %s | |
""" | |
cursor.execute(query, (found_item_id,)) | |
return cursor.fetchone() | |
except Exception as e: | |
logger.error(f"์ต๋๋ฌผ ์ ๋ณด ์กฐํ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}") | |
logger.error(traceback.format_exc()) | |
return None | |
# ํน์ ID์ ๋ถ์ค๋ฌผ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ํจ์ - ์๋ก ์ถ๊ฐ | |
async def get_lost_item_info(lost_item_id): | |
""" | |
ํน์ ๋ถ์ค๋ฌผ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ํจ์ | |
""" | |
try: | |
if os.getenv('APP_ENV') == 'test': | |
return { | |
"id": lost_item_id, | |
"item_category_id": 1, | |
"title": "๊ฒ์ ๊ฐ์ฃฝ ์ง๊ฐ", | |
"color": "๊ฒ์ ์", | |
"detail": "๊ฐ๋จ์ญ ๊ทผ์ฒ์์ ๊ฒ์ ์ ๊ฐ์ฃฝ ์ง๊ฐ์ ์์ด๋ฒ๋ ธ์ต๋๋ค.", | |
"location": "๊ฐ๋จ์ญ" | |
} | |
with get_db_connection() as connection: | |
with connection.cursor() as cursor: | |
query = """ | |
SELECT l.id, l.user_id, l.item_category_id, l.title, l.color, | |
l.lost_at, l.location, l.detail, l.image, | |
l.status, | |
ic.major_category AS majorCategory, | |
ic.name AS minorCategory | |
FROM lost_item l | |
LEFT JOIN item_category ic ON l.item_category_id = ic.id | |
WHERE l.id = %s | |
""" | |
cursor.execute(query, (lost_item_id,)) | |
return cursor.fetchone() | |
except Exception as e: | |
logger.error(f"๋ถ์ค๋ฌผ ์ ๋ณด ์กฐํ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}") | |
logger.error(traceback.format_exc()) | |
return None | |
# ํน์ ID์ ์ต๋๋ฌผ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ํจ์ - ์์ | |
async def fetch_found_item_by_id(found_item_id): | |
""" | |
๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ํน์ ID์ ์ต๋๋ฌผ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ํจ์ | |
Args: | |
found_item_id (int): ์กฐํํ ์ต๋๋ฌผ ID | |
Returns: | |
dict: ์ต๋๋ฌผ ๋ฐ์ดํฐ (์์ผ๋ฉด None) | |
""" | |
try: | |
# ํ ์คํธ ๋ชจ๋์ธ ๊ฒฝ์ฐ ์ํ ๋ฐ์ดํฐ ๋ฐํ | |
if os.getenv('APP_ENV') == 'test': | |
# ID์ ํด๋นํ๋ ํ ์คํธ ๋ฐ์ดํฐ ๋ฐํ | |
if found_item_id == 1: | |
return { | |
"id": 1, | |
"item_category_id": 1, | |
"title": "๊ฒ์ ๊ฐ์ฃฝ ์ง๊ฐ", | |
"color": "๊ฒ์ ์", | |
"content": "๊ฐ๋จ์ญ ๊ทผ์ฒ์์ ๊ฒ์ ์ ๊ฐ์ฃฝ ์ง๊ฐ์ ๋ฐ๊ฒฌํ์ต๋๋ค.", | |
"location": "๊ฐ๋จ์ญ", | |
"image": None, | |
"category": "์ง๊ฐ" | |
} | |
return None | |
# ์ค์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๋ฐ์ดํฐ ์กฐํ | |
logger.info(f"๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ต๋๋ฌผ ID {found_item_id} ์กฐํ ์ค...") | |
with get_db_connection() as connection: | |
with connection.cursor() as cursor: | |
query = """ | |
SELECT f.id, f.user_id, f.item_category_id, f.name as title, f.color, | |
f.found_at, f.location, f.detail as content, f.image, | |
f.status, f.stored_at, f.management_id, | |
ic.major_category as majorCategory, | |
ic.name as minorCategory | |
FROM found_item f | |
LEFT JOIN item_category ic ON f.item_category_id = ic.id | |
WHERE f.id = %s | |
""" | |
cursor.execute(query, (found_item_id,)) | |
item = cursor.fetchone() | |
if item: | |
logger.info(f"์ต๋๋ฌผ ID {found_item_id} ์กฐํ ์๋ฃ") | |
return item | |
else: | |
logger.warning(f"์ต๋๋ฌผ ID {found_item_id}๋ฅผ ์ฐพ์ ์ ์์") | |
return None | |
except Exception as e: | |
logger.error(f"์ต๋๋ฌผ ์กฐํ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}") | |
logger.error(traceback.format_exc()) | |
# ์ค๋ฅ ๋ฐ์ ์ None ๋ฐํ | |
return None | |
# ํน์ ID์ ๋ถ์ค๋ฌผ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ํจ์ - ์์ | |
async def fetch_lost_item_by_id(lost_item_id): | |
""" | |
๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ํน์ ID์ ๋ถ์ค๋ฌผ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ํจ์ | |
Args: | |
lost_item_id (int): ์กฐํํ ๋ถ์ค๋ฌผ ID | |
Returns: | |
dict: ๋ถ์ค๋ฌผ ๋ฐ์ดํฐ (์์ผ๋ฉด None) | |
""" | |
try: | |
# ํ ์คํธ ๋ชจ๋์ธ ๊ฒฝ์ฐ ์ํ ๋ฐ์ดํฐ ๋ฐํ | |
if os.getenv('APP_ENV') == 'test': | |
# ID์ ํด๋นํ๋ ํ ์คํธ ๋ฐ์ดํฐ ๋ฐํ | |
if lost_item_id == 1: | |
return { | |
"id": 1, | |
"item_category_id": 1, | |
"title": "๊ฒ์ ๊ฐ์ฃฝ ์ง๊ฐ", | |
"color": "๊ฒ์ ์", | |
"content": "๊ฐ๋จ์ญ ๊ทผ์ฒ์์ ๊ฒ์ ์ ๊ฐ์ฃฝ ์ง๊ฐ์ ์์ด๋ฒ๋ ธ์ต๋๋ค.", | |
"location": "๊ฐ๋จ์ญ", | |
"image": None, | |
"category": "์ง๊ฐ" | |
} | |
return None | |
# ์ค์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๋ฐ์ดํฐ ์กฐํ | |
logger.info(f"๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๋ถ์ค๋ฌผ ID {lost_item_id} ์กฐํ ์ค...") | |
with get_db_connection() as connection: | |
with connection.cursor() as cursor: | |
# stored_at ์ปฌ๋ผ ์ ๊ฑฐ | |
query = """ | |
SELECT l.id, l.user_id, l.item_category_id, l.title, l.color, | |
l.lost_at, l.location, l.detail as content, l.image, | |
l.status, | |
ic.major_category as majorCategory, | |
ic.name as minorCategory | |
FROM lost_item l | |
LEFT JOIN item_category ic ON l.item_category_id = ic.id | |
WHERE l.id = %s | |
""" | |
cursor.execute(query, (lost_item_id,)) | |
item = cursor.fetchone() | |
if item: | |
logger.info(f"๋ถ์ค๋ฌผ ID {lost_item_id} ์กฐํ ์๋ฃ") | |
return item | |
else: | |
logger.warning(f"๋ถ์ค๋ฌผ ID {lost_item_id}๋ฅผ ์ฐพ์ ์ ์์") | |
return None | |
except Exception as e: | |
logger.error(f"๋ถ์ค๋ฌผ ์กฐํ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}") | |
logger.error(traceback.format_exc()) | |
# ์ค๋ฅ ๋ฐ์ ์ None ๋ฐํ | |
return None |