Skip to content

Commit 299c1ac

Browse files
authored
✨ Trash folders (#6642)
1 parent 72766b4 commit 299c1ac

File tree

39 files changed

+1421
-364
lines changed

39 files changed

+1421
-364
lines changed

api/specs/web-server/_folders.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from models_library.workspaces import WorkspaceID
2222
from pydantic import Json
2323
from simcore_service_webserver._meta import API_VTAG
24-
from simcore_service_webserver.folders._folders_handlers import FoldersPathParams
24+
from simcore_service_webserver.folders._models import FolderFilters, FoldersPathParams
2525

2626
router = APIRouter(
2727
prefix=f"/{API_VTAG}",
@@ -30,8 +30,6 @@
3030
],
3131
)
3232

33-
### Folders
34-
3533

3634
@router.post(
3735
"/folders",
@@ -57,6 +55,10 @@ async def list_folders(
5755
example='{"field": "name", "direction": "desc"}',
5856
),
5957
] = '{"field": "modified_at", "direction": "desc"}',
58+
filters: Annotated[
59+
Json | None,
60+
Query(description=FolderFilters.schema_json(indent=1)),
61+
] = None,
6062
):
6163
...
6264

api/specs/web-server/_projects_crud.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
from simcore_service_webserver.projects._common_models import ProjectPathParams
3333
from simcore_service_webserver.projects._crud_handlers import ProjectCreateParams
3434
from simcore_service_webserver.projects._crud_handlers_models import (
35+
ProjectFilters,
3536
ProjectListFullSearchParams,
3637
ProjectListParams,
3738
)
@@ -83,7 +84,10 @@ async def list_projects(
8384
example='{"field": "last_change_date", "direction": "desc"}',
8485
),
8586
] = '{"field": "last_change_date", "direction": "desc"}',
86-
filters: Annotated[Json | None, Query()] = None,
87+
filters: Annotated[
88+
Json | None,
89+
Query(description=ProjectFilters.schema_json(indent=1)),
90+
] = None,
8791
):
8892
...
8993

api/specs/web-server/_trash.py

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,14 @@
99

1010
from fastapi import APIRouter, Depends, status
1111
from simcore_service_webserver._meta import API_VTAG
12-
from simcore_service_webserver.projects._trash_handlers import (
13-
ProjectPathParams,
12+
from simcore_service_webserver.folders._models import (
13+
FoldersPathParams,
1414
RemoveQueryParams,
1515
)
16+
from simcore_service_webserver.projects._trash_handlers import ProjectPathParams
17+
from simcore_service_webserver.projects._trash_handlers import (
18+
RemoveQueryParams as RemoveQueryParams_duplicated,
19+
)
1620

1721
router = APIRouter(
1822
prefix=f"/{API_VTAG}",
@@ -59,3 +63,36 @@ def untrash_project(
5963
_p: Annotated[ProjectPathParams, Depends()],
6064
):
6165
...
66+
67+
68+
_extra_tags = ["folders"]
69+
70+
71+
@router.post(
72+
"/folders/{folder_id}:trash",
73+
tags=_extra_tags,
74+
status_code=status.HTTP_204_NO_CONTENT,
75+
responses={
76+
status.HTTP_404_NOT_FOUND: {"description": "Not such a folder"},
77+
status.HTTP_409_CONFLICT: {
78+
"description": "One or more projects is in use and cannot be trashed"
79+
},
80+
status.HTTP_503_SERVICE_UNAVAILABLE: {"description": "Trash service error"},
81+
},
82+
)
83+
def trash_folder(
84+
_p: Annotated[FoldersPathParams, Depends()],
85+
_q: Annotated[RemoveQueryParams_duplicated, Depends()],
86+
):
87+
...
88+
89+
90+
@router.post(
91+
"/folders/{folder_id}:untrash",
92+
tags=_extra_tags,
93+
status_code=status.HTTP_204_NO_CONTENT,
94+
)
95+
def untrash_folder(
96+
_p: Annotated[FoldersPathParams, Depends()],
97+
):
98+
...

packages/models-library/src/models_library/api_schemas_webserver/folders.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class FolderGet(OutputSchema):
1818
description: str
1919
created_at: datetime
2020
modified_at: datetime
21+
trashed_at: datetime | None
2122
owner: GroupID
2223
my_access_rights: AccessRights
2324
access_rights: dict[GroupID, AccessRights]

packages/models-library/src/models_library/api_schemas_webserver/folders_v2.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class FolderGet(OutputSchema):
1818
name: str
1919
created_at: datetime
2020
modified_at: datetime
21+
trashed_at: datetime | None
2122
owner: GroupID
2223
workspace_id: WorkspaceID | None
2324
my_access_rights: AccessRights

packages/models-library/src/models_library/folders.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ class FolderDB(BaseModel):
2929
...,
3030
description="Timestamp of last modification",
3131
)
32+
trashed_at: datetime | None = Field(
33+
...,
34+
)
35+
3236
user_id: UserID | None
3337
workspace_id: WorkspaceID | None
3438

packages/models-library/src/models_library/projects.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ class Project(BaseProjectModel):
190190
default=None,
191191
alias="trashedAt",
192192
)
193+
trashed_explicitly: bool = Field(default=False, alias="trashedExplicitly")
193194

