1import sqlalchemy
2from fastapi import APIRouter, Depends, Query
3from fastapi import HTTPException
4from fastapi_pagination.customization import UseParamsFields, CustomizedPage
5from fastapi_pagination.ext.sqlalchemy import paginate
6from fastapi_pagination.links import Page
7
8from app import marznode
9from app.db import crud
10from app.db.models import Service
11from app.dependencies import DBDep, sudo_admin
12from app.models.service import ServiceCreate, ServiceModify, ServiceResponse
13
14router = APIRouter(
15 prefix="/services", dependencies=[Depends(sudo_admin)], tags=["Service"]
16)
17
18
19@router.get("", response_model=Page[ServiceResponse])
20def get_services(db: DBDep, name: str = Query(None)):
21 query = db.query(Service)
22 if name:
23 query = query.filter(Service.name.ilike(f"%{name}%"))
24 return paginate(query)
25
26
27@router.post("", response_model=ServiceResponse)
28def add_service(new_service: ServiceCreate, db: DBDep):
29 """
30 Add a new service
31
32 - **name** service name
33 - **inbounds** list of inbound ids
34 """
35 try:
36 return crud.create_service(db, new_service)
37 except sqlalchemy.exc.IntegrityError:
38 db.rollback()
39 raise HTTPException(
40 status_code=409, detail="Service by this name already exists"
41 )
42
43
44@router.get("/{id}", response_model=ServiceResponse)
45def get_service(id: int, db: DBDep):
46 """
47 Get Service information with id
48 """
49 dbservice = crud.get_service(db, id)
50 if not dbservice:
51 raise HTTPException(status_code=404, detail="Service not found")
52
53 return dbservice
54
55
56@router.put("/{id}", response_model=ServiceResponse)
57async def modify_service(id: int, modification: ServiceModify, db: DBDep):
58 """
59 Modify Service
60
61 - **name** can be up to 64 characters
62 - **inbounds** list of inbound ids. if not specified no change will be applied;
63 in case of an empty list all inbounds would be removed.
64 """
65 # TODO: Update all affected users in nodes
66 dbservice = crud.get_service(db, id)
67 if not dbservice:
68 raise HTTPException(status_code=404, detail="Service not found")
69 old_inbounds = {(i.node_id, i.protocol, i.tag) for i in dbservice.inbounds}
70 try:
71 response = crud.update_service(db, dbservice, modification)
72 except sqlalchemy.exc.IntegrityError:
73 db.rollback()
74 raise HTTPException(status_code=409, detail="problem updating the service")
75 else:
76 for user in response.users:
77 await marznode.operations.update_user(user, old_inbounds=old_inbounds)
78 return response
79
80
81@router.delete("/{id}")
82def remove_service(id: int, db: DBDep):
83 dbservice = crud.get_service(db, id)
84 if not dbservice:
85 raise HTTPException(status_code=404, detail="Service not found")
86
87 crud.remove_service(db, dbservice)
88 return dict()