Skip to content

Commit abfb431

Browse files
🎨 Enhance Functions REST API endpoints in Web Server (ITISFoundation#8117)
1 parent 2b9bf2b commit abfb431

File tree

21 files changed

+522
-117
lines changed

21 files changed

+522
-117
lines changed

api/specs/web-server/_functions.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,19 @@
77

88
from typing import Annotated
99

10+
from _common import as_query
1011
from fastapi import APIRouter, Depends, status
1112
from models_library.api_schemas_webserver.functions import (
1213
FunctionToRegister,
1314
RegisteredFunctionGet,
15+
RegisteredFunctionUpdate,
1416
)
1517
from models_library.generics import Envelope
1618
from simcore_service_webserver._meta import API_VTAG
1719
from simcore_service_webserver.functions._controller._functions_rest_schemas import (
20+
FunctionGetQueryParams,
1821
FunctionPathParams,
22+
FunctionsListQueryParams,
1923
)
2024

2125
router = APIRouter(
@@ -35,12 +39,32 @@ async def register_function(
3539
) -> Envelope[RegisteredFunctionGet]: ...
3640

3741

42+
@router.get(
43+
"/functions",
44+
response_model=Envelope[list[RegisteredFunctionGet]],
45+
)
46+
async def list_functions(
47+
_query: Annotated[as_query(FunctionsListQueryParams), Depends()],
48+
): ...
49+
50+
3851
@router.get(
3952
"/functions/{function_id}",
4053
response_model=Envelope[RegisteredFunctionGet],
4154
)
4255
async def get_function(
4356
_path: Annotated[FunctionPathParams, Depends()],
57+
_query: Annotated[as_query(FunctionGetQueryParams), Depends()],
58+
): ...
59+
60+
61+
@router.patch(
62+
"/functions/{function_id}",
63+
response_model=Envelope[RegisteredFunctionGet],
64+
)
65+
async def update_function(
66+
_body: RegisteredFunctionUpdate,
67+
_path: Annotated[FunctionPathParams, Depends()],
4468
): ...
4569

4670

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
import datetime
12
from typing import Annotated, TypeAlias
23

34
from pydantic import Field
45

56
from ..functions import (
67
Function,
8+
FunctionAccessRights,
79
FunctionBase,
810
FunctionClass,
911
FunctionClassSpecificData,
@@ -23,6 +25,7 @@
2325
FunctionOutputs,
2426
FunctionOutputSchema,
2527
FunctionSchemaClass,
28+
FunctionUpdate,
2629
JSONFunctionInputSchema,
2730
JSONFunctionOutputSchema,
2831
ProjectFunction,
@@ -46,6 +49,7 @@
4649
UnsupportedFunctionClassError,
4750
UnsupportedFunctionFunctionJobClassCombinationError,
4851
)
52+
from ..projects import ProjectID
4953
from ._base import InputSchema, OutputSchema
5054

5155
__all__ = [
@@ -113,7 +117,13 @@
113117
class RegisteredSolverFunctionGet(RegisteredSolverFunction, OutputSchema): ...
114118

115119

116-
class RegisteredProjectFunctionGet(RegisteredProjectFunction, OutputSchema): ...
120+
class RegisteredProjectFunctionGet(RegisteredProjectFunction, OutputSchema):
121+
uid: Annotated[FunctionID, Field(alias="uuid")]
122+
project_id: Annotated[ProjectID, Field(alias="templateId")]
123+
created_at: Annotated[datetime.datetime, Field(alias="creationDate")]
124+
modified_at: Annotated[datetime.datetime, Field(alias="lastChangeDate")]
125+
access_rights: FunctionAccessRights | None = None
126+
thumbnail: str | None = None
117127

118128

119129
class SolverFunctionToRegister(SolverFunction, InputSchema): ...
@@ -131,3 +141,6 @@ class ProjectFunctionToRegister(ProjectFunction, InputSchema): ...
131141
RegisteredProjectFunctionGet | RegisteredSolverFunctionGet,
132142
Field(discriminator="function_class"),
133143
]
144+
145+
146+
class RegisteredFunctionUpdate(FunctionUpdate, InputSchema): ...

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,4 +386,5 @@ def from_domain_model(cls, permission: UserPermission) -> Self:
386386

387387

388388
class MyFunctionPermissionsGet(OutputSchema):
389+
read_functions: bool
389390
write_functions: bool

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,12 @@ class FunctionBase(BaseModel):
9999
class RegisteredFunctionBase(FunctionBase):
100100
uid: FunctionID
101101
created_at: datetime.datetime
102+
modified_at: datetime.datetime
103+
104+
105+
class FunctionUpdate(BaseModel):
106+
title: str | None = None
107+
description: str | None = None
102108

103109

104110
class ProjectFunction(FunctionBase):
@@ -250,6 +256,7 @@ class FunctionDB(BaseModel):
250256
class RegisteredFunctionDB(FunctionDB):
251257
uuid: FunctionID
252258
created: datetime.datetime
259+
modified: datetime.datetime
253260

254261

255262
class FunctionJobCollectionDB(BaseModel):

services/api-server/openapi.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10623,6 +10623,11 @@
1062310623
"format": "date-time",
1062410624
"title": "Created At"
1062510625
},
10626+
"modified_at": {
10627+
"type": "string",
10628+
"format": "date-time",
10629+
"title": "Modified At"
10630+
},
1062610631
"project_id": {
1062710632
"type": "string",
1062810633
"format": "uuid",
@@ -10636,6 +10641,7 @@
1063610641
"default_inputs",
1063710642
"uid",
1063810643
"created_at",
10644+
"modified_at",
1063910645
"project_id"
1064010646
],
1064110647
"title": "RegisteredProjectFunction"
@@ -10782,6 +10788,11 @@
1078210788
"format": "date-time",
1078310789
"title": "Created At"
1078410790
},
10791+
"modified_at": {
10792+
"type": "string",
10793+
"format": "date-time",
10794+
"title": "Modified At"
10795+
},
1078510796
"code_url": {
1078610797
"type": "string",
1078710798
"title": "Code Url"
@@ -10794,6 +10805,7 @@
1079410805
"default_inputs",
1079510806
"uid",
1079610807
"created_at",
10808+
"modified_at",
1079710809
"code_url"
1079810810
],
1079910811
"title": "RegisteredPythonCodeFunction"
@@ -10934,6 +10946,11 @@
1093410946
"format": "date-time",
1093510947
"title": "Created At"
1093610948
},
10949+
"modified_at": {
10950+
"type": "string",
10951+
"format": "date-time",
10952+
"title": "Modified At"
10953+
},
1093710954
"solver_key": {
1093810955
"type": "string",
1093910956
"pattern": "^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$",
@@ -10952,6 +10969,7 @@
1095210969
"default_inputs",
1095310970
"uid",
1095410971
"created_at",
10972+
"modified_at",
1095510973
"solver_key",
1095610974
"solver_version"
1095710975
],

