gitscope
← marzneshin / v0.3.0 / app/routes/admin.py
https://dev.kronoz.win/r/marzneshin.git
app/routes/admin.py · Python
Blame Raw
  1from typing import Optional, Annotated
  2
  3import sqlalchemy
  4from fastapi import APIRouter
  5from fastapi import Depends, HTTPException, status
  6from fastapi.security import OAuth2PasswordRequestForm
  7from fastapi_pagination import Page
  8from fastapi_pagination.ext.sqlalchemy import paginate
  9
 10from app.db import Session, crud
 11from app.db.models import Admin as DBAdmin
 12from app.dependencies import AdminDep, SudoAdminDep, DBDep
 13from app.models.admin import Admin, AdminCreate, AdminInDB, AdminModify, Token
 14from app.utils.jwt import create_admin_token
 15
 16router = APIRouter(tags=["Admin"], prefix="/admins")
 17
 18
 19def authenticate_admin(db: Session, username: str, password: str) -> Optional[Admin]:
 20    dbadmin = crud.get_admin(db, username)
 21    if not dbadmin:
 22        return None
 23
 24    return (
 25        dbadmin if AdminInDB.model_validate(dbadmin).verify_password(password) else None
 26    )
 27
 28
 29@router.get("", response_model=Page[Admin])
 30def get_admins(db: DBDep, admin: SudoAdminDep, username: str = None):
 31    query = db.query(DBAdmin)
 32    if username:
 33        query = query.filter(DBAdmin.username.ilike(f"%{username}%"))
 34    return paginate(db, query)
 35
 36
 37@router.post("", response_model=Admin)
 38def create_admin(new_admin: AdminCreate, db: DBDep, admin: SudoAdminDep):
 39    try:
 40        dbadmin = crud.create_admin(db, new_admin)
 41    except sqlalchemy.exc.IntegrityError:
 42        db.rollback()
 43        raise HTTPException(status_code=409, detail="Admin already exists")
 44
 45    return dbadmin
 46
 47
 48@router.get("/current", response_model=Admin)
 49def get_current_admin(admin: AdminDep):
 50    return admin
 51
 52
 53@router.post("/token", response_model=Token)
 54def admin_token(form_data: Annotated[OAuth2PasswordRequestForm, Depends()], db: DBDep):
 55    if dbadmin := authenticate_admin(db, form_data.username, form_data.password):
 56        return Token(
 57            access_token=create_admin_token(form_data.username, is_sudo=dbadmin.is_sudo)
 58        )
 59
 60    raise HTTPException(
 61        status_code=status.HTTP_401_UNAUTHORIZED,
 62        detail="Incorrect username or password",
 63        headers={"WWW-Authenticate": "Bearer"},
 64    )
 65
 66
 67@router.put("/{username}", response_model=Admin)
 68def modify_admin(
 69    username: str, modified_admin: AdminModify, db: DBDep, admin: AdminDep
 70):
 71    if not (admin.is_sudo or admin.username == username):
 72        raise HTTPException(status_code=403, detail="You're not allowed")
 73
 74    # If a non-sudoer admin is making itself a sudoer
 75    if (admin.username == username) and (modified_admin.is_sudo and not admin.is_sudo):
 76        raise HTTPException(status_code=403, detail="You can't make yourself sudoer!")
 77
 78    dbadmin = crud.get_admin(db, username)
 79    if not dbadmin:
 80        raise HTTPException(status_code=404, detail="Admin not found")
 81
 82    # If a sudoer admin wants to edit another sudoer
 83    if (username != admin.username) and dbadmin.is_sudo:
 84        raise HTTPException(
 85            status_code=403,
 86            detail="You're not allowed to edit another sudoers account. Use marzban-cli instead.",
 87        )
 88
 89    dbadmin = crud.update_admin(db, dbadmin, modified_admin)
 90    return dbadmin
 91
 92
 93@router.delete("/{username}")
 94def remove_admin(username: str, db: DBDep, admin: SudoAdminDep):
 95    dbadmin = crud.get_admin(db, username)
 96    if not dbadmin:
 97        raise HTTPException(status_code=404, detail="Admin not found")
 98
 99    if dbadmin.is_sudo:
100        raise HTTPException(
101            status_code=403,
102            detail="You're not allowed to delete sudoers accounts. Use marzban-cli instead.",
103        )
104
105    crud.remove_admin(db, dbadmin)
106    return {}