Skip to content

Commit

Permalink
♻️ web-server: preparation of trash plugin ⚠️ (#7018)
Browse files Browse the repository at this point in the history
  • Loading branch information
pcrespov authored Jan 16, 2025
1 parent 79d19bf commit a9c4d54
Show file tree
Hide file tree
Showing 94 changed files with 900 additions and 561 deletions.
2 changes: 1 addition & 1 deletion .env-devel
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,6 @@ LOGIN_ACCOUNT_DELETION_RETENTION_DAYS=31
LOGIN_REGISTRATION_CONFIRMATION_REQUIRED=0
LOGIN_REGISTRATION_INVITATION_REQUIRED=0
PROJECTS_INACTIVITY_INTERVAL=00:00:20
PROJECTS_TRASH_RETENTION_DAYS=7
PROJECTS_MAX_COPY_SIZE_BYTES=30Gib
PROJECTS_MAX_NUM_RUNNING_DYNAMIC_NODES=5
REST_SWAGGER_API_DOC_ENABLED=1
Expand All @@ -353,6 +352,7 @@ TRACING_OPENTELEMETRY_COLLECTOR_EXPORTER_ENDPOINT=http://jaeger:4318
TRACING_OPENTELEMETRY_COLLECTOR_PORT=4318
TRACING_OPENTELEMETRY_COLLECTOR_SAMPLING_PERCENTAGE=100
TRAEFIK_SIMCORE_ZONE=internal_simcore_stack
TRASH_RETENTION_DAYS=7
TWILIO_ACCOUNT_SID=DUMMY
TWILIO_AUTH_TOKEN=DUMMY
TWILIO_COUNTRY_CODES_W_ALPHANUMERIC_SID_SUPPORT=["41"]
Expand Down
12 changes: 6 additions & 6 deletions api/specs/web-server/_folders.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@
from models_library.generics import Envelope
from models_library.rest_error import EnvelopedError
from simcore_service_webserver._meta import API_VTAG
from simcore_service_webserver.folders._exceptions_handlers import _TO_HTTP_ERROR_MAP
from simcore_service_webserver.folders._models import (
from simcore_service_webserver.folders._common.exceptions_handlers import (
_TO_HTTP_ERROR_MAP,
)
from simcore_service_webserver.folders._common.models import (
FolderSearchQueryParams,
FoldersListQueryParams,
FoldersPathParams,
)
from simcore_service_webserver.folders._workspaces_handlers import (
_FolderWorkspacesPathParams,
FolderWorkspacesPathParams,
)

router = APIRouter(
Expand Down Expand Up @@ -109,6 +109,6 @@ async def delete_folder(
tags=["workspaces"],
)
async def move_folder_to_workspace(
_path: Annotated[_FolderWorkspacesPathParams, Depends()],
_path: Annotated[FolderWorkspacesPathParams, Depends()],
):
...
6 changes: 3 additions & 3 deletions api/specs/web-server/_trash.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@
from fastapi import APIRouter, Depends, status
from models_library.trash import RemoveQueryParams
from simcore_service_webserver._meta import API_VTAG
from simcore_service_webserver.folders._models import (
from simcore_service_webserver.folders._common.models import (
FoldersPathParams,
FolderTrashQueryParams,
)
from simcore_service_webserver.projects._trash_handlers import ProjectPathParams
from simcore_service_webserver.workspaces._models import (
from simcore_service_webserver.projects._trash_rest import ProjectPathParams
from simcore_service_webserver.workspaces._common.models import (
WorkspacesPathParams,
WorkspaceTrashQueryParams,
)
Expand Down
8 changes: 5 additions & 3 deletions api/specs/web-server/_workspaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@
from models_library.generics import Envelope
from models_library.rest_error import EnvelopedError
from simcore_service_webserver._meta import API_VTAG
from simcore_service_webserver.folders._exceptions_handlers import _TO_HTTP_ERROR_MAP
from simcore_service_webserver.workspaces._groups_api import WorkspaceGroupGet
from simcore_service_webserver.workspaces._models import (
from simcore_service_webserver.folders._common.exceptions_handlers import (
_TO_HTTP_ERROR_MAP,
)
from simcore_service_webserver.workspaces._common.models import (
WorkspacesGroupsBodyParams,
WorkspacesGroupsPathParams,
WorkspacesListQueryParams,
WorkspacesPathParams,
)
from simcore_service_webserver.workspaces._groups_service import WorkspaceGroupGet

router = APIRouter(
prefix=f"/{API_VTAG}",
Expand Down
4 changes: 4 additions & 0 deletions packages/common-library/src/common_library/exclude.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ class UnSet:
UnSet.VALUE = UnSet()


def is_unset(v: Any) -> bool:
return isinstance(v, UnSet)


def as_dict_exclude_unset(**params) -> dict[str, Any]:
return {k: v for k, v in params.items() if not isinstance(v, UnSet)}

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class GroupGet(OutputSchema):
] = DEFAULT_FACTORY

@classmethod
def from_model(cls, group: Group, access_rights: AccessRightsDict) -> Self:
def from_domain_model(cls, group: Group, access_rights: AccessRightsDict) -> Self:
# Adapts these domain models into this schema
return cls.model_validate(
{
Expand Down Expand Up @@ -151,7 +151,7 @@ class GroupCreate(InputSchema):
description: str
thumbnail: AnyUrl | None = None

def to_model(self) -> StandardGroupCreate:
def to_domain_model(self) -> StandardGroupCreate:
data = remap_keys(
self.model_dump(
mode="json",
Expand All @@ -169,7 +169,7 @@ class GroupUpdate(InputSchema):
description: str | None = None
thumbnail: AnyUrl | None = None

def to_model(self) -> StandardGroupUpdate:
def to_domain_model(self) -> StandardGroupUpdate:
data = remap_keys(
self.model_dump(
mode="json",
Expand Down Expand Up @@ -230,7 +230,7 @@ class MyGroupsGet(OutputSchema):
)

@classmethod
def from_model(
def from_domain_model(
cls,
groups_by_type: GroupsByTypeTuple,
my_product_group: tuple[Group, AccessRightsDict] | None,
Expand All @@ -239,10 +239,12 @@ def from_model(
assert groups_by_type.everyone # nosec

return cls(
me=GroupGet.from_model(*groups_by_type.primary),
organizations=[GroupGet.from_model(*gi) for gi in groups_by_type.standard],
all=GroupGet.from_model(*groups_by_type.everyone),
product=GroupGet.from_model(*my_product_group)
me=GroupGet.from_domain_model(*groups_by_type.primary),
organizations=[
GroupGet.from_domain_model(*gi) for gi in groups_by_type.standard
],
all=GroupGet.from_domain_model(*groups_by_type.everyone),
product=GroupGet.from_domain_model(*my_product_group)
if my_product_group
else None,
)
Expand Down Expand Up @@ -320,7 +322,7 @@ class GroupUserGet(OutputSchemaWithoutCamelCase):
)

@classmethod
def from_model(cls, user: GroupMember) -> Self:
def from_domain_model(cls, user: GroupMember) -> Self:
return cls.model_validate(
{
"id": user.id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
"""

from datetime import datetime
from typing import Annotated, Any, Literal, TypeAlias
from typing import Annotated, Any, Literal, Self, TypeAlias

from common_library.dict_tools import remap_keys
from models_library.folders import FolderID
from models_library.utils._original_fastapi_encoders import jsonable_encoder
from models_library.workspaces import WorkspaceID
Expand Down Expand Up @@ -95,6 +96,7 @@ class ProjectGet(OutputSchema):
permalink: ProjectPermalink | None = None
workspace_id: WorkspaceID | None
folder_id: FolderID | None

trashed_at: datetime | None

_empty_description = field_validator("description", mode="before")(
Expand All @@ -103,6 +105,15 @@ class ProjectGet(OutputSchema):

model_config = ConfigDict(frozen=False)

@classmethod
def from_domain_model(cls, project_data: dict[str, Any]) -> Self:
return cls.model_validate(
remap_keys(
project_data,
rename={"trashed": "trashed_at"},
)
)


TaskProjectGet: TypeAlias = TaskGet

Expand Down Expand Up @@ -160,6 +171,9 @@ class ProjectPatch(InputSchema):
] = Field(default=None)
quality: dict[str, Any] | None = Field(default=None)

def to_domain_model(self) -> dict[str, Any]:
return self.model_dump(exclude_unset=True, by_alias=False)


__all__: tuple[str, ...] = (
"EmptyModel",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def _to_upper_string(cls, v):
return v

@classmethod
def from_model(
def from_domain_model(
cls,
my_profile: MyProfile,
my_groups_by_type: GroupsByTypeTuple,
Expand All @@ -133,7 +133,7 @@ def from_model(
)
return cls(
**data,
groups=MyGroupsGet.from_model(my_groups_by_type, my_product_group),
groups=MyGroupsGet.from_domain_model(my_groups_by_type, my_product_group),
preferences=my_preferences,
)

Expand Down Expand Up @@ -221,7 +221,7 @@ class UserGet(OutputSchema):
email: EmailStr | None = None

@classmethod
def from_model(cls, data):
def from_domain_model(cls, data):
return cls.model_validate(data, from_attributes=True)


Expand Down Expand Up @@ -293,7 +293,7 @@ class MyTokenCreate(InputSchemaWithoutCamelCase):
token_key: IDStr
token_secret: IDStr

def to_model(self) -> UserThirdPartyToken:
def to_domain_model(self) -> UserThirdPartyToken:
return UserThirdPartyToken(
service=self.service,
token_key=self.token_key,
Expand All @@ -309,7 +309,7 @@ class MyTokenGet(OutputSchemaWithoutCamelCase):
] = None

@classmethod
def from_model(cls, token: UserThirdPartyToken) -> Self:
def from_domain_model(cls, token: UserThirdPartyToken) -> Self:
return cls(
service=token.service, # type: ignore[arg-type]
token_key=token.token_key, # type: ignore[arg-type]
Expand All @@ -327,5 +327,5 @@ class MyPermissionGet(OutputSchema):
allowed: bool

@classmethod
def from_model(cls, permission: UserPermission) -> Self:
def from_domain_model(cls, permission: UserPermission) -> Self:
return cls(name=permission.name, allowed=permission.allowed)
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from datetime import datetime
from typing import NamedTuple
from typing import Self

from models_library.basic_types import IDStr
from models_library.groups import GroupID
from models_library.workspaces import WorkspaceID
from pydantic import ConfigDict, PositiveInt
from pydantic import ConfigDict

from ..access_rights import AccessRights
from ..basic_types import IDStr
from ..groups import GroupID
from ..users import UserID
from ..workspaces import UserWorkspaceWithAccessRights, WorkspaceID
from ._base import InputSchema, OutputSchema


Expand All @@ -23,10 +23,20 @@ class WorkspaceGet(OutputSchema):
my_access_rights: AccessRights
access_rights: dict[GroupID, AccessRights]


class WorkspaceGetPage(NamedTuple):
items: list[WorkspaceGet]
total: PositiveInt
@classmethod
def from_domain_model(cls, wks: UserWorkspaceWithAccessRights) -> Self:
return cls(
workspace_id=wks.workspace_id,
name=wks.name,
description=wks.description,
thumbnail=wks.thumbnail,
created_at=wks.created,
modified_at=wks.modified,
trashed_at=wks.trashed,
trashed_by=wks.trashed_by if wks.trashed else None,
my_access_rights=wks.my_access_rights,
access_rights=wks.access_rights,
)


class WorkspaceCreateBodyParams(InputSchema):
Expand Down
2 changes: 1 addition & 1 deletion packages/models-library/src/models_library/folders.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class FolderDB(BaseModel):
...,
description="Timestamp of last modification",
)
trashed_at: datetime | None = Field(
trashed: datetime | None = Field(
...,
)

Expand Down
13 changes: 7 additions & 6 deletions packages/models-library/src/models_library/projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from .projects_nodes_io import NodeIDStr
from .projects_state import ProjectState
from .projects_ui import StudyUI
from .users import UserID
from .utils.common_validators import (
empty_str_to_none_pre_validator,
none_to_empty_str_pre_validator,
Expand Down Expand Up @@ -182,10 +183,10 @@ class Project(BaseProjectModel):
alias="folderId",
)

trashed_at: datetime | None = Field(
default=None,
alias="trashedAt",
)
trashed_explicitly: bool = Field(default=False, alias="trashedExplicitly")
trashed: datetime | None = None
trashed_by: Annotated[UserID | None, Field(alias="trashedBy")] = None
trashed_explicitly: Annotated[bool, Field(alias="trashedExplicitly")] = False

model_config = ConfigDict(title="osparc-simcore project", extra="forbid")
model_config = ConfigDict(
extra="forbid",
)
Loading

0 comments on commit a9c4d54

Please sign in to comment.