Skip to content
Merged
Show file tree
Hide file tree
Changes from 48 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
99104eb
exc handlers
pcrespov Nov 8, 2024
4b0071d
exc handlers in workspaces
pcrespov Nov 8, 2024
3586430
separates models
pcrespov Nov 8, 2024
bf3b67c
updates oas builder
pcrespov Nov 8, 2024
4886caa
updates OAS
pcrespov Nov 8, 2024
39b8d4b
services/webserver api version: 0.45.0 → 0.46.0
pcrespov Nov 8, 2024
f94ab75
drafts trash section
pcrespov Nov 8, 2024
cc35618
updates oas
pcrespov Nov 12, 2024
0e5ddb0
minor
pcrespov Nov 12, 2024
b22adaf
adds db
pcrespov Nov 12, 2024
3e788bd
db models
pcrespov Nov 12, 2024
c4310b9
migration
pcrespov Nov 12, 2024
44d56be
common model
pcrespov Nov 12, 2024
8ee93da
cleanup
pcrespov Nov 12, 2024
e0a3113
models
pcrespov Nov 14, 2024
bac1ac6
workspaces query
pcrespov Nov 14, 2024
33cbd9d
rest ordering
pcrespov Nov 14, 2024
6db1ea7
base rest
pcrespov Nov 14, 2024
21aa58d
cleanup api
pcrespov Nov 18, 2024
716fe6f
openapi
pcrespov Nov 18, 2024
7e42e9f
updates oas
pcrespov Nov 18, 2024
be372fb
updates OAS
pcrespov Nov 18, 2024
141c759
updates migration
pcrespov Nov 18, 2024
8e65a1a
folders
pcrespov Nov 20, 2024
6431182
workspaces query
pcrespov Nov 20, 2024
2070135
workspaces query
pcrespov Nov 20, 2024
1cca757
clenup
pcrespov Nov 20, 2024
4484c54
implements WorkspaceGet w/ trash attributes
pcrespov Nov 20, 2024
cca0c1a
oas
pcrespov Nov 20, 2024
3453127
cleanup
pcrespov Nov 20, 2024
f040534
cleanup test
pcrespov Nov 20, 2024
998966c
cleanup tests
pcrespov Nov 20, 2024
66ef145
workspaces new list
pcrespov Nov 20, 2024
61d86e9
drafted tests
pcrespov Nov 20, 2024
93edb80
workspace update
pcrespov Nov 20, 2024
eba0877
adds trash empty workspace
pcrespov Nov 20, 2024
f4b47ac
fixes tests
pcrespov Nov 20, 2024
fee23e5
fixes mypy
pcrespov Nov 20, 2024
be91874
update OAS
pcrespov Nov 20, 2024
4823061
sonar
pcrespov Nov 20, 2024
a2a466c
fixes migration
pcrespov Nov 20, 2024
2a60b99
undos
pcrespov Nov 20, 2024
dbba633
readme
pcrespov Nov 20, 2024
af843e5
udno
pcrespov Nov 20, 2024
018ad58
path
pcrespov Nov 20, 2024
5d30429
cleanup
pcrespov Nov 20, 2024
567075e
rm badges
pcrespov Nov 20, 2024
75964f9
fixes testss
pcrespov Nov 20, 2024
5194888
Merge branch 'master' into is468/trash-api-workspaces
pcrespov Nov 21, 2024
b20528b
minor
pcrespov Nov 21, 2024
737f7ae
updates pg
pcrespov Nov 21, 2024
966980a
minor
pcrespov Nov 21, 2024
ff9777a
Merge branch 'master' into is468/trash-api-workspaces
pcrespov Nov 23, 2024
b373a4b
cleanup
pcrespov Nov 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions api/specs/web-server/_folders.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
from _common import as_query
from fastapi import APIRouter, Depends, status
from models_library.api_schemas_webserver.folders_v2 import (
CreateFolderBodyParams,
FolderCreateBodyParams,
FolderGet,
PutFolderBodyParams,
FolderReplaceBodyParams,
)
from models_library.generics import Envelope
from simcore_service_webserver._meta import API_VTAG
Expand All @@ -38,7 +38,7 @@
status_code=status.HTTP_201_CREATED,
)
async def create_folder(
_body: CreateFolderBodyParams,
_body: FolderCreateBodyParams,
):
...

Expand Down Expand Up @@ -79,7 +79,7 @@ async def get_folder(
)
async def replace_folder(
_path: Annotated[FoldersPathParams, Depends()],
_body: PutFolderBodyParams,
_body: FolderReplaceBodyParams,
):
...

