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 |