diff --git a/Tekst-API/tekst/models/browse.py b/Tekst-API/tekst/models/browse.py index 8d606def..d5837ca6 100644 --- a/Tekst-API/tekst/models/browse.py +++ b/Tekst-API/tekst/models/browse.py @@ -1,8 +1,8 @@ from tekst.models.common import ModelBase from tekst.models.location import LocationRead -from tekst.resources import AnyContentReadBody +from tekst.resources import AnyContentRead class LocationData(ModelBase): location_path: list[LocationRead] = [] - contents: list[AnyContentReadBody] = [] + contents: list[AnyContentRead] = [] diff --git a/Tekst-API/tekst/models/common.py b/Tekst-API/tekst/models/common.py index dd228841..e28c061f 100644 --- a/Tekst-API/tekst/models/common.py +++ b/Tekst-API/tekst/models/common.py @@ -74,19 +74,17 @@ class TranslationBase(TypedDict): ) -class ModelTransformerMixin: - @classmethod - def model_from(cls, obj: BaseModel) -> BaseModel: - return cls.model_validate(obj, from_attributes=True) - - -class ModelBase(ModelTransformerMixin, BaseModel): +class ModelBase(BaseModel): model_config = ConfigDict( alias_generator=camelize, populate_by_name=True, from_attributes=True, ) + @classmethod + def model_from(cls, obj: BaseModel) -> BaseModel: + return cls.model_validate(obj, from_attributes=True) + @classmethod def _field_excluded_from_model_variant( cls, field_name: str, model_variant: Literal["create", "update"] @@ -109,7 +107,7 @@ def _field_excluded_from_model_variant( return False -class DocumentBase(ModelTransformerMixin, Document): +class DocumentBase(Document): """Base model for all Tekst ODMs""" class Settings: diff --git a/Tekst-API/tekst/resources/__init__.py b/Tekst-API/tekst/resources/__init__.py index a7f43fd2..b53de4a6 100644 --- a/Tekst-API/tekst/resources/__init__.py +++ b/Tekst-API/tekst/resources/__init__.py @@ -462,117 +462,107 @@ def init_resource_types_mgr() -> None: # ### create union type aliases for models of any resource type model -# CREATE -AnyResourceCreate = Union[ # noqa: UP007 - tuple( - [ - rt.resource_model().create_model() - for rt in resource_types_mgr.get_all().values() - ] - ) -] -AnyResourceCreateBody = Annotated[ - AnyResourceCreate, +AnyResourceCreate = Annotated[ + Union[ # noqa: UP007 + tuple( + [ + rt.resource_model().create_model() + for rt in resource_types_mgr.get_all().values() + ] + ) + ], Body(discriminator="resource_type"), + Field(discriminator="resource_type"), ] -# READ -AnyResourceRead = Union[ # noqa: UP007 - tuple( - [ - rt.resource_model().read_model() - for rt in resource_types_mgr.get_all().values() - ] - ) -] -AnyResourceReadBody = Annotated[ - AnyResourceRead, +AnyResourceRead = Annotated[ + Union[ # noqa: UP007 + tuple( + [ + rt.resource_model().read_model() + for rt in resource_types_mgr.get_all().values() + ] + ) + ], Body(discriminator="resource_type"), + Field(discriminator="resource_type"), ] -# UPDATE -AnyResourceUpdate = Union[ # noqa: UP007 - tuple( - [ - rt.resource_model().update_model() - for rt in resource_types_mgr.get_all().values() - ] - ) -] -AnyResourceUpdateBody = Annotated[ - AnyResourceUpdate, +AnyResourceUpdate = Annotated[ + Union[ # noqa: UP007 + tuple( + [ + rt.resource_model().update_model() + for rt in resource_types_mgr.get_all().values() + ] + ) + ], Body(discriminator="resource_type"), -] - -# DOCUMENT -AnyResourceDocument = Union[ # noqa: UP007 - tuple( - [ - rt.resource_model().document_model() - for rt in resource_types_mgr.get_all().values() - ] - ) + Field(discriminator="resource_type"), ] -# ### create union type aliases for models of any content type model +# ### CREATE UNION TYPE ALIASES FOR MODELS OF ANY CONTENT TYPE MODEL -# CREATE -AnyContentCreate = Union[ # noqa: UP007 - tuple( - [ - rt.content_model().create_model() - for rt in resource_types_mgr.get_all().values() - ] - ) -] -AnyContentCreateBody = Annotated[ - AnyContentCreate, +AnyContentCreate = Annotated[ + Union[ # noqa: UP007 + tuple( + [ + rt.content_model().create_model() + for rt in resource_types_mgr.get_all().values() + ] + ) + ], Body(discriminator="resource_type"), + Field(discriminator="resource_type"), ] -# READ -AnyContentRead = Union[ # noqa: UP007 - tuple( - [ - rt.content_model().read_model() - for rt in resource_types_mgr.get_all().values() - ] - ) -] -AnyContentReadBody = Annotated[ - AnyContentRead, +AnyContentRead = Annotated[ + Union[ # noqa: UP007 + tuple( + [ + rt.content_model().read_model() + for rt in resource_types_mgr.get_all().values() + ] + ) + ], Body(discriminator="resource_type"), + Field(discriminator="resource_type"), ] -# UPDATE -AnyContentUpdate = Union[ # noqa: UP007 - tuple( - [ - rt.content_model().update_model() - for rt in resource_types_mgr.get_all().values() - ] - ) -] -AnyContentUpdateBody = Annotated[ - AnyContentUpdate, +AnyContentUpdate = Annotated[ + Union[ # noqa: UP007 + tuple( + [ + rt.content_model().update_model() + for rt in resource_types_mgr.get_all().values() + ] + ) + ], Body(discriminator="resource_type"), + Field(discriminator="resource_type"), ] -# DOCUMENT -AnyContentDocument = Union[ # noqa: UP007 - tuple( - [ - rt.content_model().document_model() - for rt in resource_types_mgr.get_all().values() - ] - ) +AnyContentDocument = Annotated[ + Union[ # noqa: UP007 + tuple( + [ + rt.content_model().document_model() + for rt in resource_types_mgr.get_all().values() + ] + ) + ], + Body(discriminator="resource_type"), + Field(discriminator="resource_type"), ] -# ANY RESOURCE SEARCH QUERY + +# ### CREATE UNION TYPE ALIASES FOR MODELS OF RESOURCE TYPE-SPECIFIC SEARCH QUERIES + AnyResourceSearchQuery = Annotated[ Union[ # noqa: UP007 tuple([rt.search_query_model() for rt in resource_types_mgr.get_all().values()]) ], + Body(discriminator="resource_type"), Field(discriminator="resource_type"), ] diff --git a/Tekst-API/tekst/routers/browse.py b/Tekst-API/tekst/routers/browse.py index 3761988f..507784c6 100644 --- a/Tekst-API/tekst/routers/browse.py +++ b/Tekst-API/tekst/routers/browse.py @@ -15,7 +15,7 @@ from tekst.models.resource import ( ResourceBaseDocument, ) -from tekst.resources import AnyContentReadBody +from tekst.resources import AnyContentRead # initialize content router @@ -27,7 +27,7 @@ @router.get( "/content-siblings", - response_model=list[AnyContentReadBody], + response_model=list[AnyContentRead], status_code=status.HTTP_200_OK, responses=errors.responses( [ diff --git a/Tekst-API/tekst/routers/contents.py b/Tekst-API/tekst/routers/contents.py index 225c4a77..e8b4a3de 100644 --- a/Tekst-API/tekst/routers/contents.py +++ b/Tekst-API/tekst/routers/contents.py @@ -9,10 +9,10 @@ from tekst.models.content import ContentBaseDocument from tekst.models.resource import ResourceBaseDocument from tekst.resources import ( - AnyContentCreateBody, + AnyContentCreate, AnyContentDocument, - AnyContentReadBody, - AnyContentUpdateBody, + AnyContentRead, + AnyContentUpdate, resource_types_mgr, ) from tekst.search import set_index_ood @@ -27,7 +27,7 @@ @router.post( "", - response_model=AnyContentReadBody, + response_model=AnyContentRead, status_code=status.HTTP_201_CREATED, responses=errors.responses( [ @@ -37,7 +37,7 @@ ), ) async def create_content( - content: AnyContentCreateBody, + content: AnyContentCreate, user: UserDep, ) -> AnyContentDocument: # check if the resource this content belongs to is writable by user @@ -73,7 +73,7 @@ async def create_content( @router.get( "/{id}", - response_model=AnyContentReadBody, + response_model=AnyContentRead, status_code=status.HTTP_200_OK, responses=errors.responses( [ @@ -101,7 +101,7 @@ async def get_content( @router.patch( "/{id}", - response_model=AnyContentReadBody, + response_model=AnyContentRead, status_code=status.HTTP_200_OK, responses=errors.responses( [ @@ -113,7 +113,7 @@ async def get_content( ) async def update_content( content_id: Annotated[PydanticObjectId, Path(alias="id")], - updates: AnyContentUpdateBody, + updates: AnyContentUpdate, user: UserDep, ) -> AnyContentDocument: content_doc = await ContentBaseDocument.get(content_id, with_children=True) @@ -176,7 +176,7 @@ async def delete_content( @router.get( "", - response_model=list[AnyContentReadBody], + response_model=list[AnyContentRead], status_code=status.HTTP_200_OK, ) async def find_contents( diff --git a/Tekst-API/tekst/routers/resources.py b/Tekst-API/tekst/routers/resources.py index 8be0f51b..b252c0b1 100644 --- a/Tekst-API/tekst/routers/resources.py +++ b/Tekst-API/tekst/routers/resources.py @@ -38,10 +38,9 @@ from tekst.models.text import TextDocument from tekst.models.user import UserDocument, UserRead, UserReadPublic from tekst.resources import ( - AnyResourceCreateBody, + AnyResourceCreate, AnyResourceRead, - AnyResourceReadBody, - AnyResourceUpdateBody, + AnyResourceUpdate, call_resource_maintenance_hooks, get_resource_template_readme, resource_types_mgr, @@ -134,7 +133,7 @@ async def trigger_resources_maintenance( @router.post( "", - response_model=AnyResourceReadBody, + response_model=AnyResourceRead, status_code=status.HTTP_201_CREATED, responses=errors.responses( [ @@ -145,7 +144,7 @@ async def trigger_resources_maintenance( ), ) async def create_resource( - resource: AnyResourceCreateBody, user: UserDep, cfg: ConfigDep + resource: AnyResourceCreate, user: UserDep, cfg: ConfigDep ) -> AnyResourceRead: # check user resources limit if ( @@ -182,7 +181,7 @@ async def create_resource( @router.post( "/{id}/version", - response_model=AnyResourceReadBody, + response_model=AnyResourceRead, status_code=status.HTTP_201_CREATED, responses=errors.responses( [ @@ -261,7 +260,7 @@ async def create_resource_version( @router.patch( "/{id}", - response_model=AnyResourceReadBody, + response_model=AnyResourceRead, status_code=status.HTTP_200_OK, responses=errors.responses( [ @@ -272,7 +271,7 @@ async def create_resource_version( ) async def update_resource( resource_id: Annotated[PydanticObjectId, Path(alias="id")], - updates: AnyResourceUpdateBody, + updates: AnyResourceUpdate, user: UserDep, ) -> AnyResourceRead: resource_doc = await ResourceBaseDocument.find_one( @@ -302,7 +301,7 @@ async def update_resource( @router.get( "", - response_model=list[AnyResourceReadBody], + response_model=list[AnyResourceRead], status_code=status.HTTP_200_OK, ) async def find_resources( @@ -356,7 +355,7 @@ async def find_resources( @router.get( "/{id}", status_code=status.HTTP_200_OK, - response_model=AnyResourceReadBody, + response_model=AnyResourceRead, responses=errors.responses( [ errors.E_404_RESOURCE_NOT_FOUND, @@ -441,7 +440,7 @@ async def delete_resource( @router.post( "/{id}/transfer", - response_model=AnyResourceReadBody, + response_model=AnyResourceRead, status_code=status.HTTP_200_OK, responses=errors.responses( [ @@ -508,7 +507,7 @@ async def transfer_resource( @router.post( "/{id}/propose", - response_model=AnyResourceReadBody, + response_model=AnyResourceRead, status_code=status.HTTP_200_OK, responses=errors.responses( [ @@ -551,7 +550,7 @@ async def propose_resource( @router.post( "/{id}/unpropose", - response_model=AnyResourceReadBody, + response_model=AnyResourceRead, status_code=status.HTTP_200_OK, responses=errors.responses( [ @@ -580,7 +579,7 @@ async def unpropose_resource( @router.post( "/{id}/publish", - response_model=AnyResourceReadBody, + response_model=AnyResourceRead, status_code=status.HTTP_200_OK, responses=errors.responses( [ @@ -624,7 +623,7 @@ async def publish_resource( @router.post( "/{id}/unpublish", - response_model=AnyResourceReadBody, + response_model=AnyResourceRead, status_code=status.HTTP_200_OK, responses=errors.responses( [