gitscope
← marzneshin / nightly / 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, ServiceDep
 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(service: ServiceDep, db: DBDep, admin: AdminDep):
 50    """
 51    Get Service information with id
 52    """
 53    if not (
 54        admin.is_sudo or admin.all_services_access or id in admin.service_ids
 55    ):
 56        raise HTTPException(status_code=403, detail="You're not allowed")
 57
 58    return service
 59
 60
 61@router.get("/{id}/users", response_model=Page[UserResponse])
 62def get_service_users(service: ServiceDep, db: DBDep, admin: SudoAdminDep):
 63    """
 64    Get service users
 65    """
 66    query = (
 67        db.query(User)
 68        .join(User.services)
 69        .where(Service.id == service.id)
 70        .filter(User.removed != True)
 71    )
 72
 73    return paginate(query)
 74
 75
 76@router.get("/{id}/inbounds", response_model=Page[Inbound])
 77def get_service_inbounds(service: ServiceDep, db: DBDep, admin: SudoAdminDep):
 78    """
 79    Get service inbounds
 80    """
 81    query = (
 82        db.query(Inbound)
 83        .join(Inbound.services)
 84        .where(Service.id == service.id)
 85    )
 86
 87    return paginate(query)
 88
 89
 90@router.put("/{id}", response_model=ServiceResponse)
 91async def modify_service(
 92    service: ServiceDep,
 93    modification: ServiceModify,
 94    db: DBDep,
 95    admin: SudoAdminDep,
 96):
 97    """
 98    Modify Service
 99
100    - **name** can be up to 64 characters
101    - **inbounds** list of inbound ids. if not specified no change will be applied;
102    in case of an empty list all inbounds would be removed.
103    """
104    old_inbounds = {(i.node_id, i.protocol, i.tag) for i in service.inbounds}
105    try:
106        response = crud.update_service(db, service, modification)
107    except sqlalchemy.exc.IntegrityError:
108        db.rollback()
109        raise HTTPException(
110            status_code=409, detail="problem updating the service"
111        )
112    else:
113        for user in response.users:
114            if user.activated:
115                marznode.operations.update_user(
116                    user, old_inbounds=old_inbounds
117                )
118        return response
119
120
121@router.delete("/{id}")
122def remove_service(service: ServiceDep, db: DBDep, admin: SudoAdminDep):
123    crud.remove_service(db, service)
124    return dict()