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 .device import Device, DeviceBase, DeviceCreate
from .device import Device, DeviceBase, DeviceCreate, DeviceRead
from .user import User, UserBase, UserCreate, UserRead
from .user_capability import UserCapabilityType
@ -12,6 +12,7 @@ __all__ = [
"Device",
"DeviceBase",
"DeviceCreate",
"DeviceRead",
"User",
"UserBase",
"UserCreate",

View file

@ -31,8 +31,6 @@ class DeviceCreate(DeviceBase):
Representation of a newly created device
"""
owner_name: str | None
class DeviceRead(DeviceBase):
"""
@ -62,25 +60,47 @@ class Device(DeviceBase, table=True):
)
@classmethod
def create(cls, **kwargs) -> Device | None:
def create(
cls,
*,
owner: User,
device: DeviceCreate,
) -> Device | None:
"""
Create a new device in the database.
"""
try:
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.refresh(device)
db.refresh(new_device)
return device
return new_device
except IntegrityError:
# device already existed
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:
"""
Update this device in the database.

View file

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

View file

@ -40,7 +40,7 @@ class Responses:
"description": "Must be admin",
"content": None,
}
NEEDS_ADMIN_OR_SELF = {
NEEDS_REQUESTED_USER = {
"description": "Must be the requested user",
"content": None,
}
@ -99,20 +99,29 @@ async def get_current_user_if_admin(
return current_user
async def get_current_user_if_admin_or_self(
async def get_user_by_name(
user_name: str,
current_user: User = Depends(get_current_user_if_exists),
) -> 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,
and b) if it is not an admin.
Works if a) the currently logged-in user is an admin,
or b) if it is the requested user.
"""
# fail if not requested by an admin or self
if not (current_user.can(UserCapabilityType.admin)
or current_user.name == user_name):
# check if current user is admin
if current_user.can(UserCapabilityType.admin):
# 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)
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