Merge branch '3.0' into image-management-refactoring

This commit is contained in:
Jeremy Grossmann
2021-08-10 05:46:22 -07:00
committed by GitHub
96 changed files with 1067 additions and 843 deletions

View File

@ -104,7 +104,6 @@ router.include_router(
router.include_router(
symbols.router,
dependencies=[Depends(get_current_active_user)],
prefix="/symbols", tags=["Symbols"]
)

View File

@ -18,7 +18,7 @@
API routes for computes.
"""
from fastapi import APIRouter, Depends, status
from fastapi import APIRouter, Depends, Response, status
from typing import List, Union
from uuid import UUID
@ -93,12 +93,13 @@ async def update_compute(
@router.delete("/{compute_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_compute(
compute_id: Union[str, UUID], computes_repo: ComputesRepository = Depends(get_repository(ComputesRepository))
) -> None:
) -> Response:
"""
Delete a compute from the controller.
"""
await ComputesService(computes_repo).delete_compute(compute_id)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{compute_id}/{emulator}/images")

View File

@ -18,7 +18,7 @@ import asyncio
import signal
import os
from fastapi import APIRouter, Depends, status
from fastapi import APIRouter, Depends, Response, status
from fastapi.encoders import jsonable_encoder
from typing import List
@ -72,12 +72,13 @@ def check_version(version: schemas.Version) -> dict:
dependencies=[Depends(get_current_active_user)],
status_code=status.HTTP_204_NO_CONTENT,
)
async def reload() -> None:
async def reload() -> Response:
"""
Reload the controller
"""
await Controller.instance().reload()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post(
@ -86,7 +87,7 @@ async def reload() -> None:
status_code=status.HTTP_204_NO_CONTENT,
responses={403: {"model": schemas.ErrorMessage, "description": "Server shutdown not allowed"}},
)
async def shutdown() -> None:
async def shutdown() -> Response:
"""
Shutdown the server
"""
@ -114,6 +115,7 @@ async def shutdown() -> None:
# then shutdown the server itself
os.kill(os.getpid(), signal.SIGTERM)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get(

View File

@ -18,7 +18,7 @@
API routes for drawings.
"""
from fastapi import APIRouter, status
from fastapi import APIRouter, Response, status
from fastapi.encoders import jsonable_encoder
from typing import List
from uuid import UUID
@ -76,10 +76,11 @@ async def update_drawing(project_id: UUID, drawing_id: UUID, drawing_data: schem
@router.delete("/{drawing_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_drawing(project_id: UUID, drawing_id: UUID) -> None:
async def delete_drawing(project_id: UUID, drawing_id: UUID) -> Response:
"""
Delete a drawing.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
await project.delete_drawing(str(drawing_id))
return Response(status_code=status.HTTP_204_NO_CONTENT)

View File

@ -19,7 +19,7 @@
API routes for user groups.
"""
from fastapi import APIRouter, Depends, status
from fastapi import APIRouter, Depends, Response, status
from uuid import UUID
from typing import List
@ -113,7 +113,7 @@ async def update_user_group(
async def delete_user_group(
user_group_id: UUID,
users_repo: UsersRepository = Depends(get_repository(UsersRepository)),
) -> None:
) -> Response:
"""
Delete an user group
"""
@ -129,6 +129,8 @@ async def delete_user_group(
if not success:
raise ControllerError(f"User group '{user_group_id}' could not be deleted")
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{user_group_id}/members", response_model=List[schemas.User])
async def get_user_group_members(
@ -150,7 +152,7 @@ async def add_member_to_group(
user_group_id: UUID,
user_id: UUID,
users_repo: UsersRepository = Depends(get_repository(UsersRepository))
) -> None:
) -> Response:
"""
Add member to an user group.
"""
@ -163,6 +165,8 @@ async def add_member_to_group(
if not user_group:
raise ControllerNotFoundError(f"User group '{user_group_id}' not found")
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.delete(
"/{user_group_id}/members/{user_id}",
@ -172,7 +176,7 @@ async def remove_member_from_group(
user_group_id: UUID,
user_id: UUID,
users_repo: UsersRepository = Depends(get_repository(UsersRepository)),
) -> None:
) -> Response:
"""
Remove member from an user group.
"""
@ -185,6 +189,8 @@ async def remove_member_from_group(
if not user_group:
raise ControllerNotFoundError(f"User group '{user_group_id}' not found")
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{user_group_id}/roles", response_model=List[schemas.Role])
async def get_user_group_roles(
@ -207,7 +213,7 @@ async def add_role_to_group(
role_id: UUID,
users_repo: UsersRepository = Depends(get_repository(UsersRepository)),
rbac_repo: RbacRepository = Depends(get_repository(RbacRepository))
) -> None:
) -> Response:
"""
Add role to an user group.
"""
@ -220,6 +226,8 @@ async def add_role_to_group(
if not user_group:
raise ControllerNotFoundError(f"User group '{user_group_id}' not found")
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.delete(
"/{user_group_id}/roles/{role_id}",
@ -230,7 +238,7 @@ async def remove_role_from_group(
role_id: UUID,
users_repo: UsersRepository = Depends(get_repository(UsersRepository)),
rbac_repo: RbacRepository = Depends(get_repository(RbacRepository))
) -> None:
) -> Response:
"""
Remove role from an user group.
"""
@ -242,3 +250,5 @@ async def remove_role_from_group(
user_group = await users_repo.remove_role_from_user_group(user_group_id, role)
if not user_group:
raise ControllerNotFoundError(f"User group '{user_group_id}' not found")
return Response(status_code=status.HTTP_204_NO_CONTENT)

View File

@ -21,7 +21,7 @@ API routes for links.
import multidict
import aiohttp
from fastapi import APIRouter, Depends, Request, status
from fastapi import APIRouter, Depends, Request, Response, status
from fastapi.responses import StreamingResponse
from fastapi.encoders import jsonable_encoder
from typing import List
@ -81,6 +81,8 @@ async def create_link(project_id: UUID, link_data: schemas.LinkCreate) -> schema
link_data = jsonable_encoder(link_data, exclude_unset=True)
if "filters" in link_data:
await link.update_filters(link_data["filters"])
if "link_style" in link_data:
await link.update_link_style(link_data["link_style"])
if "suspend" in link_data:
await link.update_suspend(link_data["suspend"])
try:
@ -124,6 +126,8 @@ async def update_link(link_data: schemas.LinkUpdate, link: Link = Depends(dep_li
link_data = jsonable_encoder(link_data, exclude_unset=True)
if "filters" in link_data:
await link.update_filters(link_data["filters"])
if "link_style" in link_data:
await link.update_link_style(link_data["link_style"])
if "suspend" in link_data:
await link.update_suspend(link_data["suspend"])
if "nodes" in link_data:
@ -132,13 +136,14 @@ async def update_link(link_data: schemas.LinkUpdate, link: Link = Depends(dep_li
@router.delete("/{link_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_link(project_id: UUID, link: Link = Depends(dep_link)) -> None:
async def delete_link(project_id: UUID, link: Link = Depends(dep_link)) -> Response:
"""
Delete a link.
"""
project = await Controller.instance().get_loaded_project(str(project_id))
await project.delete_link(link.id)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{link_id}/reset", response_model=schemas.Link)
@ -165,12 +170,13 @@ async def start_capture(capture_data: dict, link: Link = Depends(dep_link)) -> s
@router.post("/{link_id}/capture/stop", status_code=status.HTTP_204_NO_CONTENT)
async def stop_capture(link: Link = Depends(dep_link)) -> None:
async def stop_capture(link: Link = Depends(dep_link)) -> Response:
"""
Stop packet capture on the link.
"""
await link.stop_capture()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{link_id}/capture/stream")

View File

@ -130,40 +130,44 @@ async def get_nodes(project: Project = Depends(dep_project)) -> List[schemas.Nod
@router.post("/start", status_code=status.HTTP_204_NO_CONTENT)
async def start_all_nodes(project: Project = Depends(dep_project)) -> None:
async def start_all_nodes(project: Project = Depends(dep_project)) -> Response:
"""
Start all nodes belonging to a given project.
"""
await project.start_all()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/stop", status_code=status.HTTP_204_NO_CONTENT)
async def stop_all_nodes(project: Project = Depends(dep_project)) -> None:
async def stop_all_nodes(project: Project = Depends(dep_project)) -> Response:
"""
Stop all nodes belonging to a given project.
"""
await project.stop_all()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/suspend", status_code=status.HTTP_204_NO_CONTENT)
async def suspend_all_nodes(project: Project = Depends(dep_project)) -> None:
async def suspend_all_nodes(project: Project = Depends(dep_project)) -> Response:
"""
Suspend all nodes belonging to a given project.
"""
await project.suspend_all()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/reload", status_code=status.HTTP_204_NO_CONTENT)
async def reload_all_nodes(project: Project = Depends(dep_project)) -> None:
async def reload_all_nodes(project: Project = Depends(dep_project)) -> Response:
"""
Reload all nodes belonging to a given project.
"""
await project.stop_all()
await project.start_all()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{node_id}", response_model=schemas.Node)
@ -197,12 +201,13 @@ async def update_node(node_data: schemas.NodeUpdate, node: Node = Depends(dep_no
status_code=status.HTTP_204_NO_CONTENT,
responses={**responses, 409: {"model": schemas.ErrorMessage, "description": "Cannot delete node"}},
)
async def delete_node(node_id: UUID, project: Project = Depends(dep_project)) -> None:
async def delete_node(node_id: UUID, project: Project = Depends(dep_project)) -> Response:
"""
Delete a node from a project.
"""
await project.delete_node(str(node_id))
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/duplicate", response_model=schemas.Node, status_code=status.HTTP_201_CREATED)
@ -216,39 +221,43 @@ async def duplicate_node(duplicate_data: schemas.NodeDuplicate, node: Node = Dep
@router.post("/{node_id}/start", status_code=status.HTTP_204_NO_CONTENT)
async def start_node(start_data: dict, node: Node = Depends(dep_node)) -> None:
async def start_node(start_data: dict, node: Node = Depends(dep_node)) -> Response:
"""
Start a node.
"""
await node.start(data=start_data)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/stop", status_code=status.HTTP_204_NO_CONTENT)
async def stop_node(node: Node = Depends(dep_node)) -> None:
async def stop_node(node: Node = Depends(dep_node)) -> Response:
"""
Stop a node.
"""
await node.stop()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/suspend", status_code=status.HTTP_204_NO_CONTENT)
async def suspend_node(node: Node = Depends(dep_node)) -> None:
async def suspend_node(node: Node = Depends(dep_node)) -> Response:
"""
Suspend a node.
"""
await node.suspend()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/reload", status_code=status.HTTP_204_NO_CONTENT)
async def reload_node(node: Node = Depends(dep_node)) -> None:
async def reload_node(node: Node = Depends(dep_node)) -> Response:
"""
Reload a node.
"""
await node.reload()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{node_id}/links", response_model=List[schemas.Link], response_model_exclude_unset=True)
@ -282,11 +291,13 @@ async def idlepc_proposals(node: Node = Depends(dep_node)) -> List[str]:
@router.post("/{node_id}/resize_disk", status_code=status.HTTP_204_NO_CONTENT)
async def resize_disk(resize_data: dict, node: Node = Depends(dep_node)) -> None:
async def resize_disk(resize_data: dict, node: Node = Depends(dep_node)) -> Response:
"""
Resize a disk image.
"""
await node.post("/resize_disk", **resize_data)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{node_id}/files/{file_path:path}")
@ -377,15 +388,17 @@ async def ws_console(websocket: WebSocket, node: Node = Depends(dep_node)) -> No
@router.post("/console/reset", status_code=status.HTTP_204_NO_CONTENT)
async def reset_console_all_nodes(project: Project = Depends(dep_project)) -> None:
async def reset_console_all_nodes(project: Project = Depends(dep_project)) -> Response:
"""
Reset console for all nodes belonging to the project.
"""
await project.reset_console_all()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{node_id}/console/reset", status_code=status.HTTP_204_NO_CONTENT)
async def console_reset(node: Node = Depends(dep_node)) -> None:
async def console_reset(node: Node = Depends(dep_node)) -> Response:
await node.post("/console/reset") # , request.json)
await node.post("/console/reset")
return Response(status_code=status.HTTP_204_NO_CONTENT)

View File

@ -19,7 +19,7 @@
API routes for permissions.
"""
from fastapi import APIRouter, Depends, status
from fastapi import APIRouter, Depends, Response, status
from uuid import UUID
from typing import List
@ -104,7 +104,7 @@ async def update_permission(
async def delete_permission(
permission_id: UUID,
rbac_repo: RbacRepository = Depends(get_repository(RbacRepository)),
) -> None:
) -> Response:
"""
Delete a permission.
"""
@ -116,3 +116,6 @@ async def delete_permission(
success = await rbac_repo.delete_permission(permission_id)
if not success:
raise ControllerError(f"Permission '{permission_id}' could not be deleted")
return Response(status_code=status.HTTP_204_NO_CONTENT)

View File

@ -30,7 +30,7 @@ import logging
log = logging.getLogger()
from fastapi import APIRouter, Depends, Request, Body, HTTPException, status, WebSocket, WebSocketDisconnect
from fastapi import APIRouter, Depends, Request, Response, Body, HTTPException, status, WebSocket, WebSocketDisconnect
from fastapi.encoders import jsonable_encoder
from fastapi.responses import StreamingResponse, FileResponse
from websockets.exceptions import ConnectionClosed, WebSocketException
@ -141,7 +141,7 @@ async def update_project(
async def delete_project(
project: Project = Depends(dep_project),
rbac_repo: RbacRepository = Depends(get_repository(RbacRepository))
) -> None:
) -> Response:
"""
Delete a project.
"""
@ -150,6 +150,7 @@ async def delete_project(
await project.delete()
controller.remove_project(project)
await rbac_repo.delete_all_permissions_with_path(f"/projects/{project.id}")
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{project_id}/stats")
@ -166,12 +167,13 @@ def get_project_stats(project: Project = Depends(dep_project)) -> dict:
status_code=status.HTTP_204_NO_CONTENT,
responses={**responses, 409: {"model": schemas.ErrorMessage, "description": "Could not close project"}},
)
async def close_project(project: Project = Depends(dep_project)) -> None:
async def close_project(project: Project = Depends(dep_project)) -> Response:
"""
Close a project.
"""
await project.close()
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post(
@ -415,7 +417,7 @@ async def get_file(file_path: str, project: Project = Depends(dep_project)) -> F
@router.post("/{project_id}/files/{file_path:path}", status_code=status.HTTP_204_NO_CONTENT)
async def write_file(file_path: str, request: Request, project: Project = Depends(dep_project)) -> None:
async def write_file(file_path: str, request: Request, project: Project = Depends(dep_project)) -> Response:
"""
Write a file from a project.
"""
@ -440,6 +442,8 @@ async def write_file(file_path: str, request: Request, project: Project = Depend
except OSError as e:
raise ControllerError(str(e))
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post(
"/{project_id}/templates/{template_id}",

View File

@ -19,7 +19,7 @@
API routes for roles.
"""
from fastapi import APIRouter, Depends, status
from fastapi import APIRouter, Depends, Response, status
from uuid import UUID
from typing import List
@ -106,7 +106,7 @@ async def update_role(
async def delete_role(
role_id: UUID,
rbac_repo: RbacRepository = Depends(get_repository(RbacRepository)),
) -> None:
) -> Response:
"""
Delete a role.
"""
@ -122,6 +122,8 @@ async def delete_role(
if not success:
raise ControllerError(f"Role '{role_id}' could not be deleted")
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("/{role_id}/permissions", response_model=List[schemas.Permission])
async def get_role_permissions(
@ -143,7 +145,7 @@ async def add_permission_to_role(
role_id: UUID,
permission_id: UUID,
rbac_repo: RbacRepository = Depends(get_repository(RbacRepository))
) -> None:
) -> Response:
"""
Add a permission to a role.
"""
@ -156,6 +158,8 @@ async def add_permission_to_role(
if not role:
raise ControllerNotFoundError(f"Role '{role_id}' not found")
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.delete(
"/{role_id}/permissions/{permission_id}",
@ -165,7 +169,7 @@ async def remove_permission_from_role(
role_id: UUID,
permission_id: UUID,
rbac_repo: RbacRepository = Depends(get_repository(RbacRepository)),
) -> None:
) -> Response:
"""
Remove member from an user group.
"""
@ -177,3 +181,5 @@ async def remove_permission_from_role(
role = await rbac_repo.remove_permission_from_role(role_id, permission)
if not role:
raise ControllerNotFoundError(f"Role '{role_id}' not found")
return Response(status_code=status.HTTP_204_NO_CONTENT)

View File

@ -23,7 +23,7 @@ import logging
log = logging.getLogger()
from fastapi import APIRouter, Depends, status
from fastapi import APIRouter, Depends, Response, status
from typing import List
from uuid import UUID
@ -69,12 +69,13 @@ def get_snapshots(project: Project = Depends(dep_project)) -> List[schemas.Snaps
@router.delete("/{snapshot_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_snapshot(snapshot_id: UUID, project: Project = Depends(dep_project)) -> None:
async def delete_snapshot(snapshot_id: UUID, project: Project = Depends(dep_project)) -> Response:
"""
Delete a snapshot.
"""
await project.delete_snapshot(str(snapshot_id))
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post("/{snapshot_id}/restore", status_code=status.HTTP_201_CREATED, response_model=schemas.Project)

View File

@ -21,7 +21,7 @@ API routes for symbols.
import os
from fastapi import APIRouter, Request, status
from fastapi import APIRouter, Request, Depends, Response, status
from fastapi.responses import FileResponse
from typing import List
@ -29,6 +29,8 @@ from gns3server.controller import Controller
from gns3server import schemas
from gns3server.controller.controller_error import ControllerError, ControllerNotFoundError
from .dependencies.authentication import get_current_active_user
import logging
log = logging.getLogger(__name__)
@ -57,7 +59,7 @@ async def get_symbol(symbol_id: str) -> FileResponse:
symbol = controller.symbols.get_path(symbol_id)
return FileResponse(symbol)
except (KeyError, OSError) as e:
return ControllerNotFoundError(f"Could not get symbol file: {e}")
raise ControllerNotFoundError(f"Could not get symbol file: {e}")
@router.get(
@ -75,11 +77,25 @@ async def get_symbol_dimensions(symbol_id: str) -> dict:
symbol_dimensions = {"width": width, "height": height}
return symbol_dimensions
except (KeyError, OSError, ValueError) as e:
return ControllerNotFoundError(f"Could not get symbol file: {e}")
raise ControllerNotFoundError(f"Could not get symbol file: {e}")
@router.post("/{symbol_id:path}/raw", status_code=status.HTTP_204_NO_CONTENT)
async def upload_symbol(symbol_id: str, request: Request) -> None:
@router.get("/default_symbols")
def get_default_symbols() -> dict:
"""
Return all default symbols.
"""
controller = Controller.instance()
return controller.symbols.default_symbols()
@router.post(
"/{symbol_id:path}/raw",
dependencies=[Depends(get_current_active_user)],
status_code=status.HTTP_204_NO_CONTENT
)
async def upload_symbol(symbol_id: str, request: Request) -> Response:
"""
Upload a symbol file.
"""
@ -96,12 +112,4 @@ async def upload_symbol(symbol_id: str, request: Request) -> None:
# Reset the symbol list
controller.symbols.list()
@router.get("/default_symbols")
def get_default_symbols() -> dict:
"""
Return all default symbols.
"""
controller = Controller.instance()
return controller.symbols.default_symbols()
return Response(status_code=status.HTTP_204_NO_CONTENT)

View File

@ -25,7 +25,7 @@ import logging
log = logging.getLogger(__name__)
from fastapi import APIRouter, Request, Response, HTTPException, Depends, status
from fastapi import APIRouter, Request, Response, HTTPException, Depends, Response, status
from typing import List
from uuid import UUID
@ -99,13 +99,14 @@ async def delete_template(
template_id: UUID,
templates_repo: TemplatesRepository = Depends(get_repository(TemplatesRepository)),
rbac_repo: RbacRepository = Depends(get_repository(RbacRepository))
) -> None:
) -> Response:
"""
Delete a template.
"""
await TemplatesService(templates_repo).delete_template(template_id)
await rbac_repo.delete_all_permissions_with_path(f"/templates/{template_id}")
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get("", response_model=List[schemas.Template], response_model_exclude_unset=True)

View File

@ -19,7 +19,7 @@
API routes for users.
"""
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi import APIRouter, Depends, HTTPException, Response, status
from fastapi.security import OAuth2PasswordRequestForm
from uuid import UUID
from typing import List
@ -99,13 +99,20 @@ async def get_logged_in_user(current_user: schemas.User = Depends(get_current_ac
return current_user
@router.get("/me", response_model=schemas.User)
async def get_logged_in_user(current_user: schemas.User = Depends(get_current_active_user)) -> schemas.User:
@router.put("/me", response_model=schemas.User)
async def update_logged_in_user(
user_update: schemas.LoggedInUserUpdate,
current_user: schemas.User = Depends(get_current_active_user),
users_repo: UsersRepository = Depends(get_repository(UsersRepository))
) -> schemas.User:
"""
Get the current active user.
Update the current active user.
"""
return current_user
if user_update.email and await users_repo.get_user_by_email(user_update.email):
raise ControllerBadRequestError(f"Email '{user_update.email}' is already registered")
return await users_repo.update_user(current_user.user_id, user_update)
@router.get("", response_model=List[schemas.User], dependencies=[Depends(get_current_active_user)])
@ -167,6 +174,12 @@ async def update_user(
Update an user.
"""
if user_update.username and await users_repo.get_user_by_username(user_update.username):
raise ControllerBadRequestError(f"Username '{user_update.username}' is already registered")
if user_update.email and await users_repo.get_user_by_email(user_update.email):
raise ControllerBadRequestError(f"Email '{user_update.email}' is already registered")
user = await users_repo.update_user(user_id, user_update)
if not user:
raise ControllerNotFoundError(f"User '{user_id}' not found")
@ -181,7 +194,7 @@ async def update_user(
async def delete_user(
user_id: UUID,
users_repo: UsersRepository = Depends(get_repository(UsersRepository)),
) -> None:
) -> Response:
"""
Delete an user.
"""
@ -197,6 +210,8 @@ async def delete_user(
if not success:
raise ControllerError(f"User '{user_id}' could not be deleted")
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.get(
"/{user_id}/groups",
@ -239,7 +254,7 @@ async def add_permission_to_user(
user_id: UUID,
permission_id: UUID,
rbac_repo: RbacRepository = Depends(get_repository(RbacRepository))
) -> None:
) -> Response:
"""
Add a permission to an user.
"""
@ -252,6 +267,8 @@ async def add_permission_to_user(
if not user:
raise ControllerNotFoundError(f"User '{user_id}' not found")
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.delete(
"/{user_id}/permissions/{permission_id}",
@ -262,7 +279,7 @@ async def remove_permission_from_user(
user_id: UUID,
permission_id: UUID,
rbac_repo: RbacRepository = Depends(get_repository(RbacRepository)),
) -> None:
) -> Response:
"""
Remove permission from an user.
"""
@ -274,3 +291,5 @@ async def remove_permission_from_user(
user = await rbac_repo.remove_permission_from_user(user_id, permission)
if not user:
raise ControllerNotFoundError(f"User '{user_id}' not found")
return Response(status_code=status.HTTP_204_NO_CONTENT)