""" Settings and User Management API Router """ from fastapi import APIRouter, HTTPException from typing import List, Optional, Dict from pydantic import BaseModel from app.core.database import execute_query import logging logger = logging.getLogger(__name__) router = APIRouter() # Pydantic Models class Setting(BaseModel): id: int key: str value: Optional[str] category: str description: Optional[str] value_type: str is_public: bool class SettingUpdate(BaseModel): value: str class User(BaseModel): id: int username: str email: Optional[str] full_name: Optional[str] is_active: bool last_login: Optional[str] created_at: str class UserCreate(BaseModel): username: str email: str password: str full_name: Optional[str] = None class UserUpdate(BaseModel): email: Optional[str] = None full_name: Optional[str] = None is_active: Optional[bool] = None # Settings Endpoints @router.get("/settings", response_model=List[Setting], tags=["Settings"]) async def get_settings(category: Optional[str] = None): """Get all settings or filter by category""" query = "SELECT * FROM settings" params = [] if category: query += " WHERE category = %s" params.append(category) query += " ORDER BY category, key" result = execute_query(query, tuple(params) if params else None) return result or [] @router.get("/settings/{key}", response_model=Setting, tags=["Settings"]) async def get_setting(key: str): """Get a specific setting by key""" query = "SELECT * FROM settings WHERE key = %s" result = execute_query(query, (key,)) if not result: raise HTTPException(status_code=404, detail="Setting not found") return result[0] @router.put("/settings/{key}", response_model=Setting, tags=["Settings"]) async def update_setting(key: str, setting: SettingUpdate): """Update a setting value""" query = """ UPDATE settings SET value = %s, updated_at = CURRENT_TIMESTAMP WHERE key = %s RETURNING * """ result = execute_query(query, (setting.value, key)) if not result: raise HTTPException(status_code=404, detail="Setting not found") logger.info(f"✅ Updated setting: {key}") return result[0] @router.get("/settings/categories/list", tags=["Settings"]) async def get_setting_categories(): """Get list of all setting categories""" query = "SELECT DISTINCT category FROM settings ORDER BY category" result = execute_query(query) return [row['category'] for row in result] if result else [] # User Management Endpoints @router.get("/users", response_model=List[User], tags=["Users"]) async def get_users(is_active: Optional[bool] = None): """Get all users""" query = "SELECT user_id as id, username, email, full_name, is_active, last_login, created_at FROM users" params = [] if is_active is not None: query += " WHERE is_active = %s" params.append(is_active) query += " ORDER BY username" result = execute_query(query, tuple(params) if params else None) return result or [] @router.get("/users/{user_id}", response_model=User, tags=["Users"]) async def get_user(user_id: int): """Get user by ID""" query = "SELECT user_id as id, username, email, full_name, is_active, last_login, created_at FROM users WHERE user_id = %s" result = execute_query(query, (user_id,)) if not result: raise HTTPException(status_code=404, detail="User not found") return result[0] @router.post("/users", response_model=User, tags=["Users"]) async def create_user(user: UserCreate): """Create a new user""" # Check if username exists existing = execute_query("SELECT user_id FROM users WHERE username = %s", (user.username,)) if existing: raise HTTPException(status_code=400, detail="Username already exists") # Hash password (simple SHA256 for now - should use bcrypt in production) import hashlib password_hash = hashlib.sha256(user.password.encode()).hexdigest() query = """ INSERT INTO users (username, email, password_hash, full_name, is_active) VALUES (%s, %s, %s, %s, true) RETURNING user_id as id, username, email, full_name, is_active, last_login, created_at """ result = execute_query(query, (user.username, user.email, password_hash, user.full_name)) if not result: raise HTTPException(status_code=500, detail="Failed to create user") logger.info(f"✅ Created user: {user.username}") return result[0] @router.put("/users/{user_id}", response_model=User, tags=["Users"]) async def update_user(user_id: int, user: UserUpdate): """Update user details""" # Check if user exists existing = execute_query("SELECT user_id FROM users WHERE user_id = %s", (user_id,)) if not existing: raise HTTPException(status_code=404, detail="User not found") # Build update query update_fields = [] params = [] if user.email is not None: update_fields.append("email = %s") params.append(user.email) if user.full_name is not None: update_fields.append("full_name = %s") params.append(user.full_name) if user.is_active is not None: update_fields.append("is_active = %s") params.append(user.is_active) if not update_fields: raise HTTPException(status_code=400, detail="No fields to update") params.append(user_id) query = f""" UPDATE users SET {', '.join(update_fields)}, updated_at = CURRENT_TIMESTAMP WHERE user_id = %s RETURNING user_id as id, username, email, full_name, is_active, last_login, created_at """ result = execute_query(query, tuple(params)) if not result: raise HTTPException(status_code=500, detail="Failed to update user") logger.info(f"✅ Updated user: {user_id}") return result[0] @router.delete("/users/{user_id}", tags=["Users"]) async def deactivate_user(user_id: int): """Deactivate a user (soft delete)""" query = """ UPDATE users SET is_active = false, updated_at = CURRENT_TIMESTAMP WHERE user_id = %s RETURNING user_id as id """ result = execute_query(query, (user_id,)) if not result: raise HTTPException(status_code=404, detail="User not found") logger.info(f"✅ Deactivated user: {user_id}") return {"message": "User deactivated successfully"} @router.post("/users/{user_id}/reset-password", tags=["Users"]) async def reset_user_password(user_id: int, new_password: str): """Reset user password""" import hashlib password_hash = hashlib.sha256(new_password.encode()).hexdigest() query = """ UPDATE users SET password_hash = %s, updated_at = CURRENT_TIMESTAMP WHERE user_id = %s RETURNING user_id as id """ result = execute_query(query, (password_hash, user_id)) if not result: raise HTTPException(status_code=404, detail="User not found") logger.info(f"✅ Reset password for user: {user_id}") return {"message": "Password reset successfully"}