gitscope
← marzneshin / v0.5.0 / app/routes/service.py
https://dev.kronoz.win/r/marzneshin.git
app/routes/service.py · Python
Blame Raw
  1import sqlalchemy
  2from fastapi import APIRouter, Query
  3from fastapi import HTTPException
  4from fastapi_pagination.ext.sqlalchemy import paginate
  5from fastapi_pagination.links import Page
  6
  7from app import marznode
  8from app.db import crud
  9from app.db.models import Service, User
 10from app.dependencies import DBDep, AdminDep, SudoAdminDep
 11from app.models.proxy import Inbound
 12from app.models.service import ServiceCreate, ServiceModify, ServiceResponse
 13from app.models.user import UserResponse
 14
 15router = APIRouter(prefix="/services", tags=["Service"])
 16
 17
 18@router.get("", response_model=Page[ServiceResponse])
 19def get_services(db: DBDep, admin: AdminDep, name: str = Query(None)):
 20    query = db.query(Service)
 21
 22    if name:
 23        query = query.filter(Service.name.ilike(f"%{name}%"))
 24
 25    if not admin.is_sudo and not admin.all_services_access:
 26        query = query.filter(Service.id.in_(admin.service_ids))
 27
 28    return paginate(query)
 29
 30
 31@router.post("", response_model=ServiceResponse)
 32def add_service(new_service: ServiceCreate, db: DBDep, admin: SudoAdminDep):
 33    """
 34    Add a new service
 35
 36    - **name** service name
 37    - **inbounds** list of inbound ids
 38    """
 39    try:
 40        return crud.create_service(db, new_service)
 41    except sqlalchemy.exc.IntegrityError:
 42        db.rollback()
 43        raise HTTPException(
 44            status_code=409, detail="Service by this name already exists"
 45        )
 46
 47
 48@router.get("/{id}", response_model=ServiceResponse)
 49def get_service(id: int, db: DBDep, admin: AdminDep):
 50    """
 51    Get Service information with id
 52    """
 53    dbservice = crud.get_service(db, id)
 54    if not dbservice:
 55        raise HTTPException(status_code=404, detail="Service not found")
 56
 57    if not (
 58        admin.is_sudo or admin.all_services_access or id in admin.service_ids
 59    ):
 60        raise HTTPException(status_code=403, detail="You're not allowed")
 61
 62    return dbservice
 63
 64
 65@router.get("/{id}/users", response_model=Page[UserResponse])
 66def get_service_users(id: int, db: DBDep, admin: SudoAdminDep):
 67    """
 68    Get service users
 69    """
 70    service = crud.get_service(db, id)
 71
 72    if not service:
 73        raise HTTPException(status_code=404, detail="Service not found")
 74
 75    query = db.query(User).join(User.services).where(Service.id == service.id)
 76
 77    return paginate(query)
 78
 79
 80@router.get("/{id}/inbounds", response_model=Page[Inbound])
 81def get_service_inbounds(id: int, db: DBDep, admin: SudoAdminDep):
 82    """
 83    Get service inbounds
 84    """
 85    service = crud.get_service(db, id)
 86
 87    if not service:
 88        raise HTTPException(status_code=404, detail="Service not found")
 89
 90    query = (
 91        db.query(Inbound)
 92        .join(Inbound.services)
 93        .where(Service.id == service.id)
 94    )
 95
 96    return paginate(query)
 97
 98
 99@router.put("/{id}", response_model=ServiceResponse)
100async def modify_service(
101    id: int, modification: ServiceModify, db: DBDep, admin: SudoAdminDep
102):
103    """
104    Modify Service
105
106    - **name** can be up to 64 characters
107    - **inbounds** list of inbound ids. if not specified no change will be applied;
108    in case of an empty list all inbounds would be removed.
109    """
110    dbservice = crud.get_service(db, id)
111    if not dbservice:
112        raise HTTPException(status_code=404, detail="Service not found")
113    old_inbounds = {(i.node_id, i.protocol, i.tag) for i in dbservice.inbounds}
114    try:
115        response = crud.update_service(db, dbservice, modification)
116    except sqlalchemy.exc.IntegrityError:
117        db.rollback()
118        raise HTTPException(
119            status_code=409, detail="problem updating the service"
120        )
121    else:
122        for user in response.users:
123            if user.activated:
124                marznode.operations.update_user(
125                    user, old_inbounds=old_inbounds
126                )
127        return response
128
129
130@router.delete("/{id}")
131def remove_service(id: int, db: DBDep, admin: SudoAdminDep):
132    dbservice = crud.get_service(db, id)
133    if not dbservice:
134        raise HTTPException(status_code=404, detail="Service not found")
135
136    crud.remove_service(db, dbservice)
137    return dict()