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