services/api-server/tests/unit/api_functions/conftest.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,10 @@ def mock_function(
127127
def mock_registered_project_function(mock_function: Function) -> RegisteredFunction:
128128
return RegisteredProjectFunction(
129129
**{
130-
**mock_function.dict(),
131-
"uid": str(uuid4()),
130+
**mock_function.model_dump(),
131+
"uid": f"{uuid4()}",
132132
"created_at": datetime.datetime.now(datetime.UTC),
133+
"modified_at": datetime.datetime.now(datetime.UTC),
133134
}
134135
)
135136

@@ -148,8 +149,9 @@ def mock_registered_solver_function(
148149
"input_schema": sample_input_schema,
149150
"output_schema": sample_output_schema,
150151
"default_inputs": None,
151-
"uid": str(uuid4()),
152+
"uid": f"{uuid4()}",
152153
"created_at": datetime.datetime.now(datetime.UTC),
154+
"modified_at": datetime.datetime.now(datetime.UTC),
153155
"solver_key": "simcore/services/comp/ans-model",
154156
"solver_version": "1.0.1",
155157
}
@@ -166,7 +168,7 @@ def mock_project_function_job(
166168
"description": "A test function job",
167169
"inputs": {"key": "value"},
168170
"outputs": None,
169-
"project_job_id": str(uuid4()),
171+
"project_job_id": f"{uuid4()}",
170172
"function_class": FunctionClass.PROJECT,
171173
}
172174
return ProjectFunctionJob(**mock_function_job)
@@ -178,8 +180,8 @@ def mock_registered_project_function_job(
178180
) -> RegisteredFunctionJob:
179181
return RegisteredProjectFunctionJob(
180182
**{
181-
**mock_project_function_job.dict(),
182-
"uid": str(uuid4()),
183+
**mock_project_function_job.model_dump(),
184+
"uid": f"{uuid4()}",
183185
"created_at": datetime.datetime.now(datetime.UTC),
184186
}
185187
)
@@ -206,8 +208,8 @@ def mock_registered_solver_function_job(
206208
) -> RegisteredFunctionJob:
207209
return RegisteredSolverFunctionJob(
208210
**{
209-
**mock_solver_function_job.dict(),
210-
"uid": str(uuid4()),
211+
**mock_solver_function_job.model_dump(),
212+
"uid": f"{uuid4()}",
211213
"created_at": datetime.datetime.now(datetime.UTC),
212214
}
213215
)
@@ -222,7 +224,7 @@ def mock_function_job_collection(
222224
"description": "A test function job collection",
223225
"function_uid": mock_registered_project_function_job.function_uid,
224226
"function_class": FunctionClass.PROJECT,
225-
"project_id": str(uuid4()),
227+
"project_id": f"{uuid4()}",
226228
"function_job_ids": [
227229
mock_registered_project_function_job.uid for _ in range(5)
228230
],
@@ -237,7 +239,7 @@ def mock_registered_function_job_collection(
237239
return RegisteredFunctionJobCollection(
238240
**{
239241
**mock_function_job_collection.model_dump(),
240-
"uid": str(uuid4()),
242+
"uid": f"{uuid4()}",
241243
"created_at": datetime.datetime.now(datetime.UTC),
242244
}
243245
)

services/static-webserver/client/source/class/osparc/data/Resources.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,14 @@ qx.Class.define("osparc.data.Resources", {
631631
create: {
632632
method: "POST",
633633
url: statics.API + "/functions"
634+
},
635+
getOne: {
636+
method: "GET",
637+
url: statics.API + "/functions/{functionId}?include_extras=true"
638+
},
639+
getPage: {
640+
method: "GET",
641+
url: statics.API + "/functions?include_extras=true"
634642
}
635643
}
636644
},

services/static-webserver/client/source/class/osparc/data/model/Function.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ qx.Class.define("osparc.data.model.Function", {
3131
this.set({
3232
uuid: functionData.uuid,
3333
functionType: functionData.functionClass,
34-
name: functionData.name,
34+
name: functionData.title,
3535
description: functionData.description,
3636
inputSchema: functionData.inputSchema || this.getInputSchema(),
3737
outputSchema: functionData.outputSchema || this.getOutputSchema(),

services/static-webserver/client/source/class/osparc/store/Functions.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ qx.Class.define("osparc.store.Functions", {
9292
},
9393

9494
fetchFunctionsPaginated: function(params, options) {
95-
const isBackendReady = false;
95+
const isBackendReady = true;
9696
if (!isBackendReady) {
9797
return new Promise(resolve => {
9898
const response = this.__dummyResponse();
@@ -110,7 +110,7 @@ qx.Class.define("osparc.store.Functions", {
110110
},
111111

112112
fetchFunction: function(functionId) {
113-
const isBackendReady = false;
113+
const isBackendReady = true;
114114
if (!isBackendReady) {
115115
return new Promise(resolve => {
116116
const response = this.__dummyResponse();

0 commit comments

Comments
 (0)