Expand Down
45 changes: 40 additions & 5 deletions api/specs/web-server/_trash.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@
from typing import Annotated

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 (
FoldersPathParams,
RemoveQueryParams,
FolderTrashQueryParams,
)
from simcore_service_webserver.projects._trash_handlers import ProjectPathParams
from simcore_service_webserver.projects._trash_handlers import (
RemoveQueryParams as RemoveQueryParams_duplicated,
from simcore_service_webserver.workspaces._models import (
WorkspacesPathParams,
WorkspaceTrashQueryParams,
)

router = APIRouter(
Expand Down Expand Up @@ -75,14 +77,14 @@ def untrash_project(
responses={
status.HTTP_404_NOT_FOUND: {"description": "Not such a folder"},
status.HTTP_409_CONFLICT: {
"description": "One or more projects is in use and cannot be trashed"
"description": "One or more projects in the folder are in use and cannot be trashed"
},
status.HTTP_503_SERVICE_UNAVAILABLE: {"description": "Trash service error"},
},
)
def trash_folder(
_path: Annotated[FoldersPathParams, Depends()],
_query: Annotated[RemoveQueryParams_duplicated, Depends()],
_query: Annotated[FolderTrashQueryParams, Depends()],
):
...

Expand All @@ -96,3 +98,36 @@ def untrash_folder(
_path: Annotated[FoldersPathParams, Depends()],
):
...


_extra_tags = ["workspaces"]


@router.post(
"/workspaces/{workspace_id}:trash",
tags=_extra_tags,
status_code=status.HTTP_204_NO_CONTENT,
responses={
status.HTTP_404_NOT_FOUND: {"description": "Not such a workspace"},
status.HTTP_409_CONFLICT: {
"description": "One or more projects in the workspace are in use and cannot be trashed"
},
status.HTTP_503_SERVICE_UNAVAILABLE: {"description": "Trash service error"},
},
)
def trash_workspace(
_path: Annotated[WorkspacesPathParams, Depends()],
_query: Annotated[WorkspaceTrashQueryParams, Depends()],
):
...


@router.post(
"/workspaces/{workspace_id}:untrash",
tags=_extra_tags,
status_code=status.HTTP_204_NO_CONTENT,
)
def untrash_workspace(
_path: Annotated[WorkspacesPathParams, Depends()],
):
...
52 changes: 32 additions & 20 deletions api/specs/web-server/_workspaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,24 @@
# pylint: disable=unused-variable
# pylint: disable=too-many-arguments


from enum import Enum
from typing import Annotated

from _common import as_query
from fastapi import APIRouter, Depends, status
from models_library.api_schemas_webserver.workspaces import (
CreateWorkspaceBodyParams,
PutWorkspaceBodyParams,
WorkspaceCreateBodyParams,
WorkspaceGet,
WorkspaceReplaceBodyParams,
)
from models_library.generics import Envelope
from models_library.workspaces import WorkspaceID
from simcore_service_webserver._meta import API_VTAG
from simcore_service_webserver.workspaces._groups_api import WorkspaceGroupGet
from simcore_service_webserver.workspaces._groups_handlers import (
_WorkspacesGroupsBodyParams,
_WorkspacesGroupsPathParams,
from simcore_service_webserver.workspaces._models import (
WorkspacesGroupsBodyParams,
WorkspacesGroupsPathParams,
WorkspacesListQueryParams,
WorkspacesPathParams,
)

router = APIRouter(
Expand All @@ -32,47 +33,56 @@
],
)

### Workspaces


@router.post(
"/workspaces",
response_model=Envelope[WorkspaceGet],
status_code=status.HTTP_201_CREATED,
)
async def create_workspace(_body: CreateWorkspaceBodyParams):
async def create_workspace(
_body: WorkspaceCreateBodyParams,
):
...


@router.get(
"/workspaces",
response_model=Envelope[list[WorkspaceGet]],
)
async def list_workspaces():
async def list_workspaces(
_query: Annotated[as_query(WorkspacesListQueryParams), Depends()],
):
...


@router.get(
"/workspaces/{workspace_id}",
response_model=Envelope[WorkspaceGet],
)
async def get_workspace(workspace_id: WorkspaceID):
async def get_workspace(
_path: Annotated[WorkspacesPathParams, Depends()],
):
...


@router.put(
"/workspaces/{workspace_id}",
response_model=Envelope[WorkspaceGet],
)
async def replace_workspace(workspace_id: WorkspaceID, _body: PutWorkspaceBodyParams):
async def replace_workspace(
_path: Annotated[WorkspacesPathParams, Depends()],
_body: WorkspaceReplaceBodyParams,
):
...


@router.delete(
"/workspaces/{workspace_id}",
status_code=status.HTTP_204_NO_CONTENT,
)
async def delete_workspace(workspace_id: WorkspaceID):
async def delete_workspace(
_path: Annotated[WorkspacesPathParams, Depends()],
):
...


Expand All @@ -87,8 +97,8 @@ async def delete_workspace(workspace_id: WorkspaceID):
tags=_extra_tags,
)
async def create_workspace_group(
_path_parms: Annotated[_WorkspacesGroupsPathParams, Depends()],
_body: _WorkspacesGroupsBodyParams,
_path: Annotated[WorkspacesGroupsPathParams, Depends()],
_body: WorkspacesGroupsBodyParams,
):
...

Expand All @@ -98,7 +108,9 @@ async def create_workspace_group(
response_model=Envelope[list[WorkspaceGroupGet]],
tags=_extra_tags,
)
async def list_workspace_groups(workspace_id: WorkspaceID):
async def list_workspace_groups(
_path: Annotated[WorkspacesPathParams, Depends()],
):
...


Expand All @@ -108,8 +120,8 @@ async def list_workspace_groups(workspace_id: WorkspaceID):
tags=_extra_tags,
)
async def replace_workspace_group(
_path_parms: Annotated[_WorkspacesGroupsPathParams, Depends()],
_body: _WorkspacesGroupsBodyParams,
_path: Annotated[WorkspacesGroupsPathParams, Depends()],
_body: WorkspacesGroupsBodyParams,
):
...

