from fastapi import APIRouter, Depends, HTTPException, Request, Form, Query, status from fastapi.responses import HTMLResponse, RedirectResponse from sqlalchemy.orm import Session from models import User, Device, SystemSetting, StatusRecord from database import get_db from datetime import datetime from typing import Optional from fastapi.templating import Jinja2Templates admin_router = APIRouter(prefix="/admin", tags=["admin"]) templates = Jinja2Templates(directory="templates") def login_required(request: Request, db: Session = Depends(get_db)): username = request.cookies.get("username") if not username: return RedirectResponse(url="/login", status_code=status.HTTP_302_FOUND) user = db.query(User).filter(User.username == username).first() if not user: return RedirectResponse(url="/login", status_code=status.HTTP_302_FOUND) return user @admin_router.get("", response_class=HTMLResponse) async def admin_page(request: Request, db: Session = Depends(get_db)): current_user = login_required(request, db) if isinstance(current_user, RedirectResponse): return current_user if not current_user.is_admin: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Not authorized" ) users = db.query(User).all() devices = db.query(Device).all() system_setting = db.query(SystemSetting).first() return templates.TemplateResponse( "admin.html", { "request": request, "users": users, "devices": devices, "system_setting": system_setting, "current_user": current_user } ) @admin_router.post("/edit_system_setting") async def edit_system_setting( request: Request, check_connect_period: int = Form(...), data_sync_period: int = Form(...), get_config_period: int = Form(...), point_distance: int = Form(...), db: Session = Depends(get_db), ): current_user = login_required(request, db) if isinstance(current_user, RedirectResponse): return current_user if not current_user.is_admin: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Not authorized" ) system_setting = db.query(SystemSetting).first() if not system_setting: system_setting = SystemSetting() db.add(system_setting) system_setting.check_connect_period = check_connect_period system_setting.data_sync_period = data_sync_period system_setting.get_config_period = get_config_period system_setting.point_distance = point_distance db.commit() return RedirectResponse(url="/admin", status_code=status.HTTP_302_FOUND) @admin_router.get("/data", response_class=HTMLResponse, name="admin_data") async def admin_data( request: Request, start_date: Optional[str] = Query(None), end_date: Optional[str] = Query(None), device_id: Optional[str] = Query(None), page: int = Query(1, ge=1), per_page: int = Query(10, ge=10, le=100), db: Session = Depends(get_db) ): current_user = login_required(request, db) if isinstance(current_user, RedirectResponse): return current_user if not current_user.is_admin: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Not authorized") query = db.query(StatusRecord) if start_date: query = query.filter(StatusRecord.timestamp >= datetime.strptime(start_date, "%Y-%m-%d")) if end_date: query = query.filter(StatusRecord.timestamp <= datetime.strptime(end_date, "%Y-%m-%d")) if device_id: query = query.filter(StatusRecord.device_id == device_id) total_records = query.count() total_pages = (total_records + per_page - 1) // per_page records = query.order_by(StatusRecord.timestamp.desc()).offset((page - 1) * per_page).limit(per_page).all() devices = db.query(Device.device_id).distinct().all() device_ids = [device.device_id for device in devices] # Tính toán phạm vi trang để hiển thị page_range = 5 start_page = max(1, page - page_range // 2) end_page = min(total_pages, start_page + page_range - 1) start_page = max(1, end_page - page_range + 1) return templates.TemplateResponse( "admin_data.html", { "request": request, "records": records, "current_page": page, "total_pages": total_pages, "start_page": start_page, "end_page": end_page, "start_date": start_date, "end_date": end_date, "device_id": device_id, "device_ids": device_ids, "current_user": current_user, "per_page": per_page, } ) @admin_router.post("/delete/{username}") async def delete_user(request: Request, username: str, db: Session = Depends(get_db)): current_user = login_required(request, db) if isinstance(current_user, RedirectResponse): return current_user if not current_user.is_admin: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Not authorized" ) user = db.query(User).filter(User.username == username).first() if user: db.delete(user) db.commit() return RedirectResponse(url="/admin", status_code=status.HTTP_302_FOUND) @admin_router.post("/edit/{username}") async def edit_user( request: Request, username: str, new_username: str = Form(...), email: str = Form(...), is_admin: bool = Form(False), is_active: bool = Form(False), old_password: str = Form(None), new_password: str = Form(None), db: Session = Depends(get_db), ): current_user = login_required(request, db) if isinstance(current_user, RedirectResponse): return current_user if not current_user.is_admin: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Not authorized" ) user = db.query(User).filter(User.username == username).first() if user: if ( new_username != username and db.query(User).filter(User.username == new_username).first() ): raise HTTPException(status_code=400, detail="Username already exists") user.username = new_username user.email = email user.is_admin = is_admin user.is_active = is_active if old_password and new_password: if user.password != old_password: raise HTTPException(status_code=400, detail="Incorrect old password") user.password = new_password db.commit() return RedirectResponse(url="/admin", status_code=status.HTTP_302_FOUND) @admin_router.post("/add_device") async def add_device( request: Request, name: str = Form(...), description: str = Form(...), device_id: str = Form(...), password: str = Form(...), db: Session = Depends(get_db), ): current_user = login_required(request, db) if isinstance(current_user, RedirectResponse): return current_user if not current_user.is_admin: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Not authorized" ) existing_device = db.query(Device).filter(Device.device_id == device_id).first() if existing_device: raise HTTPException(status_code=400, detail="Device ID already exists") new_device = Device( name=name, description=description, device_id=device_id, password=password ) db.add(new_device) db.commit() return RedirectResponse(url="/admin", status_code=status.HTTP_302_FOUND) @admin_router.post("/edit_device/{device_id}") async def edit_device( request: Request, device_id: str, name: str = Form(...), description: str = Form(...), new_device_id: str = Form(...), password: str = Form(...), db: Session = Depends(get_db), ): current_user = login_required(request, db) if isinstance(current_user, RedirectResponse): return current_user if not current_user.is_admin: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Not authorized" ) device = db.query(Device).filter(Device.device_id == device_id).first() if not device: raise HTTPException(status_code=404, detail="Device not found") if ( new_device_id != device_id and db.query(Device).filter(Device.device_id == new_device_id).first() ): raise HTTPException(status_code=400, detail="New Device ID already exists") device.name = name device.description = description device.device_id = new_device_id device.password = password db.commit() return RedirectResponse(url="/admin", status_code=status.HTTP_302_FOUND) @admin_router.post("/delete_device/{device_id}") async def delete_device( request: Request, device_id: str, db: Session = Depends(get_db) ): current_user = login_required(request, db) if isinstance(current_user, RedirectResponse): return current_user if not current_user.is_admin: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Not authorized" ) device = db.query(Device).filter(Device.device_id == device_id).first() if device: db.delete(device) db.commit() return RedirectResponse(url="/admin", status_code=status.HTTP_302_FOUND)