194195
class Config:
195196
description = "Document that stores metadata, pipeline and UI setup of a study"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
"""project and folder trash columns
2+
3+
Revision ID: 5ad02358751a
4+
Revises: fce5d231e16d
5+
Create Date: 2024-11-07 17:14:01.094583+00:00
6+
7+
"""
8+
import sqlalchemy as sa
9+
from alembic import op
10+
from sqlalchemy.dialects import postgresql
11+
12+
# revision identifiers, used by Alembic.
13+
revision = "5ad02358751a"
14+
down_revision = "fce5d231e16d"
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade():
20+
# ### commands auto generated by Alembic - please adjust! ###
21+
op.add_column(
22+
"folders_v2",
23+
sa.Column(
24+
"trashed_at",
25+
sa.DateTime(timezone=True),
26+
nullable=True,
27+
comment="The date and time when the folder was marked as trashed.Null if the folder has not been trashed [default].",
28+
),
29+
)
30+
op.add_column(
31+
"folders_v2",
32+
sa.Column(
33+
"trashed_explicitly",
34+
sa.Boolean(),
35+
server_default=sa.text("false"),
36+
nullable=False,
37+
comment="Indicates whether the folder was explicitly trashed by the user (true) or inherited its trashed status from a parent (false) [default].",
38+
),
39+
)
40+
op.add_column(
41+
"projects",
42+
sa.Column(
43+
"trashed_explicitly",
44+
sa.Boolean(),
45+
server_default=sa.text("false"),
46+
nullable=False,
47+
comment="Indicates whether the project was explicitly trashed by the user (true) or inherited its trashed status from a parent (false) [default].",
48+
),
49+
)
50+
op.alter_column(
51+
"projects",
52+
"trashed_at",
53+
existing_type=postgresql.TIMESTAMP(timezone=True),
54+
comment="The date and time when the project was marked as trashed. Null if the project has not been trashed [default].",
55+
existing_nullable=True,
56+
)
57+
# ### end Alembic commands ###
58+
59+
60+
def downgrade():
61+
# ### commands auto generated by Alembic - please adjust! ###
62+
op.alter_column(
63+
"projects",
64+
"trashed_at",
65+
existing_type=postgresql.TIMESTAMP(timezone=True),
66+
comment=None,
67+
existing_comment="The date and time when the project was marked as trashed. Null if the project has not been trashed [default].",
68+
existing_nullable=True,
69+
)
70+
op.drop_column("projects", "trashed_explicitly")
71+
op.drop_column("folders_v2", "trashed_explicitly")
72+
op.drop_column("folders_v2", "trashed_at")
73+
# ### end Alembic commands ###

packages/postgres-database/src/simcore_postgres_database/models/folders_v2.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import sqlalchemy as sa
2+
from sqlalchemy.sql import expression
23

34
from ._common import column_created_datetime, column_modified_datetime
45
from .base import metadata
@@ -74,4 +75,19 @@
7475
),
7576
column_created_datetime(timezone=True),
7677
column_modified_datetime(timezone=True),
78+
sa.Column(
79+
"trashed_at",
80+
sa.DateTime(timezone=True),
81+
nullable=True,
82+
comment="The date and time when the folder was marked as trashed."
83+
"Null if the folder has not been trashed [default].",
84+
),
85+
sa.Column(
86+
"trashed_explicitly",
87+
sa.Boolean,
88+
nullable=False,
89+
server_default=expression.false(),
90+
comment="Indicates whether the folder was explicitly trashed by the user (true)"
91+
" or inherited its trashed status from a parent (false) [default].",
92+
),
7793
)

packages/postgres-database/src/simcore_postgres_database/models/projects.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import sqlalchemy as sa
77
from sqlalchemy.dialects.postgresql import ARRAY, JSONB
8-
from sqlalchemy.sql import func
8+
from sqlalchemy.sql import expression, func
99

1010
from .base import metadata
1111

@@ -145,7 +145,16 @@ class ProjectType(enum.Enum):
145145
"trashed_at",
146146
sa.DateTime(timezone=True),
147147
nullable=True,
148-
doc="Timestamp indicating when the project was marked as trashed, or null otherwise.",
148+
comment="The date and time when the project was marked as trashed. "
149+
"Null if the project has not been trashed [default].",
150+
),
151+
sa.Column(
152+
"trashed_explicitly",
153+
sa.Boolean,
154+
nullable=False,
155+
server_default=expression.false(),
156+
comment="Indicates whether the project was explicitly trashed by the user (true)"
157+
" or inherited its trashed status from a parent (false) [default].",
149158
),
150159
sa.Column(
151160
"workspace_id",

0 commit comments

Comments
 (0)