gitscope
← marzneshin / v0.6.1 / 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 = (
 76        db.query(User)
 77        .join(User.services)
 78        .where(Service.id == service.id)
 79        .filter(User.removed != True)
 80    )
 81
 82    return paginate(query)
 83
 84
 85@router.get("/{id}/inbounds", response_model=Page[Inbound])
 86def get_service_inbounds(id: int, db: DBDep, admin: SudoAdminDep):
 87    """
 88    Get service inbounds
 89    """
 90    service = crud.get_service(db, id)
 91
 92    if not service:
 93        raise HTTPException(status_code=404, detail="Service not found")
 94
 95    query = (
 96        db.query(Inbound)
 97        .join(Inbound.services)
 98        .where(Service.id == service.id)
 99    )
100
101    return paginate(query)
102
103
104@router.put("/{id}", response_model=ServiceResponse)
105async def modify_service(
106    id: int, modification: ServiceModify, db: DBDep, admin: SudoAdminDep
107):
108    """
109    Modify Service
110
111    - **name** can be up to 64 characters
112    - **inbounds** list of inbound ids. if not specified no change will be applied;
113    in case of an empty list all inbounds would be removed.
114    """
115    dbservice = crud.get_service(db, id)
116    if not dbservice:
117        raise HTTPException(status_code=404, detail="Service not found")
118    old_inbounds = {(i.node_id, i.protocol, i.tag) for i in dbservice.inbounds}
119    try:
120        response = crud.update_service(db, dbservice, modification)
121    except sqlalchemy.exc.IntegrityError:
122        db.rollback()
123        raise HTTPException(
124            status_code=409, detail="problem updating the service"
125        )
126    else:
127        for user in response.users:
128            if user.activated:
129                marznode.operations.update_user(
130                    user, old_inbounds=old_inbounds
131                )
132        return response
133
134
135@router.delete("/{id}")
136def remove_service(id: int, db: DBDep, admin: SudoAdminDep):
137    dbservice = crud.get_service(db, id)
138    if not dbservice:
139        raise HTTPException(status_code=404, detail="Service not found")
140
141    crud.remove_service(db, dbservice)
142    return dict()