Skip to content

Commit

Permalink
rest schemas public
Browse files Browse the repository at this point in the history
  • Loading branch information
pcrespov committed Sep 4, 2024
1 parent 7eb3c1f commit b53f1ac
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 109 deletions.
2 changes: 1 addition & 1 deletion api/specs/web-server/_catalog_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
ServicePathParams,
ServiceTagPathParams,
)
from simcore_service_webserver.tags._handlers import TagGet
from simcore_service_webserver.tags.schemas import TagGet

router = APIRouter(
prefix=f"/{API_VTAG}",
Expand Down
2 changes: 1 addition & 1 deletion api/specs/web-server/_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from fastapi import APIRouter, Depends, status
from models_library.generics import Envelope
from simcore_service_webserver._meta import API_VTAG
from simcore_service_webserver.tags._handlers import (
from simcore_service_webserver.tags.schemas import (
TagCreate,
TagGet,
TagPathParams,
Expand Down
2 changes: 1 addition & 1 deletion api/specs/web-server/_tags_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from fastapi import APIRouter, Depends, status
from models_library.generics import Envelope
from simcore_service_webserver._meta import API_VTAG
from simcore_service_webserver.tags._handlers import (
from simcore_service_webserver.tags.schemas import (
TagGet,
TagGroupCreate,
TagGroupGet,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
from servicelib.aiohttp.requests_validation import parse_request_path_parameters_as

from .._meta import API_VTAG
from ..catalog._handlers import ServicePathParams
from ..login.decorators import login_required
from ..security.decorators import permission_required
from ..tags._handlers import TagGet
from ..tags.schemas import TagGet
from ._handlers import ServicePathParams

_logger = logging.getLogger(__name__)

Expand Down
117 changes: 13 additions & 104 deletions services/web/server/src/simcore_service_webserver/tags/_handlers.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,15 @@
import functools
import re
from datetime import datetime

from aiohttp import web
from aiopg.sa.engine import Engine
from models_library.api_schemas_webserver._base import InputSchema, OutputSchema
from models_library.users import GroupID, UserID
from pydantic import ConstrainedStr, Field, PositiveInt
from servicelib.aiohttp.application_keys import APP_DB_ENGINE_KEY
from servicelib.aiohttp.requests_validation import (
RequestParams,
StrictRequestParams,
parse_request_body_as,
parse_request_path_parameters_as,
)
from servicelib.aiohttp.typing_extension import Handler
from servicelib.mimetype_constants import MIMETYPE_APPLICATION_JSON
from servicelib.request_keys import RQT_USERID_KEY
from simcore_postgres_database.utils_tags import (
TagDict,
TagNotFoundError,
TagOperationNotAllowedError,
TagsRepo,
Expand All @@ -28,6 +19,15 @@
from ..login.decorators import login_required
from ..security.decorators import permission_required
from ..utils_aiohttp import envelope_json_response
from .schemas import (
TagCreate,
TagGet,
TagGroupCreate,
TagGroupPathParams,
TagPathParams,
TagRequestContext,
TagUpdate,
)


def _handle_tags_exceptions(handler: Handler):
Expand All @@ -45,71 +45,6 @@ async def wrapper(request: web.Request) -> web.StreamResponse:
return wrapper


#
# API components/schemas
#


class _RequestContext(RequestParams):
user_id: UserID = Field(..., alias=RQT_USERID_KEY) # type: ignore[literal-required]


class TagPathParams(StrictRequestParams):
tag_id: PositiveInt


class ColorStr(ConstrainedStr):
regex = re.compile(r"^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$")


class TagUpdate(InputSchema):
name: str | None = None
description: str | None = None
color: ColorStr | None = None


class TagCreate(InputSchema):
name: str
description: str | None = None
color: ColorStr


class TagAccessRights(OutputSchema):
# NOTE: analogous to GroupAccessRights
read: bool
write: bool
delete: bool


class TagGet(OutputSchema):
id: PositiveInt
name: str
description: str | None = None
color: str

# analogous to UsersGroup
access_rights: TagAccessRights = Field(..., alias="accessRights")

@classmethod
def from_db(cls, tag: TagDict) -> "TagGet":
# NOTE: cls(access_rights=tag, **tag) would also work because of Config
return cls(
id=tag["id"],
name=tag["name"],
description=tag["description"],
color=tag["color"],
access_rights=TagAccessRights( # type: ignore[call-arg]
read=tag["read"],
write=tag["write"],
delete=tag["delete"],
),
)


#
# API handlers
#

routes = web.RouteTableDef()


Expand All @@ -119,7 +54,7 @@ def from_db(cls, tag: TagDict) -> "TagGet":
@_handle_tags_exceptions
async def create_tag(request: web.Request):
engine: Engine = request.app[APP_DB_ENGINE_KEY]
req_ctx = _RequestContext.parse_obj(request)
req_ctx = TagRequestContext.parse_obj(request)
new_tag = await parse_request_body_as(TagCreate, request)

repo = TagsRepo(user_id=req_ctx.user_id)
Expand All @@ -141,7 +76,7 @@ async def create_tag(request: web.Request):
@_handle_tags_exceptions
async def list_tags(request: web.Request):
engine: Engine = request.app[APP_DB_ENGINE_KEY]
req_ctx = _RequestContext.parse_obj(request)
req_ctx = TagRequestContext.parse_obj(request)

repo = TagsRepo(user_id=req_ctx.user_id)
async with engine.acquire() as conn:
Expand All @@ -157,7 +92,7 @@ async def list_tags(request: web.Request):
@_handle_tags_exceptions
async def update_tag(request: web.Request):
engine: Engine = request.app[APP_DB_ENGINE_KEY]
req_ctx = _RequestContext.parse_obj(request)
req_ctx = TagRequestContext.parse_obj(request)
path_params = parse_request_path_parameters_as(TagPathParams, request)
tag_updates = await parse_request_body_as(TagUpdate, request)

Expand All @@ -176,7 +111,7 @@ async def update_tag(request: web.Request):
@_handle_tags_exceptions
async def delete_tag(request: web.Request):
engine: Engine = request.app[APP_DB_ENGINE_KEY]
req_ctx = _RequestContext.parse_obj(request)
req_ctx = TagRequestContext.parse_obj(request)
path_params = parse_request_path_parameters_as(TagPathParams, request)

repo = TagsRepo(user_id=req_ctx.user_id)
Expand All @@ -186,32 +121,6 @@ async def delete_tag(request: web.Request):
raise web.HTTPNoContent(content_type=MIMETYPE_APPLICATION_JSON)


#
# Share API
#


class TagGroupPathParams(TagPathParams):
group_id: GroupID


class TagGroupCreate(InputSchema):
read: bool
write: bool
delete: bool


class TagGroupGet(OutputSchema):
gid: GroupID
# access
read: bool
write: bool
delete: bool
# timestamps
created: datetime
modified: datetime


@routes.get(f"/{VTAG}/tags/{{tag_id}}/groups", name="list_tag_groups")
@login_required
@permission_required("tag.crud.*")
Expand Down
91 changes: 91 additions & 0 deletions services/web/server/src/simcore_service_webserver/tags/schemas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import re
from datetime import datetime

from models_library.api_schemas_webserver._base import InputSchema, OutputSchema
from models_library.users import GroupID, UserID
from pydantic import ConstrainedStr, Field, PositiveInt
from servicelib.aiohttp.requests_validation import RequestParams, StrictRequestParams
from servicelib.request_keys import RQT_USERID_KEY
from simcore_postgres_database.utils_tags import TagDict


class TagRequestContext(RequestParams):
user_id: UserID = Field(..., alias=RQT_USERID_KEY) # type: ignore[literal-required]


class TagPathParams(StrictRequestParams):
tag_id: PositiveInt


class ColorStr(ConstrainedStr):
regex = re.compile(r"^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$")


class TagUpdate(InputSchema):
name: str | None = None
description: str | None = None
color: ColorStr | None = None


class TagCreate(InputSchema):
name: str
description: str | None = None
color: ColorStr


class TagAccessRights(OutputSchema):
# NOTE: analogous to GroupAccessRights
read: bool
write: bool
delete: bool


class TagGet(OutputSchema):
id: PositiveInt
name: str
description: str | None = None
color: str

# analogous to UsersGroup
access_rights: TagAccessRights = Field(..., alias="accessRights")

@classmethod
def from_db(cls, tag: TagDict) -> "TagGet":
# NOTE: cls(access_rights=tag, **tag) would also work because of Config
return cls(
id=tag["id"],
name=tag["name"],
description=tag["description"],
color=tag["color"],
access_rights=TagAccessRights( # type: ignore[call-arg]
read=tag["read"],
write=tag["write"],
delete=tag["delete"],
),
)


#
# Share API: GROUPS
#


class TagGroupPathParams(TagPathParams):
group_id: GroupID


class TagGroupCreate(InputSchema):
read: bool
write: bool
delete: bool


class TagGroupGet(OutputSchema):
gid: GroupID
# access
read: bool
write: bool
delete: bool
# timestamps
created: datetime
modified: datetime

0 comments on commit b53f1ac

Please sign in to comment.