feat: Migrate to MySQL and add unified environment configuration
## Database Migration (SQLite → MySQL) - Add Alembic migration framework - Add 'tr_' prefix to all tables to avoid conflicts in shared database - Remove SQLite support, use MySQL exclusively - Add pymysql driver dependency - Change ad_token column to Text type for long JWT tokens ## Unified Environment Configuration - Centralize all hardcoded settings to environment variables - Backend: Extend Settings class in app/core/config.py - Frontend: Use Vite environment variables (import.meta.env) - Docker: Move credentials to environment variables - Update .env.example files with comprehensive documentation ## Test Organization - Move root-level test files to tests/ directory: - test_chat_room.py → tests/test_chat_room.py - test_websocket.py → tests/test_websocket.py - test_realtime_implementation.py → tests/test_realtime_implementation.py - Fix path references in test_realtime_implementation.py Breaking Changes: - CORS now requires explicit origins (no more wildcard) - All database tables renamed with 'tr_' prefix - SQLite no longer supported 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,7 @@ from datetime import datetime
|
||||
import json
|
||||
|
||||
from app.core.database import get_db
|
||||
from app.core.config import get_settings
|
||||
from app.modules.auth.dependencies import get_current_user
|
||||
from app.modules.auth.services.session_service import session_service
|
||||
from app.modules.chat_room.models import RoomMember, MemberRole
|
||||
@@ -32,7 +33,7 @@ from sqlalchemy import and_
|
||||
|
||||
router = APIRouter(prefix="/api", tags=["realtime"])
|
||||
|
||||
SYSTEM_ADMIN_EMAIL = "ymirliu@panjit.com.tw"
|
||||
settings = get_settings()
|
||||
|
||||
|
||||
async def ws_send_json(websocket: WebSocket, data: dict):
|
||||
@@ -51,9 +52,14 @@ def get_user_room_membership(db: Session, room_id: str, user_id: str) -> Optiona
|
||||
).first()
|
||||
|
||||
|
||||
def is_system_admin(user_id: str) -> bool:
|
||||
"""Check if user is the system administrator"""
|
||||
return bool(settings.SYSTEM_ADMIN_EMAIL and user_id == settings.SYSTEM_ADMIN_EMAIL)
|
||||
|
||||
|
||||
def can_write_message(membership: Optional[RoomMember], user_id: str) -> bool:
|
||||
"""Check if user has write permission (OWNER or EDITOR)"""
|
||||
if user_id == SYSTEM_ADMIN_EMAIL:
|
||||
if is_system_admin(user_id):
|
||||
return True
|
||||
|
||||
if not membership:
|
||||
@@ -99,7 +105,7 @@ async def websocket_endpoint(
|
||||
|
||||
# Check room membership
|
||||
membership = get_user_room_membership(db, room_id, user_id)
|
||||
if not membership and user_id != SYSTEM_ADMIN_EMAIL:
|
||||
if not membership and not is_system_admin(user_id):
|
||||
await websocket.close(code=4001, reason="Not a member of this room")
|
||||
return
|
||||
|
||||
@@ -225,12 +231,11 @@ async def websocket_endpoint(
|
||||
continue
|
||||
|
||||
# Delete message
|
||||
is_admin = user_id == SYSTEM_ADMIN_EMAIL
|
||||
deleted_message = MessageService.delete_message(
|
||||
db=db,
|
||||
message_id=ws_message.message_id,
|
||||
user_id=user_id,
|
||||
is_admin=is_admin
|
||||
is_admin=is_system_admin(user_id)
|
||||
)
|
||||
|
||||
if not deleted_message:
|
||||
@@ -345,7 +350,7 @@ async def get_messages(
|
||||
|
||||
# Check room membership
|
||||
membership = get_user_room_membership(db, room_id, user_id)
|
||||
if not membership and user_id != SYSTEM_ADMIN_EMAIL:
|
||||
if not membership and not is_system_admin(user_id):
|
||||
raise HTTPException(status_code=403, detail="Not a member of this room")
|
||||
|
||||
return MessageService.get_messages(
|
||||
@@ -414,7 +419,7 @@ async def search_messages(
|
||||
|
||||
# Check room membership
|
||||
membership = get_user_room_membership(db, room_id, user_id)
|
||||
if not membership and user_id != SYSTEM_ADMIN_EMAIL:
|
||||
if not membership and not is_system_admin(user_id):
|
||||
raise HTTPException(status_code=403, detail="Not a member of this room")
|
||||
|
||||
return MessageService.search_messages(
|
||||
@@ -437,7 +442,7 @@ async def get_online_users(
|
||||
|
||||
# Check room membership
|
||||
membership = get_user_room_membership(db, room_id, user_id)
|
||||
if not membership and user_id != SYSTEM_ADMIN_EMAIL:
|
||||
if not membership and not is_system_admin(user_id):
|
||||
raise HTTPException(status_code=403, detail="Not a member of this room")
|
||||
|
||||
online_users = manager.get_online_users(room_id)
|
||||
@@ -455,7 +460,7 @@ async def get_typing_users(
|
||||
|
||||
# Check room membership
|
||||
membership = get_user_room_membership(db, room_id, user_id)
|
||||
if not membership and user_id != SYSTEM_ADMIN_EMAIL:
|
||||
if not membership and not is_system_admin(user_id):
|
||||
raise HTTPException(status_code=403, detail="Not a member of this room")
|
||||
|
||||
typing_users = manager.get_typing_users(room_id)
|
||||
|
||||
Reference in New Issue
Block a user