POST /device route

This commit is contained in:
Jörn-Michael Miehe 2022-03-29 00:01:12 +00:00
parent cd3cccb540
commit 865e712ea5
5 changed files with 93 additions and 18 deletions

View file

@ -3,7 +3,7 @@ Package `db`: ORM and schemas for database content.
""" """
from .connection import Connection from .connection import Connection
from .device import Device, DeviceBase, DeviceCreate from .device import Device, DeviceBase, DeviceCreate, DeviceRead
from .user import User, UserBase, UserCreate, UserRead from .user import User, UserBase, UserCreate, UserRead
from .user_capability import UserCapabilityType from .user_capability import UserCapabilityType
@ -12,6 +12,7 @@ __all__ = [
"Device", "Device",
"DeviceBase", "DeviceBase",
"DeviceCreate", "DeviceCreate",
"DeviceRead",
"User", "User",
"UserBase", "UserBase",
"UserCreate", "UserCreate",

View file

@ -31,8 +31,6 @@ class DeviceCreate(DeviceBase):
Representation of a newly created device Representation of a newly created device
""" """
owner_name: str | None
class DeviceRead(DeviceBase): class DeviceRead(DeviceBase):
""" """
@ -62,25 +60,47 @@ class Device(DeviceBase, table=True):
) )
@classmethod @classmethod
def create(cls, **kwargs) -> Device | None: def create(
cls,
*,
owner: User,
device: DeviceCreate,
) -> Device | None:
""" """
Create a new device in the database. Create a new device in the database.
""" """
try: try:
with Connection.session as db: with Connection.session as db:
device = cls.from_orm(DeviceCreate(**kwargs)) new_device = cls.from_orm(device)
new_device.owner = owner
db.add(device) db.add(new_device)
db.commit() db.commit()
db.refresh(device) db.refresh(new_device)
return device return new_device
except IntegrityError: except IntegrityError:
# device already existed # device already existed
return None return None
@classmethod
def create_kwargs(
cls,
*,
owner: User,
**kwargs
) -> Device | None:
"""
Create a new device in the database. Keywords version.
"""
return cls.create(
owner=owner,
device=DeviceCreate(**kwargs),
)
def update(self) -> None: def update(self) -> None:
""" """
Update this device in the database. Update this device in the database.

View file

@ -6,11 +6,12 @@ This file: Main API router definition.
from fastapi import APIRouter from fastapi import APIRouter
from . import admin, user from . import admin, device, user
main_router = APIRouter() main_router = APIRouter()
main_router.include_router(admin.router) main_router.include_router(admin.router)
main_router.include_router(device.router)
main_router.include_router(user.router) main_router.include_router(user.router)
__all__ = [ __all__ = [

View file

@ -40,7 +40,7 @@ class Responses:
"description": "Must be admin", "description": "Must be admin",
"content": None, "content": None,
} }
NEEDS_ADMIN_OR_SELF = { NEEDS_REQUESTED_USER = {
"description": "Must be the requested user", "description": "Must be the requested user",
"content": None, "content": None,
} }
@ -99,20 +99,29 @@ async def get_current_user_if_admin(
return current_user return current_user
async def get_current_user_if_admin_or_self( async def get_user_by_name(
user_name: str, user_name: str,
current_user: User = Depends(get_current_user_if_exists), current_user: User = Depends(get_current_user_if_exists),
) -> User: ) -> User:
""" """
Get the currently logged-in user. Get a user by name.
Fails a) if the currently logged-in user is not the requested user, Works if a) the currently logged-in user is an admin,
and b) if it is not an admin. or b) if it is the requested user.
""" """
# fail if not requested by an admin or self # check if current user is admin
if not (current_user.can(UserCapabilityType.admin) if current_user.can(UserCapabilityType.admin):
or current_user.name == user_name): # fail if requested user doesn't exist
if (user := User.get(user_name)) is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)
# check if current user is requested user
elif current_user.name == user_name:
pass
# current user is neither admin nor the requested user
else:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN) raise HTTPException(status_code=status.HTTP_403_FORBIDDEN)
return current_user return user

View file

@ -0,0 +1,44 @@
"""
/device endpoints.
"""
from fastapi import APIRouter, Depends, HTTPException, status
from ..db import Device, DeviceCreate, DeviceRead, User
from ._common import Responses, get_user_by_name
router = APIRouter(prefix="/device", tags=["device"])
@router.post(
"",
responses={
status.HTTP_200_OK: Responses.OK,
status.HTTP_400_BAD_REQUEST: Responses.NOT_INSTALLED,
status.HTTP_401_UNAUTHORIZED: Responses.NEEDS_USER,
status.HTTP_403_FORBIDDEN: Responses.NEEDS_REQUESTED_USER,
status.HTTP_404_NOT_FOUND: Responses.ENTRY_DOESNT_EXIST,
status.HTTP_409_CONFLICT: Responses.ENTRY_EXISTS,
},
response_model=DeviceRead,
)
async def add_device(
device: DeviceCreate,
user: User = Depends(get_user_by_name),
) -> Device:
"""
POST ./: Create a new device in the database.
"""
# create the new device
new_device = Device.create(
owner=user,
device=device,
)
# fail if creation was unsuccessful
if new_device is None:
raise HTTPException(status_code=status.HTTP_409_CONFLICT)
# return the created device on success
return new_device