Expand All @@ -120,6 +132,6 @@ async def replace_workspace_group(
tags=_extra_tags,
)
async def delete_workspace_group(
_path_parms: Annotated[_WorkspacesGroupsPathParams, Depends()]
_path: Annotated[WorkspacesGroupsPathParams, Depends()],
):
...
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class FolderGetPage(NamedTuple):
total: PositiveInt


class CreateFolderBodyParams(InputSchema):
class FolderCreateBodyParams(InputSchema):
name: IDStr
parent_folder_id: FolderID | None = None
workspace_id: WorkspaceID | None = None
Expand All @@ -46,7 +46,7 @@ class Config:
)(null_or_none_str_to_none_validator)


class PutFolderBodyParams(InputSchema):
class FolderReplaceBodyParams(InputSchema):
name: IDStr
parent_folder_id: FolderID | None

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from pydantic import Extra, PositiveInt

from ..access_rights import AccessRights
from ..users import UserID
from ._base import InputSchema, OutputSchema


Expand All @@ -17,6 +18,8 @@ class WorkspaceGet(OutputSchema):
thumbnail: str | None
created_at: datetime
modified_at: datetime
trashed_at: datetime | None
trashed_by: UserID | None
my_access_rights: AccessRights
access_rights: dict[GroupID, AccessRights]

Expand All @@ -26,7 +29,7 @@ class WorkspaceGetPage(NamedTuple):
total: PositiveInt


class CreateWorkspaceBodyParams(InputSchema):
class WorkspaceCreateBodyParams(InputSchema):
name: str
description: str | None = None
thumbnail: str | None = None
Expand All @@ -35,7 +38,7 @@ class Config:
extra = Extra.forbid


class PutWorkspaceBodyParams(InputSchema):
class WorkspaceReplaceBodyParams(InputSchema):
name: IDStr
description: str | None = None
thumbnail: str | None = None
Expand Down
7 changes: 7 additions & 0 deletions packages/models-library/src/models_library/trash.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from pydantic import BaseModel, Field


class RemoveQueryParams(BaseModel):
force: bool = Field(
default=False, description="Force removal (even if resource is active)"
)
22 changes: 15 additions & 7 deletions packages/models-library/src/models_library/workspaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from pydantic import BaseModel, Field, PositiveInt, validator

from .access_rights import AccessRights
from .users import GroupID
from .users import GroupID, UserID
from .utils.enums import StrAutoEnum

WorkspaceID: TypeAlias = PositiveInt
Expand All @@ -26,13 +26,11 @@ class WorkspaceQuery(BaseModel):
def validate_workspace_id(cls, value, values):
scope = values.get("workspace_scope")
if scope == WorkspaceScope.SHARED and value is None:
raise ValueError(
"workspace_id must be provided when workspace_scope is SHARED."
)
msg = f"workspace_id must be provided when workspace_scope is SHARED. Got {scope=}, {value=}"
raise ValueError(msg)
if scope != WorkspaceScope.SHARED and value is not None:
raise ValueError(
"workspace_id should be None when workspace_scope is not SHARED."
)
msg = f"workspace_id should be None when workspace_scope is not SHARED. Got {scope=}, {value=}"
raise ValueError(msg)
return value


Expand All @@ -58,6 +56,8 @@ class WorkspaceDB(BaseModel):
...,
description="Timestamp of last modification",
)
trashed: datetime | None
trashed_by: UserID | None

class Config:
orm_mode = True
Expand All @@ -69,3 +69,11 @@ class UserWorkspaceAccessRightsDB(WorkspaceDB):

class Config:
orm_mode = True


class WorkspaceUpdateDB(BaseModel):
name: str | None = None
description: str | None = None
thumbnail: str | None = None
trashed: datetime | None = None
trashed_by: UserID | None = None
Loading
Loading