diff --git a/.env-devel b/.env-devel index 6cea5247c93..0b606a2426d 100644 --- a/.env-devel +++ b/.env-devel @@ -59,7 +59,7 @@ CLUSTERS_KEEPER_EC2_INSTANCES_PREFIX="" CLUSTERS_KEEPER_LOGLEVEL=INFO CLUSTERS_KEEPER_MAX_MISSED_HEARTBEATS_BEFORE_CLUSTER_TERMINATION=5 CLUSTERS_KEEPER_PRIMARY_EC2_INSTANCES=null -CLUSTERS_KEEPER_TASK_INTERVAL=30 +CLUSTERS_KEEPER_TASK_INTERVAL=00:00:30 CLUSTERS_KEEPER_WORKERS_EC2_INSTANCES=null CLUSTERS_KEEPER_TRACING={} diff --git a/.vscode/launch.template.json b/.vscode/launch.template.json index 6e74bb461fa..dc3fd1cd481 100644 --- a/.vscode/launch.template.json +++ b/.vscode/launch.template.json @@ -15,6 +15,7 @@ "--log-cli-level=INFO", "--pdb", "--setup-show", + "--durations=5", "-sx", "-vv", "${file}" diff --git a/Makefile b/Makefile index 28964b2f2d1..9dbdf84c9f4 100644 --- a/Makefile +++ b/Makefile @@ -601,8 +601,8 @@ auto-doc: .stack-simcore-version.yml ## Auto generates diagrams for README.md # Updating docs/img @mv --verbose $<.png docs/img/ -.PHONY: services.md -services.md: ## Auto generates service.md +.PHONY: services.ignore.md +services.ignore.md: ## Auto generates service.md # Making $@ scripts/echo_services_markdown.py > $@ diff --git a/api/specs/storage/scripts/Makefile b/api/specs/storage/Makefile similarity index 51% rename from api/specs/storage/scripts/Makefile rename to api/specs/storage/Makefile index 079fa84aed2..879009a1baa 100644 --- a/api/specs/storage/scripts/Makefile +++ b/api/specs/storage/Makefile @@ -1,3 +1,4 @@ +.DEFAULT_GOAL := all .PHONY: _check_venv_active _check_venv_active: @@ -6,13 +7,12 @@ _check_venv_active: .PHONY: install -install: _check_venv_active - @cd ./../../../../services/storage && make install-dev && cd - +install-dev install: _check_venv_active + # installing storage and requirements.txt + @cd ./../../../services/storage && make install-dev && cd - @uv pip install -r requirements.txt .PHONY: all -all: _check_venv_active - @for file in *.py; do \ - python $$file; \ - done +all: _check_venv_active install + python openapi.py diff --git a/api/specs/storage/scripts/storage.py b/api/specs/storage/openapi.py similarity index 97% rename from api/specs/storage/scripts/storage.py rename to api/specs/storage/openapi.py index 24c0b06a48e..0f9ba5afb96 100644 --- a/api/specs/storage/scripts/storage.py +++ b/api/specs/storage/openapi.py @@ -27,6 +27,7 @@ from models_library.projects_nodes_io import LocationID, StorageFileID from models_library.users import UserID from pydantic import AnyUrl, ByteSize +from servicelib.fastapi.openapi import create_openapi_specs from servicelib.long_running_tasks._models import TaskGet, TaskId, TaskStatus from settings_library.s3 import S3Settings from simcore_service_storage._meta import API_VTAG @@ -35,6 +36,7 @@ FileMetaData, SearchFilesQueryParams, ) +from simcore_service_storage.resources import storage_resources TAGS_DATASETS: list[str | Enum] = ["datasets"] TAGS_FILES: list[str | Enum] = ["files"] @@ -401,6 +403,7 @@ async def cancel_and_delete_task(task_id: TaskId): if __name__ == "__main__": - from _common import CURRENT_DIR, create_openapi_specs + openapi = create_openapi_specs(app, drop_fastapi_default_422=True) - create_openapi_specs(app, CURRENT_DIR.parent / "openapi.yaml") + oas_path = storage_resources.get_path("api/v0/openapi.yaml").resolve() + print(f"Writing {oas_path}...", end=None) diff --git a/api/specs/storage/openapi.yaml b/api/specs/storage/openapi.yaml deleted file mode 100644 index 0a9abeeb43b..00000000000 --- a/api/specs/storage/openapi.yaml +++ /dev/null @@ -1,1459 +0,0 @@ -openapi: 3.1.0 -info: - title: simcore-service-storage API - description: API definition for simcore-service-storage service - contact: - name: IT'IS Foundation - email: support@simcore.io - license: - name: MIT - url: https://github.com/ITISFoundation/osparc-simcore/blob/master/LICENSE - version: 0.3.0 -servers: -- url: / - description: 'Default server: requests directed to serving url' -- url: http://{host}:{port}/ - description: 'Development server: can configure any base url' - variables: - host: - default: 127.0.0.1 - port: - default: '8000' -paths: - /v0/locations/{location_id}/datasets: - get: - tags: - - datasets - summary: Get datasets metadata - description: returns all the top level datasets a user has access to - operationId: get_datasets_metadata - parameters: - - required: true - schema: - type: integer - title: Location Id - name: location_id - in: path - - required: true - schema: - type: integer - exclusiveMinimum: true - title: User Id - minimum: 0 - name: user_id - in: query - responses: - '200': - description: Successful Response - content: - application/json: - schema: - $ref: '#/components/schemas/Envelope_list_simcore_service_storage.models.DatasetMetaData__' - /v0/locations/{location_id}/datasets/{dataset_id}/metadata: - get: - tags: - - datasets - summary: Get Files Metadata - description: returns all the file meta data inside dataset with dataset_id - operationId: get_files_metadata_dataset - parameters: - - required: true - schema: - type: integer - title: Location Id - name: location_id - in: path - - required: true - schema: - type: string - title: Dataset Id - name: dataset_id - in: path - - required: true - schema: - type: integer - exclusiveMinimum: true - title: User Id - minimum: 0 - name: user_id - in: query - - description: Automatic directory expansion. This will be replaced by pagination - the future - required: false - schema: - type: boolean - title: Expand Dirs - description: Automatic directory expansion. This will be replaced by pagination - the future - default: true - name: expand_dirs - in: query - responses: - '200': - description: Successful Response - content: - application/json: - schema: - $ref: '#/components/schemas/Envelope_list_models_library.api_schemas_storage.FileMetaDataGet__' - /v0/locations: - get: - tags: - - locations - summary: Get available storage locations - description: Returns the list of available storage locations - operationId: get_storage_locations - parameters: - - required: true - schema: - type: integer - exclusiveMinimum: true - title: User Id - minimum: 0 - name: user_id - in: query - responses: - '200': - description: Successful Response - content: - application/json: - schema: - items: - $ref: '#/components/schemas/DatasetMetaData' - type: array - title: Response Get Storage Locations - /v0/locations/{location_id}:sync: - post: - tags: - - locations - summary: Manually triggers the synchronisation of the file meta data table in - the database - description: Returns an object containing added, changed and removed paths - operationId: synchronise_meta_data_table - parameters: - - required: true - schema: - type: integer - title: Location Id - name: location_id - in: path - - required: false - schema: - type: boolean - title: Dry Run - default: false - name: dry_run - in: query - - required: false - schema: - type: boolean - title: Fire And Forget - default: false - name: fire_and_forget - in: query - responses: - '200': - description: Successful Response - content: - application/json: - schema: - $ref: '#/components/schemas/Envelope_TableSynchronisation_' - /v0/locations/{location_id}/files/metadata: - get: - tags: - - files - summary: Get datasets metadata - description: returns all the file meta data a user has access to (uuid_filter - may be used) - operationId: get_files_metadata - parameters: - - required: true - schema: - type: integer - title: Location Id - name: location_id - in: path - - required: false - schema: - type: string - title: Uuid Filter - default: '' - name: uuid_filter - in: query - - description: Automatic directory expansion. This will be replaced by pagination - the future - required: false - schema: - type: boolean - title: Expand Dirs - description: Automatic directory expansion. This will be replaced by pagination - the future - default: true - name: expand_dirs - in: query - responses: - '200': - description: Successful Response - content: - application/json: - schema: - $ref: '#/components/schemas/Envelope_list_simcore_service_storage.models.DatasetMetaData__' - /v0/locations/{location_id}/files/{file_id}/metadata: - get: - tags: - - files - summary: Get File Metadata - description: returns the file meta data of file_id if user_id has the rights - to - operationId: get_file_metadata - parameters: - - required: true - schema: - type: integer - title: Location Id - name: location_id - in: path - - required: true - schema: - anyOf: - - type: string - pattern: ^(api|([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}))\/([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12})\/(.+)$ - - type: string - pattern: ^N:package:[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}$ - title: File Id - name: file_id - in: path - - required: true - schema: - type: integer - exclusiveMinimum: true - title: User Id - minimum: 0 - name: user_id - in: query - responses: - '200': - description: Successful Response - content: - application/json: - schema: - anyOf: - - $ref: '#/components/schemas/FileMetaData' - - $ref: '#/components/schemas/Envelope_FileMetaDataGet_' - title: Response Get File Metadata - /v0/locations/{location_id}/files/{file_id}: - get: - tags: - - files - summary: Returns download link for requested file - description: creates a download file link if user has the rights to - operationId: download_file - parameters: - - required: true - schema: - type: integer - title: Location Id - name: location_id - in: path - - required: true - schema: - anyOf: - - type: string - pattern: ^(api|([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}))\/([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12})\/(.+)$ - - type: string - pattern: ^N:package:[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}$ - title: File Id - name: file_id - in: path - - required: true - schema: - type: integer - exclusiveMinimum: true - title: User Id - minimum: 0 - name: user_id - in: query - - required: false - schema: - allOf: - - $ref: '#/components/schemas/LinkType' - default: PRESIGNED - name: link_type - in: query - responses: - '200': - description: Successful Response - content: - application/json: - schema: - $ref: '#/components/schemas/Envelope_PresignedLink_' - put: - tags: - - files - summary: Returns upload link - description: creates one or more upload file links if user has the rights to, - expects the client to complete/abort upload - operationId: upload_file - parameters: - - required: true - schema: - type: integer - title: Location Id - name: location_id - in: path - - required: true - schema: - anyOf: - - type: string - pattern: ^(api|([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}))\/([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12})\/(.+)$ - - type: string - pattern: ^N:package:[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}$ - title: File Id - name: file_id - in: path - - required: true - schema: - type: integer - title: File Size - name: file_size - in: query - - required: false - schema: - allOf: - - $ref: '#/components/schemas/LinkType' - default: PRESIGNED - name: link_type - in: query - - required: false - schema: - type: boolean - title: Is Directory - default: false - name: is_directory - in: query - responses: - '200': - description: Successful Response - content: - application/json: - schema: - anyOf: - - $ref: '#/components/schemas/Envelope_FileUploadSchema_' - - $ref: '#/components/schemas/Envelope_AnyUrl_' - title: Response Upload File - delete: - tags: - - files - summary: Deletes File - description: deletes file if user has the rights to - operationId: delete_file - parameters: - - required: true - schema: - type: integer - title: Location Id - name: location_id - in: path - - required: true - schema: - anyOf: - - type: string - pattern: ^(api|([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}))\/([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12})\/(.+)$ - - type: string - pattern: ^N:package:[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}$ - title: File Id - name: file_id - in: path - - required: true - schema: - type: integer - exclusiveMinimum: true - title: User Id - minimum: 0 - name: user_id - in: query - responses: - '204': - description: Successful Response - /v0/locations/{location_id}/files/{file_id}:abort: - post: - tags: - - files - summary: Abort Upload File - description: 'aborts an upload if user has the rights to, and reverts - - to the latest version if available, else will delete the file' - operationId: abort_upload_file - parameters: - - required: true - schema: - type: integer - title: Location Id - name: location_id - in: path - - required: true - schema: - anyOf: - - type: string - pattern: ^(api|([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}))\/([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12})\/(.+)$ - - type: string - pattern: ^N:package:[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}$ - title: File Id - name: file_id - in: path - - required: true - schema: - type: integer - exclusiveMinimum: true - title: User Id - minimum: 0 - name: user_id - in: query - responses: - '204': - description: Successful Response - /v0/locations/{location_id}/files/{file_id}:complete: - post: - tags: - - files - summary: Complete Upload File - description: completes an upload if the user has the rights to - operationId: complete_upload_file - parameters: - - required: true - schema: - type: integer - title: Location Id - name: location_id - in: path - - required: true - schema: - anyOf: - - type: string - pattern: ^(api|([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}))\/([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12})\/(.+)$ - - type: string - pattern: ^N:package:[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}$ - title: File Id - name: file_id - in: path - - required: true - schema: - type: integer - exclusiveMinimum: true - title: User Id - minimum: 0 - name: user_id - in: query - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/Envelope_FileUploadCompletionBody_' - required: true - responses: - '202': - description: Successful Response - content: - application/json: - schema: - $ref: '#/components/schemas/Envelope_FileUploadCompleteResponse_' - /v0/locations/{location_id}/files/{file_id}:complete/futures/{future_id}: - post: - tags: - - files - summary: Check for upload completion - description: Returns state of upload completion - operationId: is_completed_upload_file - parameters: - - required: true - schema: - type: integer - title: Location Id - name: location_id - in: path - - required: true - schema: - anyOf: - - type: string - pattern: ^(api|([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}))\/([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12})\/(.+)$ - - type: string - pattern: ^N:package:[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}$ - title: File Id - name: file_id - in: path - - required: true - schema: - type: string - title: Future Id - name: future_id - in: path - - required: true - schema: - type: integer - exclusiveMinimum: true - title: User Id - minimum: 0 - name: user_id - in: query - responses: - '200': - description: Successful Response - content: - application/json: - schema: - $ref: '#/components/schemas/Envelope_FileUploadCompleteFutureResponse_' - /v0/: - get: - tags: - - health - summary: health check endpoint - description: Current service health - operationId: health_check - responses: - '200': - description: Successful Response - content: - application/json: - schema: - $ref: '#/components/schemas/Envelope_HealthCheck_' - /v0/status: - get: - tags: - - health - summary: returns the status of the services inside - description: returns the status of all the external dependencies - operationId: get_status - responses: - '200': - description: Successful Response - content: - application/json: - schema: - $ref: '#/components/schemas/Envelope_AppStatusCheck_' - /v0/files/{file_id}:soft-copy: - post: - tags: - - files - summary: copy file as soft link - description: creates and returns a soft link - operationId: copy_as_soft_link - parameters: - - required: true - schema: - anyOf: - - type: string - pattern: ^(api|([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}))\/([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12})\/(.+)$ - - type: string - pattern: ^N:package:[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}$ - title: File Id - name: file_id - in: path - - required: true - schema: - type: integer - exclusiveMinimum: true - title: User Id - minimum: 0 - name: user_id - in: query - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/SoftCopyBody' - required: true - responses: - '200': - description: Successful Response - content: - application/json: - schema: - $ref: '#/components/schemas/FileMetaDataGet' - /v0/simcore-s3:access: - post: - tags: - - simcore-s3 - summary: gets or creates the a temporary access - description: returns a set of S3 credentials - operationId: get_or_create_temporary_s3_access - parameters: - - required: true - schema: - type: integer - exclusiveMinimum: true - title: User Id - minimum: 0 - name: user_id - in: query - responses: - '200': - description: Successful Response - content: - application/json: - schema: - $ref: '#/components/schemas/Envelope_S3Settings_' - /v0/simcore-s3/folders: - post: - tags: - - simcore-s3 - summary: copies folders from project - description: copies folders from project - operationId: copy_folders_from_project - parameters: - - required: true - schema: - type: integer - exclusiveMinimum: true - title: User Id - minimum: 0 - name: user_id - in: query - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/FoldersBody' - required: true - responses: - '200': - description: Successful Response - content: - application/json: - schema: - $ref: '#/components/schemas/Envelope_TaskGet_' - /v0/simcore-s3/folders/{folder_id}: - delete: - tags: - - simcore-s3 - summary: delete folders from project - description: removes folders from a project - operationId: delete_folders_of_project - parameters: - - required: true - schema: - type: string - title: Folder Id - name: folder_id - in: path - - required: true - schema: - type: integer - exclusiveMinimum: true - title: User Id - minimum: 0 - name: user_id - in: query - - required: false - schema: - type: string - format: uuid - title: Node Id - name: node_id - in: query - responses: - '204': - description: Successful Response - /v0/simcore-s3/files/metadata:search: - post: - tags: - - simcore-s3 - summary: search for owned files - description: search for files starting with `startswith` and/or matching a sha256_checksum - in the file_meta_data table - operationId: search_files - parameters: - - required: true - schema: - type: integer - exclusiveMinimum: true - title: User Id - minimum: 0 - name: user_id - in: query - - required: false - schema: - type: string - title: Startswith - name: startswith - in: query - - required: false - schema: - type: string - pattern: ^[a-fA-F0-9]{64}$ - title: Sha256 Checksum - name: sha256_checksum - in: query - - required: true - schema: - type: string - enum: - - owned - title: Kind - name: kind - in: query - - required: false - schema: - type: integer - maximum: 50 - minimum: 1 - title: Limit - default: 20 - name: limit - in: query - - required: false - schema: - type: integer - minimum: 0 - title: Offset - default: 0 - name: offset - in: query - responses: - '200': - description: Successful Response - content: - application/json: - schema: - $ref: '#/components/schemas/Envelope_FileMetaDataGet_' - /v0/futures: - get: - tags: - - tasks - summary: list current long running tasks - description: list current long running tasks - operationId: list_tasks - responses: - '200': - description: Successful Response - content: - application/json: - schema: - $ref: '#/components/schemas/Envelope_TaskGet_' - /v0/futures/{task_id}: - get: - tags: - - tasks - summary: gets the status of the task - description: gets the status of the task - operationId: get_task_status - parameters: - - required: true - schema: - type: string - title: Task Id - name: task_id - in: path - responses: - '200': - description: Successful Response - content: - application/json: - schema: - $ref: '#/components/schemas/Envelope_TaskStatus_' - delete: - tags: - - tasks - summary: cancels and removes the task - description: cancels and removes the task - operationId: cancel_and_delete_task - parameters: - - required: true - schema: - type: string - title: Task Id - name: task_id - in: path - responses: - '204': - description: Successful Response - /v0/futures/{task_id}/result: - get: - tags: - - tasks - summary: get result of the task - description: get result of the task - operationId: get_task_result - parameters: - - required: true - schema: - type: string - title: Task Id - name: task_id - in: path - responses: - '200': - description: Successful Response - content: - application/json: - schema: - title: Response Get Task Result -components: - schemas: - AppStatusCheck: - properties: - app_name: - type: string - title: App Name - description: Application name - version: - type: string - title: Version - description: Application's version - services: - type: object - title: Services - description: Other backend services connected from this service - default: {} - sessions: - type: object - title: Sessions - description: Client sessions info. If single session per app, then is denoted - as main - default: {} - url: - type: string - maxLength: 65536 - minLength: 1 - format: uri - title: Url - description: Link to current resource - diagnostics_url: - type: string - maxLength: 65536 - minLength: 1 - format: uri - title: Diagnostics Url - description: Link to diagnostics report sub-resource. This MIGHT take some - time to compute - type: object - required: - - app_name - - version - title: AppStatusCheck - DatasetMetaData: - properties: - dataset_id: - anyOf: - - type: string - format: uuid - - type: string - pattern: ^N:dataset:[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}$ - title: Dataset Id - display_name: - type: string - title: Display Name - additionalProperties: false - type: object - required: - - dataset_id - - display_name - title: DatasetMetaData - Envelope_AnyUrl_: - properties: - data: - type: string - maxLength: 65536 - minLength: 1 - format: uri - title: Data - error: - title: Error - type: object - title: Envelope[AnyUrl] - Envelope_AppStatusCheck_: - properties: - data: - $ref: '#/components/schemas/AppStatusCheck' - error: - title: Error - type: object - title: Envelope[AppStatusCheck] - Envelope_FileMetaDataGet_: - properties: - data: - $ref: '#/components/schemas/FileMetaDataGet' - error: - title: Error - type: object - title: Envelope[FileMetaDataGet] - Envelope_FileUploadCompleteFutureResponse_: - properties: - data: - $ref: '#/components/schemas/FileUploadCompleteFutureResponse' - error: - title: Error - type: object - title: Envelope[FileUploadCompleteFutureResponse] - Envelope_FileUploadCompleteResponse_: - properties: - data: - $ref: '#/components/schemas/FileUploadCompleteResponse' - error: - title: Error - type: object - title: Envelope[FileUploadCompleteResponse] - Envelope_FileUploadCompletionBody_: - properties: - data: - $ref: '#/components/schemas/FileUploadCompletionBody' - error: - title: Error - type: object - title: Envelope[FileUploadCompletionBody] - Envelope_FileUploadSchema_: - properties: - data: - $ref: '#/components/schemas/FileUploadSchema' - error: - title: Error - type: object - title: Envelope[FileUploadSchema] - Envelope_HealthCheck_: - properties: - data: - $ref: '#/components/schemas/HealthCheck' - error: - title: Error - type: object - title: Envelope[HealthCheck] - Envelope_PresignedLink_: - properties: - data: - $ref: '#/components/schemas/PresignedLink' - error: - title: Error - type: object - title: Envelope[PresignedLink] - Envelope_S3Settings_: - properties: - data: - $ref: '#/components/schemas/S3Settings' - error: - title: Error - type: object - title: Envelope[S3Settings] - Envelope_TableSynchronisation_: - properties: - data: - $ref: '#/components/schemas/TableSynchronisation' - error: - title: Error - type: object - title: Envelope[TableSynchronisation] - Envelope_TaskGet_: - properties: - data: - $ref: '#/components/schemas/TaskGet' - error: - title: Error - type: object - title: Envelope[TaskGet] - Envelope_TaskStatus_: - properties: - data: - $ref: '#/components/schemas/TaskStatus' - error: - title: Error - type: object - title: Envelope[TaskStatus] - Envelope_list_models_library.api_schemas_storage.FileMetaDataGet__: - properties: - data: - items: - $ref: '#/components/schemas/FileMetaDataGet' - type: array - title: Data - error: - title: Error - type: object - title: Envelope[list[models_library.api_schemas_storage.FileMetaDataGet]] - Envelope_list_simcore_service_storage.models.DatasetMetaData__: - properties: - data: - items: - $ref: '#/components/schemas/DatasetMetaData' - type: array - title: Data - error: - title: Error - type: object - title: Envelope[list[simcore_service_storage.models.DatasetMetaData]] - FileMetaData: - properties: - file_uuid: - type: string - title: File Uuid - description: NOT a unique ID, like (api|uuid)/uuid/file_name or DATCORE - folder structure - location_id: - type: integer - title: Location Id - description: Storage location - project_name: - type: string - title: Project Name - description: optional project name, used by frontend to display path - node_name: - type: string - title: Node Name - description: optional node name, used by frontend to display path - file_name: - type: string - title: File Name - description: Display name for a file - file_id: - anyOf: - - type: string - pattern: ^(api|([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}))\/([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12})\/(.+)$ - - type: string - pattern: ^N:package:[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}$ - title: File Id - description: THIS IS the unique ID for the file. either (api|project_id)/node_id/file_name.ext - for S3 and N:package:UUID for datcore - created_at: - type: string - format: date-time - title: Created At - last_modified: - type: string - format: date-time - title: Last Modified - file_size: - anyOf: - - type: integer - - type: integer - title: File Size - description: File size in bytes (-1 means invalid) - default: -1 - entity_tag: - type: string - title: Entity Tag - description: Entity tag (or ETag), represents a specific version of the - file, None if invalid upload or datcore - is_soft_link: - type: boolean - title: Is Soft Link - description: If true, this file is a soft link.i.e. is another entry with - the same object_name - default: false - is_directory: - type: boolean - title: Is Directory - description: if True this is a directory - default: false - sha256_checksum: - type: string - pattern: ^[a-fA-F0-9]{64}$ - title: Sha256 Checksum - upload_id: - type: string - title: Upload Id - upload_expires_at: - type: string - format: date-time - title: Upload Expires At - location: - type: string - title: Location - bucket_name: - type: string - title: Bucket Name - object_name: - type: string - title: Object Name - project_id: - type: string - format: uuid - title: Project Id - node_id: - type: string - format: uuid - title: Node Id - user_id: - type: integer - exclusiveMinimum: true - title: User Id - minimum: 0 - additionalProperties: false - type: object - required: - - file_uuid - - location_id - - file_name - - file_id - - created_at - - last_modified - - location - - bucket_name - - object_name - title: FileMetaData - FileMetaDataGet: - properties: - file_uuid: - type: string - title: File Uuid - description: NOT a unique ID, like (api|uuid)/uuid/file_name or DATCORE - folder structure - location_id: - type: integer - title: Location Id - description: Storage location - project_name: - type: string - title: Project Name - description: optional project name, used by frontend to display path - node_name: - type: string - title: Node Name - description: optional node name, used by frontend to display path - file_name: - type: string - title: File Name - description: Display name for a file - file_id: - anyOf: - - type: string - pattern: ^(api|([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}))\/([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12})\/(.+)$ - - type: string - pattern: ^N:package:[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}$ - title: File Id - description: THIS IS the unique ID for the file. either (api|project_id)/node_id/file_name.ext - for S3 and N:package:UUID for datcore - created_at: - type: string - format: date-time - title: Created At - last_modified: - type: string - format: date-time - title: Last Modified - file_size: - anyOf: - - type: integer - - type: integer - title: File Size - description: File size in bytes (-1 means invalid) - default: -1 - entity_tag: - type: string - title: Entity Tag - description: Entity tag (or ETag), represents a specific version of the - file, None if invalid upload or datcore - is_soft_link: - type: boolean - title: Is Soft Link - description: If true, this file is a soft link.i.e. is another entry with - the same object_name - default: false - is_directory: - type: boolean - title: Is Directory - description: if True this is a directory - default: false - sha256_checksum: - type: string - pattern: ^[a-fA-F0-9]{64}$ - title: Sha256 Checksum - description: 'SHA256 message digest of the file content. Main purpose: cheap - lookup.' - additionalProperties: false - type: object - required: - - file_uuid - - location_id - - file_name - - file_id - - created_at - - last_modified - title: FileMetaDataGet - FileUploadCompleteFutureResponse: - properties: - state: - $ref: '#/components/schemas/FileUploadCompleteState' - e_tag: - type: string - title: E Tag - type: object - required: - - state - title: FileUploadCompleteFutureResponse - FileUploadCompleteLinks: - properties: - state: - type: string - maxLength: 65536 - minLength: 1 - format: uri - title: State - type: object - required: - - state - title: FileUploadCompleteLinks - FileUploadCompleteResponse: - properties: - links: - $ref: '#/components/schemas/FileUploadCompleteLinks' - type: object - required: - - links - title: FileUploadCompleteResponse - FileUploadCompleteState: - enum: - - ok - - nok - title: FileUploadCompleteState - description: An enumeration. - FileUploadCompletionBody: - properties: - parts: - items: - $ref: '#/components/schemas/UploadedPart' - type: array - title: Parts - type: object - required: - - parts - title: FileUploadCompletionBody - FileUploadLinks: - properties: - abort_upload: - type: string - maxLength: 65536 - minLength: 1 - format: uri - title: Abort Upload - complete_upload: - type: string - maxLength: 65536 - minLength: 1 - format: uri - title: Complete Upload - type: object - required: - - abort_upload - - complete_upload - title: FileUploadLinks - FileUploadSchema: - properties: - chunk_size: - type: integer - title: Chunk Size - urls: - items: - type: string - maxLength: 65536 - minLength: 1 - format: uri - type: array - title: Urls - links: - $ref: '#/components/schemas/FileUploadLinks' - type: object - required: - - chunk_size - - urls - - links - title: FileUploadSchema - FoldersBody: - properties: - source: - type: object - title: Source - destination: - type: object - title: Destination - nodes_map: - additionalProperties: - type: string - format: uuid - type: object - title: Nodes Map - type: object - title: FoldersBody - HealthCheck: - properties: - name: - type: string - title: Name - status: - type: string - title: Status - api_version: - type: string - title: Api Version - version: - type: string - title: Version - type: object - title: HealthCheck - LinkType: - type: string - enum: - - PRESIGNED - - S3 - title: LinkType - description: An enumeration. - PresignedLink: - properties: - link: - type: string - maxLength: 65536 - minLength: 1 - format: uri - title: Link - type: object - required: - - link - title: PresignedLink - S3Settings: - properties: - S3_ACCESS_KEY: - type: string - maxLength: 50 - minLength: 1 - title: S3 Access Key - S3_BUCKET_NAME: - type: string - maxLength: 50 - minLength: 1 - title: S3 Bucket Name - S3_ENDPOINT: - type: string - maxLength: 65536 - minLength: 1 - format: uri - title: S3 Endpoint - description: do not define if using standard AWS - S3_REGION: - type: string - maxLength: 50 - minLength: 1 - title: S3 Region - S3_SECRET_KEY: - type: string - maxLength: 50 - minLength: 1 - title: S3 Secret Key - additionalProperties: false - type: object - required: - - S3_ACCESS_KEY - - S3_BUCKET_NAME - - S3_REGION - - S3_SECRET_KEY - title: S3Settings - description: "- Customized configuration for all settings\n- If a field is a\ - \ BaseCustomSettings subclass, it allows creating a default from env vars\ - \ setting the Field\n option 'auto_default_from_env=True'.\n\nSEE tests for\ - \ details." - SoftCopyBody: - properties: - link_id: - type: string - pattern: ^(api|([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}))\/([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12})\/(.+)$ - title: Link Id - type: object - required: - - link_id - title: SoftCopyBody - TableSynchronisation: - properties: - dry_run: - type: boolean - title: Dry Run - fire_and_forget: - type: boolean - title: Fire And Forget - removed: - items: - type: string - type: array - title: Removed - type: object - required: - - removed - title: TableSynchronisation - TaskGet: - properties: - task_id: - type: string - title: Task Id - task_name: - type: string - title: Task Name - status_href: - type: string - title: Status Href - result_href: - type: string - title: Result Href - abort_href: - type: string - title: Abort Href - type: object - required: - - task_id - - task_name - - status_href - - result_href - - abort_href - title: TaskGet - TaskProgress: - properties: - task_id: - type: string - title: Task Id - message: - type: string - title: Message - default: '' - percent: - type: number - maximum: 1.0 - minimum: 0.0 - title: Percent - default: 0.0 - type: object - title: TaskProgress - description: 'Helps the user to keep track of the progress. Progress is expected - to be - - defined as a float bound between 0.0 and 1.0' - TaskStatus: - properties: - task_progress: - $ref: '#/components/schemas/TaskProgress' - done: - type: boolean - title: Done - started: - type: string - format: date-time - title: Started - type: object - required: - - task_progress - - done - - started - title: TaskStatus - UploadedPart: - properties: - number: - type: integer - exclusiveMinimum: true - title: Number - minimum: 0 - e_tag: - type: string - title: E Tag - type: object - required: - - number - - e_tag - title: UploadedPart -tags: -- name: datasets -- name: files -- name: health -- name: locations -- name: tasks -- name: simcore-s3 diff --git a/api/specs/storage/requirements.txt b/api/specs/storage/requirements.txt new file mode 100644 index 00000000000..52c5ebf91cb --- /dev/null +++ b/api/specs/storage/requirements.txt @@ -0,0 +1,4 @@ +# Extra reqs, besides webserver's +--constraint ../../../requirements/constraints.txt + +fastapi diff --git a/api/specs/storage/scripts/_common.py b/api/specs/storage/scripts/_common.py deleted file mode 100644 index 6417a490582..00000000000 --- a/api/specs/storage/scripts/_common.py +++ /dev/null @@ -1,38 +0,0 @@ -""" Common utils for OAS script generators -""" - -import sys -from pathlib import Path - -import yaml -from fastapi import FastAPI -from servicelib.fastapi.openapi import override_fastapi_openapi_method - -CURRENT_DIR = Path(sys.argv[0] if __name__ == "__main__" else __file__).resolve().parent - - -def create_openapi_specs( - app: FastAPI, file_path: Path, *, drop_fastapi_default_422: bool = True -): - override_fastapi_openapi_method(app) - openapi = app.openapi() - - schemas = openapi["components"]["schemas"] - for section in ("HTTPValidationError", "ValidationError"): - schemas.pop(section) - - # Removes default response 422 - if drop_fastapi_default_422: - for _, method_item in openapi.get("paths", {}).items(): - for _, param in method_item.items(): - # NOTE: If description is like this, - # it assumes it is the default HTTPValidationError from fastapi - if (e422 := param.get("responses", {}).get("422", None)) and e422.get( - "description" - ) == "Validation Error": - param.get("responses", {}).pop("422", None) - - with file_path.open("wt") as fh: - yaml.safe_dump(openapi, fh, indent=1, sort_keys=False) - - print("Saved OAS to", file_path) diff --git a/api/specs/storage/scripts/requirements.txt b/api/specs/storage/scripts/requirements.txt deleted file mode 100644 index cee28f62683..00000000000 --- a/api/specs/storage/scripts/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -# Extra reqs, besides webserver's - -fastapi<0.100 diff --git a/api/specs/web-server/_catalog.py b/api/specs/web-server/_catalog.py index ffaa9ed916b..729ede624de 100644 --- a/api/specs/web-server/_catalog.py +++ b/api/specs/web-server/_catalog.py @@ -127,7 +127,7 @@ def get_compatible_outputs_given_target_input( @router.get( "/catalog/services/{service_key}/{service_version}/resources", - response_model=ServiceResourcesGet, + response_model=Envelope[ServiceResourcesGet], ) def get_service_resources( _params: Annotated[ServicePathParams, Depends()], diff --git a/api/specs/web-server/_common.py b/api/specs/web-server/_common.py index 06ba6872800..637f4101819 100644 --- a/api/specs/web-server/_common.py +++ b/api/specs/web-server/_common.py @@ -5,45 +5,55 @@ import sys from collections.abc import Callable from pathlib import Path -from typing import Any, ClassVar, NamedTuple +from typing import Annotated, NamedTuple, Optional, Union, get_args, get_origin -import yaml from common_library.json_serialization import json_dumps from common_library.pydantic_fields_extension import get_type -from fastapi import FastAPI, Query +from fastapi import Query from models_library.basic_types import LogLevel -from pydantic import BaseModel, Field, create_model +from pydantic import BaseModel, ConfigDict, Field, Json, create_model from pydantic.fields import FieldInfo -from servicelib.fastapi.openapi import override_fastapi_openapi_method CURRENT_DIR = Path(sys.argv[0] if __name__ == "__main__" else __file__).resolve().parent -def _create_json_type(**schema_extras): - class _Json(str): - __slots__ = () +def _replace_basemodel_in_annotation(annotation, new_type): + origin = get_origin(annotation) - @classmethod - def __modify_schema__(cls, field_schema: dict[str, Any]) -> None: - # openapi.json schema is corrected here - field_schema.update( - type="string", - # format="json-string" NOTE: we need to get rid of openapi-core in web-server before using this! - ) - if schema_extras: - field_schema.update(schema_extras) + # Handle Annotated + if origin is Annotated: + args = get_args(annotation) + base_type = args[0] + metadata = args[1:] + if isinstance(base_type, type) and issubclass(base_type, BaseModel): + # Replace the BaseModel subclass + base_type = new_type - return _Json + return Annotated[(base_type, *metadata)] + + # Handle Optionals, Unions, or other generic types + if origin in (Optional, Union, list, dict, tuple): # Extendable for other generics + new_args = tuple( + _replace_basemodel_in_annotation(arg, new_type) + for arg in get_args(annotation) + ) + return origin[new_args] + + # Replace BaseModel subclass directly + if isinstance(annotation, type) and issubclass(annotation, BaseModel): + return new_type + + # Return as-is if no changes + return annotation def as_query(model_class: type[BaseModel]) -> type[BaseModel]: fields = {} for field_name, field_info in model_class.model_fields.items(): - field_type = get_type(field_info) - default_value = field_info.default - - kwargs = { + field_default = field_info.default + assert not field_info.default_factory # nosec + query_kwargs = { "alias": field_info.alias, "title": field_info.title, "description": field_info.description, @@ -51,18 +61,18 @@ def as_query(model_class: type[BaseModel]) -> type[BaseModel]: "json_schema_extra": field_info.json_schema_extra, } - if issubclass(field_type, BaseModel): - # Complex fields - assert "json_schema_extra" in kwargs # nosec - assert kwargs["json_schema_extra"] # nosec - field_type = _create_json_type( - description=kwargs["description"], - example=kwargs.get("json_schema_extra", {}).get("example_json"), - ) + annotation = _replace_basemodel_in_annotation( + # NOTE: still missing description=query_kwargs["description"] and example=query_kwargs.get("json_schema_extra", {}).get("example_json") + # SEE https://github.com/ITISFoundation/osparc-simcore/issues/6786 + field_info.annotation, + new_type=Json, + ) - default_value = json_dumps(default_value) if default_value else None + if annotation != field_info.annotation: + # Complex fields are transformed to Json + field_default = json_dumps(field_default) if field_default else None - fields[field_name] = (field_type, Query(default=default_value, **kwargs)) + fields[field_name] = (annotation, Query(default=field_default, **query_kwargs)) new_model_name = f"{model_class.__name__}Query" return create_model(new_model_name, **fields) @@ -78,14 +88,15 @@ class Log(BaseModel): None, description="name of the logger receiving this message" ) - class Config: - schema_extra: ClassVar[dict[str, Any]] = { + model_config = ConfigDict( + json_schema_extra={ "example": { "message": "Hi there, Mr user", "level": "INFO", "logger": "user-logger", } } + ) class ErrorItem(BaseModel): @@ -106,48 +117,6 @@ class Error(BaseModel): status: int | None = Field(None, description="HTTP error code") -def create_openapi_specs( - app: FastAPI, - *, - drop_fastapi_default_422: bool = True, - remove_main_sections: bool = True, -): - override_fastapi_openapi_method(app) - openapi = app.openapi() - - # Remove these sections - if remove_main_sections: - for section in ("info", "openapi"): - openapi.pop(section, None) - - schemas = openapi["components"]["schemas"] - for section in ("HTTPValidationError", "ValidationError"): - schemas.pop(section, None) - - # Removes default response 422 - if drop_fastapi_default_422: - for method_item in openapi.get("paths", {}).values(): - for param in method_item.values(): - # NOTE: If description is like this, - # it assumes it is the default HTTPValidationError from fastapi - if (e422 := param.get("responses", {}).get("422", None)) and e422.get( - "description" - ) == "Validation Error": - param.get("responses", {}).pop("422", None) - return openapi - - -def create_and_save_openapi_specs( - app: FastAPI, file_path: Path, *, drop_fastapi_default_422: bool = True -): - openapi = create_openapi_specs( - app=app, drop_fastapi_default_422=drop_fastapi_default_422 - ) - with file_path.open("wt") as fh: - yaml.safe_dump(openapi, fh, indent=1, sort_keys=False) - print("Saved OAS to", file_path) # noqa: T201 - - class ParamSpec(NamedTuple): name: str annotated_type: type diff --git a/api/specs/web-server/_folders.py b/api/specs/web-server/_folders.py index c2e75579b26..f98b5e98308 100644 --- a/api/specs/web-server/_folders.py +++ b/api/specs/web-server/_folders.py @@ -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 @@ -38,7 +38,7 @@ status_code=status.HTTP_201_CREATED, ) async def create_folder( - _body: CreateFolderBodyParams, + _body: FolderCreateBodyParams, ): ... @@ -79,7 +79,7 @@ async def get_folder( ) async def replace_folder( _path: Annotated[FoldersPathParams, Depends()], - _body: PutFolderBodyParams, + _body: FolderReplaceBodyParams, ): ... diff --git a/api/specs/web-server/_publications.py b/api/specs/web-server/_publications.py index 7b9f8e0c51b..2d435b18545 100644 --- a/api/specs/web-server/_publications.py +++ b/api/specs/web-server/_publications.py @@ -16,8 +16,9 @@ status_code=status.HTTP_204_NO_CONTENT, ) def service_submission( - _file: Annotated[bytes, File(description="metadata.json submission file")] + file: Annotated[bytes, File(description="metadata.json submission file")] ): """ Submits files with new service candidate """ + assert file # nosec diff --git a/api/specs/web-server/_trash.py b/api/specs/web-server/_trash.py index 9aa23b8b288..6eb39f6593c 100644 --- a/api/specs/web-server/_trash.py +++ b/api/specs/web-server/_trash.py @@ -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( @@ -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()], ): ... @@ -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()], +): + ... diff --git a/api/specs/web-server/_workspaces.py b/api/specs/web-server/_workspaces.py index e3f1b4ebc5c..958b8457bca 100644 --- a/api/specs/web-server/_workspaces.py +++ b/api/specs/web-server/_workspaces.py @@ -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( @@ -32,15 +33,15 @@ ], ) -### 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, +): ... @@ -48,7 +49,9 @@ async def create_workspace(_body: CreateWorkspaceBodyParams): "/workspaces", response_model=Envelope[list[WorkspaceGet]], ) -async def list_workspaces(): +async def list_workspaces( + _query: Annotated[as_query(WorkspacesListQueryParams), Depends()], +): ... @@ -56,7 +59,9 @@ async def list_workspaces(): "/workspaces/{workspace_id}", response_model=Envelope[WorkspaceGet], ) -async def get_workspace(workspace_id: WorkspaceID): +async def get_workspace( + _path: Annotated[WorkspacesPathParams, Depends()], +): ... @@ -64,7 +69,10 @@ async def get_workspace(workspace_id: WorkspaceID): "/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, +): ... @@ -72,7 +80,9 @@ async def replace_workspace(workspace_id: WorkspaceID, _body: PutWorkspaceBodyPa "/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()], +): ... @@ -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, ): ... @@ -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()], +): ... @@ -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, ): ... @@ -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()], ): ... diff --git a/api/specs/web-server/openapi.py b/api/specs/web-server/openapi.py index 29a7bbedbab..c205153e506 100644 --- a/api/specs/web-server/openapi.py +++ b/api/specs/web-server/openapi.py @@ -6,9 +6,9 @@ import importlib import yaml -from _common import create_openapi_specs from fastapi import FastAPI from fastapi.routing import APIRoute +from servicelib.fastapi.openapi import create_openapi_specs from simcore_service_webserver._meta import API_VERSION, PROJECT_NAME, SUMMARY from simcore_service_webserver._resources import webserver_resources @@ -30,7 +30,7 @@ "_activity", "_announcements", "_catalog", - "_catalog_tags", # after _catalog + "_catalog_tags", # MUST BE after _catalog "_cluster", "_computations", "_exporter", diff --git a/api/specs/web-server/requirements.txt b/api/specs/web-server/requirements.txt index 45bdbf97568..62bea8dd0a9 100644 --- a/api/specs/web-server/requirements.txt +++ b/api/specs/web-server/requirements.txt @@ -1,5 +1,9 @@ # Extra reqs, besides webserver's -fastapi==0.96.0 +--constraint ../../../requirements/constraints.txt + +fastapi jsonref +pydantic +pydantic-extra-types python-multipart diff --git a/api/tests/test_conventions_openapi.py b/api/tests/test_conventions_openapi.py index 18129abad6e..bb1f2d9f893 100644 --- a/api/tests/test_conventions_openapi.py +++ b/api/tests/test_conventions_openapi.py @@ -7,7 +7,6 @@ import pytest import yaml from utils import list_files_in_api_specs -from yarl import URL # Conventions _REQUIRED_FIELDS = [ @@ -42,29 +41,3 @@ def test_openapi_envelope_required_fields(path: Path): assert "error" in required_fields or "data" in required_fields assert "error" in fields_definitions or "data" in fields_definitions - - -main_openapi_yamls = [ - pathstr - for pathstr in list_files_in_api_specs("openapi.y*ml") - if not f"{pathstr}".endswith(CONVERTED_SUFFIX) and ("director" not in f"{pathstr}") -] # skip converted schemas and director - -assert main_openapi_yamls - - -@pytest.mark.parametrize( - "openapi_path", main_openapi_yamls, ids=lambda p: p.parent.name -) -def test_versioning_and_basepath(openapi_path: Path): - # version in folder name is only major! - with openapi_path.open() as f: - oas_dict = yaml.safe_load(f) - - # basepath in servers must also be as '/v0' - for server in oas_dict["servers"]: - kwargs = { - key: value["default"] for key, value in server.get("variables", {}).items() - } - url = URL(server["url"].format(**kwargs)) - assert url.path == "/", "Wrong basepath in server: %s" % server diff --git a/packages/models-library/src/models_library/api_schemas_directorv2/clusters.py b/packages/models-library/src/models_library/api_schemas_directorv2/clusters.py index 0539ec5a3eb..35513ace551 100644 --- a/packages/models-library/src/models_library/api_schemas_directorv2/clusters.py +++ b/packages/models-library/src/models_library/api_schemas_directorv2/clusters.py @@ -1,4 +1,4 @@ -from typing import Any, TypeAlias +from typing import Annotated, Any, TypeAlias from pydantic import ( AnyHttpUrl, @@ -92,11 +92,23 @@ class ClusterDetails(BaseModel): class ClusterGet(Cluster): - access_rights: dict[GroupID, ClusterAccessRights] = Field( - alias="accessRights", default_factory=dict - ) + access_rights: Annotated[ + dict[GroupID, ClusterAccessRights], + Field( + alias="accessRights", + default_factory=dict, + json_schema_extra={"default": {}}, + ), + ] - model_config = ConfigDict(extra="allow", populate_by_name=True) + model_config = ConfigDict( + extra="allow", + populate_by_name=True, + json_schema_extra={ + # NOTE: make openapi-specs fails because + # Cluster.model_config.json_schema_extra is raises `TypeError: unhashable type: 'ClusterAccessRights'` + }, + ) @model_validator(mode="before") @classmethod diff --git a/packages/models-library/src/models_library/api_schemas_webserver/catalog.py b/packages/models-library/src/models_library/api_schemas_webserver/catalog.py index 09bfa36499a..c6f56597327 100644 --- a/packages/models-library/src/models_library/api_schemas_webserver/catalog.py +++ b/packages/models-library/src/models_library/api_schemas_webserver/catalog.py @@ -228,8 +228,7 @@ class ServiceGet(api_schemas_catalog_services.ServiceGet): ) -class ServiceResourcesGet(api_schemas_catalog_services.ServiceResourcesGet): - model_config = OutputSchema.model_config +ServiceResourcesGet: TypeAlias = api_schemas_catalog_services.ServiceResourcesGet class CatalogServiceGet(api_schemas_catalog_services.ServiceGetV2): diff --git a/packages/models-library/src/models_library/api_schemas_webserver/folders_v2.py b/packages/models-library/src/models_library/api_schemas_webserver/folders_v2.py index cd574893d94..4a88532848a 100644 --- a/packages/models-library/src/models_library/api_schemas_webserver/folders_v2.py +++ b/packages/models-library/src/models_library/api_schemas_webserver/folders_v2.py @@ -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 @@ -44,7 +44,7 @@ class CreateFolderBodyParams(InputSchema): )(null_or_none_str_to_none_validator) -class PutFolderBodyParams(InputSchema): +class FolderReplaceBodyParams(InputSchema): name: IDStr parent_folder_id: FolderID | None = None model_config = ConfigDict(extra="forbid") diff --git a/packages/models-library/src/models_library/api_schemas_webserver/workspaces.py b/packages/models-library/src/models_library/api_schemas_webserver/workspaces.py index 32f17200ee4..73fb684d3aa 100644 --- a/packages/models-library/src/models_library/api_schemas_webserver/workspaces.py +++ b/packages/models-library/src/models_library/api_schemas_webserver/workspaces.py @@ -7,6 +7,7 @@ from pydantic import ConfigDict, PositiveInt from ..access_rights import AccessRights +from ..users import UserID from ._base import InputSchema, OutputSchema @@ -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] @@ -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 @@ -34,7 +37,7 @@ class CreateWorkspaceBodyParams(InputSchema): model_config = ConfigDict(extra="forbid") -class PutWorkspaceBodyParams(InputSchema): +class WorkspaceReplaceBodyParams(InputSchema): name: IDStr description: str | None = None thumbnail: str | None = None diff --git a/packages/models-library/src/models_library/rest_filters.py b/packages/models-library/src/models_library/rest_filters.py index 1527a2e6170..c6edfb730ad 100644 --- a/packages/models-library/src/models_library/rest_filters.py +++ b/packages/models-library/src/models_library/rest_filters.py @@ -1,6 +1,8 @@ -from typing import Generic, TypeVar +from typing import Annotated, Generic, TypeVar -from pydantic import BaseModel, Field, Json +from pydantic import BaseModel, BeforeValidator, Field + +from .utils.common_validators import parse_json_pre_validator class Filters(BaseModel): @@ -15,7 +17,9 @@ class Filters(BaseModel): class FiltersQueryParameters(BaseModel, Generic[FilterT]): - filters: Json[FilterT] | None = Field( # pylint: disable=unsubscriptable-object + filters: Annotated[ + FilterT | None, BeforeValidator(parse_json_pre_validator) + ] = Field( # pylint: disable=unsubscriptable-object default=None, description="Custom filter query parameter encoded as JSON", ) diff --git a/packages/models-library/src/models_library/trash.py b/packages/models-library/src/models_library/trash.py new file mode 100644 index 00000000000..306787ab60f --- /dev/null +++ b/packages/models-library/src/models_library/trash.py @@ -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)" + ) diff --git a/packages/models-library/src/models_library/workspaces.py b/packages/models-library/src/models_library/workspaces.py index 5d1d206e8dd..6c34efbf790 100644 --- a/packages/models-library/src/models_library/workspaces.py +++ b/packages/models-library/src/models_library/workspaces.py @@ -12,7 +12,7 @@ ) from .access_rights import AccessRights -from .users import GroupID +from .users import GroupID, UserID from .utils.enums import StrAutoEnum WorkspaceID: TypeAlias = PositiveInt @@ -33,10 +33,10 @@ class WorkspaceQuery(BaseModel): def validate_workspace_id(cls, value, info: ValidationInfo): scope = info.data.get("workspace_scope") if scope == WorkspaceScope.SHARED and value is None: - msg = "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: - msg = "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 @@ -63,6 +63,8 @@ class WorkspaceDB(BaseModel): ..., description="Timestamp of last modification", ) + trashed: datetime | None + trashed_by: UserID | None model_config = ConfigDict(from_attributes=True) @@ -72,3 +74,11 @@ class UserWorkspaceAccessRightsDB(WorkspaceDB): access_rights: dict[GroupID, AccessRights] model_config = ConfigDict(from_attributes=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 diff --git a/packages/postgres-database/src/simcore_postgres_database/migration/versions/c9db8bf5091e_trash_columns_in_workspaces.py b/packages/postgres-database/src/simcore_postgres_database/migration/versions/c9db8bf5091e_trash_columns_in_workspaces.py new file mode 100644 index 00000000000..b61a9e21009 --- /dev/null +++ b/packages/postgres-database/src/simcore_postgres_database/migration/versions/c9db8bf5091e_trash_columns_in_workspaces.py @@ -0,0 +1,57 @@ +"""trash columns in workspaces + +Revision ID: c9db8bf5091e +Revises: 8e1f83486be7 +Create Date: 2024-11-20 16:42:43.784855+00:00 + +""" +import sqlalchemy as sa +from alembic import op + +# revision identifiers, used by Alembic. +revision = "c9db8bf5091e" +down_revision = "8e1f83486be7" +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column( + "workspaces", + sa.Column( + "trashed", + sa.DateTime(timezone=True), + nullable=True, + comment="The date and time when the workspace was marked as trashed. Null if the workspace has not been trashed [default].", + ), + ) + op.add_column( + "workspaces", + sa.Column( + "trashed_by", + sa.BigInteger(), + nullable=True, + comment="User who trashed the workspace, or null if not trashed or user is unknown.", + ), + ) + op.create_foreign_key( + "fk_workspace_trashed_by_user_id", + "workspaces", + "users", + ["trashed_by"], + ["id"], + onupdate="CASCADE", + ondelete="SET NULL", + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_constraint( + "fk_workspace_trashed_by_user_id", "workspaces", type_="foreignkey" + ) + op.drop_column("workspaces", "trashed_by") + op.drop_column("workspaces", "trashed") + # ### end Alembic commands ### diff --git a/packages/postgres-database/src/simcore_postgres_database/models/_common.py b/packages/postgres-database/src/simcore_postgres_database/models/_common.py index c3f671d244a..47bfeb6ebf0 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/_common.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/_common.py @@ -5,6 +5,17 @@ from ..constants import DECIMAL_PLACES +class RefActions: + """Referential actions for `ON UPDATE`, `ON DELETE`""" + + # SEE https://docs.sqlalchemy.org/en/20/core/constraints.html#on-update-on-delete + CASCADE: Final[str] = "CASCADE" + SET_NULL: Final[str] = "SET NULL" + SET_DEFAULT: Final[str] = "SET DEFAULT" + RESTRICT: Final[str] = "RESTRICT" + NO_ACTION: Final[str] = "NO ACTION" + + def column_created_datetime(*, timezone: bool = True) -> sa.Column: return sa.Column( "created", @@ -34,8 +45,8 @@ def column_created_by_user( sa.Integer, sa.ForeignKey( users_table.c.id, - onupdate="CASCADE", - ondelete="SET NULL", + onupdate=RefActions.CASCADE, + ondelete=RefActions.SET_NULL, ), nullable=not required, doc="Who created this row at `created`", @@ -50,14 +61,39 @@ def column_modified_by_user( sa.Integer, sa.ForeignKey( users_table.c.id, - onupdate="CASCADE", - ondelete="SET NULL", + onupdate=RefActions.CASCADE, + ondelete=RefActions.SET_NULL, ), nullable=not required, doc="Who modified this row at `modified`", ) +def column_trashed_datetime(resource_name: str) -> sa.Column: + return sa.Column( + "trashed", + sa.DateTime(timezone=True), + nullable=True, + comment=f"The date and time when the {resource_name} was marked as trashed. " + f"Null if the {resource_name} has not been trashed [default].", + ) + + +def column_trashed_by_user(resource_name: str, users_table: sa.Table) -> sa.Column: + return sa.Column( + "trashed_by", + sa.BigInteger, + sa.ForeignKey( + users_table.c.id, + onupdate=RefActions.CASCADE, + ondelete=RefActions.SET_NULL, + name=f"fk_{resource_name}_trashed_by_user_id", + ), + nullable=True, + comment=f"User who trashed the {resource_name}, or null if not trashed or user is unknown.", + ) + + _TRIGGER_NAME: Final[str] = "auto_update_modified_timestamp" diff --git a/packages/postgres-database/src/simcore_postgres_database/models/api_keys.py b/packages/postgres-database/src/simcore_postgres_database/models/api_keys.py index 5db5416b677..416e29d4e2d 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/api_keys.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/api_keys.py @@ -13,6 +13,7 @@ import sqlalchemy as sa from sqlalchemy.sql import func +from ._common import RefActions from .base import metadata from .users import users @@ -35,7 +36,7 @@ sa.Column( "user_id", sa.BigInteger(), - sa.ForeignKey(users.c.id, ondelete="CASCADE"), + sa.ForeignKey(users.c.id, ondelete=RefActions.CASCADE), nullable=False, doc="Identified user", ), @@ -44,8 +45,8 @@ sa.String, sa.ForeignKey( "products.name", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, name="fk_api_keys_product_name", ), nullable=False, diff --git a/packages/postgres-database/src/simcore_postgres_database/models/classifiers.py b/packages/postgres-database/src/simcore_postgres_database/models/classifiers.py index 238c7b04f8c..7e4a2cf39df 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/classifiers.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/classifiers.py @@ -11,6 +11,7 @@ from sqlalchemy.dialects.postgresql import JSONB from sqlalchemy.sql import func +from ._common import RefActions from .base import metadata group_classifiers = sa.Table( @@ -32,8 +33,8 @@ sa.ForeignKey( "groups.gid", name="fk_group_classifiers_gid_to_groups_gid", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), unique=True, # Every Group can ONLY have one set of classifiers ), diff --git a/packages/postgres-database/src/simcore_postgres_database/models/cluster_to_groups.py b/packages/postgres-database/src/simcore_postgres_database/models/cluster_to_groups.py index 6f563926200..63996c1404b 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/cluster_to_groups.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/cluster_to_groups.py @@ -1,6 +1,7 @@ import sqlalchemy as sa from sqlalchemy.sql import expression, func +from ._common import RefActions from .base import metadata from .clusters import clusters from .groups import groups @@ -14,8 +15,8 @@ sa.ForeignKey( clusters.c.id, name="fk_cluster_to_groups_id_clusters", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), doc="Cluster unique ID", ), @@ -25,8 +26,8 @@ sa.ForeignKey( groups.c.gid, name="fk_cluster_to_groups_gid_groups", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), doc="Group unique IDentifier", ), diff --git a/packages/postgres-database/src/simcore_postgres_database/models/clusters.py b/packages/postgres-database/src/simcore_postgres_database/models/clusters.py index a4ddc53123c..39536ae241b 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/clusters.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/clusters.py @@ -4,6 +4,7 @@ from sqlalchemy.dialects.postgresql import JSONB from sqlalchemy.sql import func +from ._common import RefActions from .base import metadata @@ -36,8 +37,8 @@ class ClusterType(Enum): sa.ForeignKey( "groups.gid", name="fk_clusters_gid_groups", - onupdate="CASCADE", - ondelete="RESTRICT", + onupdate=RefActions.CASCADE, + ondelete=RefActions.RESTRICT, ), nullable=False, doc="Identifier of the group that owns this cluster", diff --git a/packages/postgres-database/src/simcore_postgres_database/models/comp_runs.py b/packages/postgres-database/src/simcore_postgres_database/models/comp_runs.py index eb84cefaa76..3975cb91eee 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/comp_runs.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/comp_runs.py @@ -5,6 +5,7 @@ from sqlalchemy.dialects.postgresql import JSONB from sqlalchemy.sql import func +from ._common import RefActions from .base import metadata from .comp_pipeline import StateType @@ -26,8 +27,8 @@ sa.ForeignKey( "projects.uuid", name="fk_comp_runs_project_uuid_projects", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), nullable=False, doc="The project uuid with which the run entry is associated", @@ -38,8 +39,8 @@ sa.ForeignKey( "users.id", name="fk_comp_runs_user_id_users", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), nullable=False, doc="The user id with which the run entry is associated", @@ -50,8 +51,8 @@ sa.ForeignKey( "clusters.id", name="fk_comp_runs_cluster_id_clusters", - onupdate="CASCADE", - ondelete="SET NULL", + onupdate=RefActions.CASCADE, + ondelete=RefActions.SET_NULL, ), nullable=True, doc="The cluster id on which the run entry is associated, if NULL or 0 uses the default", diff --git a/packages/postgres-database/src/simcore_postgres_database/models/confirmations.py b/packages/postgres-database/src/simcore_postgres_database/models/confirmations.py index 3b9b1274804..6fd56e8c8e0 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/confirmations.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/confirmations.py @@ -9,6 +9,7 @@ import sqlalchemy as sa +from ._common import RefActions from .base import metadata from .users import users @@ -57,6 +58,9 @@ class ConfirmationAction(enum.Enum): # constraints ---------------- sa.PrimaryKeyConstraint("code", name="confirmation_code"), sa.ForeignKeyConstraint( - ["user_id"], [users.c.id], name="user_confirmation_fkey", ondelete="CASCADE" + ["user_id"], + [users.c.id], + name="user_confirmation_fkey", + ondelete=RefActions.CASCADE, ), ) diff --git a/packages/postgres-database/src/simcore_postgres_database/models/folders_v2.py b/packages/postgres-database/src/simcore_postgres_database/models/folders_v2.py index fcad0ada76c..78f3de8bdf9 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/folders_v2.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/folders_v2.py @@ -1,7 +1,7 @@ import sqlalchemy as sa from sqlalchemy.sql import expression -from ._common import column_created_datetime, column_modified_datetime +from ._common import RefActions, column_created_datetime, column_modified_datetime from .base import metadata from .workspaces import workspaces @@ -35,8 +35,8 @@ sa.String, sa.ForeignKey( "products.name", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, name="fk_new_folders_to_products_name", ), nullable=False, @@ -46,8 +46,8 @@ sa.BigInteger, sa.ForeignKey( "users.id", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, name="fk_folders_to_user_id", ), nullable=True, @@ -57,8 +57,8 @@ sa.BigInteger, sa.ForeignKey( workspaces.c.workspace_id, - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, name="fk_folders_to_workspace_id", ), nullable=True, @@ -69,7 +69,7 @@ sa.ForeignKey( "groups.gid", name="fk_new_folders_to_groups_gid", - ondelete="SET NULL", + ondelete=RefActions.SET_NULL, ), nullable=True, ), diff --git a/packages/postgres-database/src/simcore_postgres_database/models/groups.py b/packages/postgres-database/src/simcore_postgres_database/models/groups.py index 0aec758a6c6..a70e9fa8db4 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/groups.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/groups.py @@ -10,6 +10,7 @@ from sqlalchemy.dialects.postgresql import JSONB from sqlalchemy.sql import func +from ._common import RefActions from .base import metadata @@ -86,8 +87,8 @@ class GroupType(enum.Enum): sa.ForeignKey( "users.id", name="fk_user_to_groups_id_users", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), doc="User unique IDentifier", ), @@ -97,8 +98,8 @@ class GroupType(enum.Enum): sa.ForeignKey( "groups.gid", name="fk_user_to_groups_gid_groups", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), doc="Group unique IDentifier", ), diff --git a/packages/postgres-database/src/simcore_postgres_database/models/groups_extra_properties.py b/packages/postgres-database/src/simcore_postgres_database/models/groups_extra_properties.py index 93ffe8cd7f7..e25a1bd3b2b 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/groups_extra_properties.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/groups_extra_properties.py @@ -1,21 +1,19 @@ import sqlalchemy as sa -from ._common import column_created_datetime, column_modified_datetime +from ._common import RefActions, column_created_datetime, column_modified_datetime from .base import metadata -# -# groups_extra_properties: Maps internet access permissions to groups -# groups_extra_properties = sa.Table( "groups_extra_properties", + # groups_extra_properties: Maps internet access permissions to groups metadata, sa.Column( "group_id", sa.BigInteger, sa.ForeignKey( "groups.gid", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, name="fk_groups_extra_properties_to_group_group_id", ), nullable=False, @@ -26,8 +24,8 @@ sa.VARCHAR, sa.ForeignKey( "products.name", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, name="fk_groups_extra_properties_to_products_name", ), nullable=False, diff --git a/packages/postgres-database/src/simcore_postgres_database/models/payments_autorecharge.py b/packages/postgres-database/src/simcore_postgres_database/models/payments_autorecharge.py index 3b46e217fcc..df30251c50c 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/payments_autorecharge.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/payments_autorecharge.py @@ -2,6 +2,7 @@ from ._common import ( NUMERIC_KWARGS, + RefActions, column_created_datetime, column_modified_datetime, register_modified_datetime_auto_update_trigger, @@ -49,8 +50,8 @@ sa.ForeignKey( payments_methods.c.payment_method_id, name="fk_payments_autorecharge_primary_payment_method_id", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), nullable=False, unique=True, diff --git a/packages/postgres-database/src/simcore_postgres_database/models/products.py b/packages/postgres-database/src/simcore_postgres_database/models/products.py index 70ed22911d7..344326fbf48 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/products.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/products.py @@ -15,6 +15,7 @@ TypedDict, ) +from ._common import RefActions from .base import metadata from .groups import groups from .jinja2_templates import jinja2_templates @@ -199,8 +200,8 @@ class ProductLoginSettingsDict(TypedDict, total=False): sa.ForeignKey( jinja2_templates.c.name, name="fk_jinja2_templates_name", - ondelete="SET NULL", - onupdate="CASCADE", + ondelete=RefActions.SET_NULL, + onupdate=RefActions.CASCADE, ), nullable=True, doc="Custom jinja2 template for registration email", @@ -238,8 +239,8 @@ class ProductLoginSettingsDict(TypedDict, total=False): sa.ForeignKey( groups.c.gid, name="fk_products_group_id", - ondelete="SET NULL", - onupdate="CASCADE", + ondelete=RefActions.SET_NULL, + onupdate=RefActions.CASCADE, ), unique=True, nullable=True, diff --git a/packages/postgres-database/src/simcore_postgres_database/models/products_prices.py b/packages/postgres-database/src/simcore_postgres_database/models/products_prices.py index 2784969149b..b0b652cd310 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/products_prices.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/products_prices.py @@ -1,6 +1,6 @@ import sqlalchemy as sa -from ._common import NUMERIC_KWARGS +from ._common import NUMERIC_KWARGS, RefActions from .base import metadata from .products import products @@ -20,8 +20,8 @@ sa.ForeignKey( products.c.name, name="fk_products_prices_product_name", - ondelete="RESTRICT", - onupdate="CASCADE", + ondelete=RefActions.RESTRICT, + onupdate=RefActions.CASCADE, ), nullable=False, doc="Product name", diff --git a/packages/postgres-database/src/simcore_postgres_database/models/products_to_templates.py b/packages/postgres-database/src/simcore_postgres_database/models/products_to_templates.py index 4236d95864e..44115660735 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/products_to_templates.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/products_to_templates.py @@ -1,6 +1,7 @@ import sqlalchemy as sa from ._common import ( + RefActions, column_created_datetime, column_modified_datetime, register_modified_datetime_auto_update_trigger, @@ -16,8 +17,8 @@ sa.String, sa.ForeignKey( "products.name", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, name="fk_products_to_templates_product_name", ), nullable=False, @@ -28,8 +29,8 @@ sa.ForeignKey( jinja2_templates.c.name, name="fk_products_to_templates_template_name", - ondelete="CASCADE", - onupdate="CASCADE", + ondelete=RefActions.CASCADE, + onupdate=RefActions.CASCADE, ), nullable=True, doc="Custom jinja2 template", diff --git a/packages/postgres-database/src/simcore_postgres_database/models/project_to_groups.py b/packages/postgres-database/src/simcore_postgres_database/models/project_to_groups.py index f27c6081f6c..162a51d4d24 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/project_to_groups.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/project_to_groups.py @@ -1,7 +1,7 @@ import sqlalchemy as sa from sqlalchemy.sql import expression -from ._common import column_created_datetime, column_modified_datetime +from ._common import RefActions, column_created_datetime, column_modified_datetime from .base import metadata from .groups import groups from .projects import projects @@ -15,8 +15,8 @@ sa.ForeignKey( projects.c.uuid, name="fk_project_to_groups_project_uuid", - ondelete="CASCADE", - onupdate="CASCADE", + ondelete=RefActions.CASCADE, + onupdate=RefActions.CASCADE, ), index=True, nullable=False, @@ -28,8 +28,8 @@ sa.ForeignKey( groups.c.gid, name="fk_project_to_groups_gid_groups", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), nullable=False, doc="Group unique IDentifier", diff --git a/packages/postgres-database/src/simcore_postgres_database/models/projects.py b/packages/postgres-database/src/simcore_postgres_database/models/projects.py index 778d2b80eb5..93ff3a74ea3 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/projects.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/projects.py @@ -7,6 +7,7 @@ from sqlalchemy.dialects.postgresql import ARRAY, JSONB from sqlalchemy.sql import expression, func +from ._common import RefActions from .base import metadata @@ -64,8 +65,8 @@ class ProjectType(enum.Enum): sa.ForeignKey( "users.id", name="fk_projects_prj_owner_users", - onupdate="CASCADE", - ondelete="RESTRICT", + onupdate=RefActions.CASCADE, + ondelete=RefActions.RESTRICT, ), nullable=True, doc="Project's owner", @@ -161,8 +162,8 @@ class ProjectType(enum.Enum): sa.BigInteger, sa.ForeignKey( "workspaces.workspace_id", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, name="fk_projects_to_workspaces_id", ), nullable=True, diff --git a/packages/postgres-database/src/simcore_postgres_database/models/projects_comments.py b/packages/postgres-database/src/simcore_postgres_database/models/projects_comments.py index fb07f56a202..919b143bff3 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/projects_comments.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/projects_comments.py @@ -1,6 +1,6 @@ import sqlalchemy as sa -from ._common import column_created_datetime, column_modified_datetime +from ._common import RefActions, column_created_datetime, column_modified_datetime from .base import metadata from .projects import projects from .users import users @@ -22,8 +22,8 @@ sa.ForeignKey( projects.c.uuid, name="fk_projects_comments_project_uuid", - ondelete="CASCADE", - onupdate="CASCADE", + ondelete=RefActions.CASCADE, + onupdate=RefActions.CASCADE, ), index=True, nullable=False, @@ -36,7 +36,7 @@ sa.ForeignKey( users.c.id, name="fk_projects_comments_user_id", - ondelete="SET NULL", + ondelete=RefActions.SET_NULL, ), doc="user who created the comment", nullable=True, diff --git a/packages/postgres-database/src/simcore_postgres_database/models/projects_metadata.py b/packages/postgres-database/src/simcore_postgres_database/models/projects_metadata.py index b2d2d4f640a..c5379f407d4 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/projects_metadata.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/projects_metadata.py @@ -7,6 +7,7 @@ from sqlalchemy.dialects.postgresql import JSONB from ._common import ( + RefActions, column_created_datetime, column_modified_datetime, register_modified_datetime_auto_update_trigger, @@ -42,8 +43,8 @@ sa.String, sa.ForeignKey( projects.c.uuid, - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, name="fk_projects_metadata_project_uuid", ), nullable=False, @@ -88,15 +89,15 @@ sa.ForeignKeyConstraint( ("parent_project_uuid", "parent_node_id"), (projects_nodes.c.project_uuid, projects_nodes.c.node_id), - onupdate="CASCADE", - ondelete="SET NULL", + onupdate=RefActions.CASCADE, + ondelete=RefActions.SET_NULL, name="fk_projects_metadata_parent_node_id", ), sa.ForeignKeyConstraint( ("root_parent_project_uuid", "root_parent_node_id"), (projects_nodes.c.project_uuid, projects_nodes.c.node_id), - onupdate="CASCADE", - ondelete="SET NULL", + onupdate=RefActions.CASCADE, + ondelete=RefActions.SET_NULL, name="fk_projects_metadata_root_parent_node_id", ), ) diff --git a/packages/postgres-database/src/simcore_postgres_database/models/projects_networks.py b/packages/postgres-database/src/simcore_postgres_database/models/projects_networks.py index efac321a539..905c1aa4cf0 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/projects_networks.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/projects_networks.py @@ -1,6 +1,7 @@ import sqlalchemy as sa from sqlalchemy.dialects.postgresql import JSONB +from ._common import RefActions from .base import metadata from .projects import projects @@ -13,8 +14,8 @@ sa.ForeignKey( projects.c.uuid, name="fk_projects_networks_project_uuid_projects", - ondelete="CASCADE", - onupdate="CASCADE", + ondelete=RefActions.CASCADE, + onupdate=RefActions.CASCADE, ), primary_key=True, doc="project reference and primary key for this table", diff --git a/packages/postgres-database/src/simcore_postgres_database/models/projects_node_to_pricing_unit.py b/packages/postgres-database/src/simcore_postgres_database/models/projects_node_to_pricing_unit.py index aa0e42a35a3..903466c3f93 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/projects_node_to_pricing_unit.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/projects_node_to_pricing_unit.py @@ -7,6 +7,7 @@ import sqlalchemy as sa from ._common import ( + RefActions, column_created_datetime, column_modified_datetime, register_modified_datetime_auto_update_trigger, @@ -22,8 +23,8 @@ sa.BIGINT, sa.ForeignKey( projects_nodes.c.project_node_id, - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, name="fk_projects_nodes__project_node_to_pricing_unit__uuid", ), nullable=False, diff --git a/packages/postgres-database/src/simcore_postgres_database/models/projects_nodes.py b/packages/postgres-database/src/simcore_postgres_database/models/projects_nodes.py index 1da6f138cdb..f4b569270c4 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/projects_nodes.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/projects_nodes.py @@ -8,6 +8,7 @@ from sqlalchemy.dialects.postgresql import JSONB from ._common import ( + RefActions, column_created_datetime, column_modified_datetime, register_modified_datetime_auto_update_trigger, @@ -31,8 +32,8 @@ sa.String, sa.ForeignKey( projects.c.uuid, - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, name="fk_projects_to_projects_nodes_to_projects_uuid", ), nullable=False, diff --git a/packages/postgres-database/src/simcore_postgres_database/models/projects_tags.py b/packages/postgres-database/src/simcore_postgres_database/models/projects_tags.py index 223271872b7..3507fc8d239 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/projects_tags.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/projects_tags.py @@ -1,5 +1,6 @@ import sqlalchemy as sa +from ._common import RefActions from .base import metadata from .projects import projects from .tags import tags @@ -15,8 +16,8 @@ sa.BigInteger, sa.ForeignKey( projects.c.id, - onupdate="CASCADE", - ondelete="SET NULL", + onupdate=RefActions.CASCADE, + ondelete=RefActions.SET_NULL, name="project_tags_project_id_fkey", ), nullable=True, # <-- NULL means that project was deleted @@ -25,7 +26,9 @@ sa.Column( "tag_id", sa.BigInteger, - sa.ForeignKey(tags.c.id, onupdate="CASCADE", ondelete="CASCADE"), + sa.ForeignKey( + tags.c.id, onupdate=RefActions.CASCADE, ondelete=RefActions.CASCADE + ), nullable=False, ), sa.Column( diff --git a/packages/postgres-database/src/simcore_postgres_database/models/projects_to_folders.py b/packages/postgres-database/src/simcore_postgres_database/models/projects_to_folders.py index ba2b7334621..f86725a8119 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/projects_to_folders.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/projects_to_folders.py @@ -1,6 +1,6 @@ import sqlalchemy as sa -from ._common import column_created_datetime, column_modified_datetime +from ._common import RefActions, column_created_datetime, column_modified_datetime from .base import metadata from .folders_v2 import folders_v2 @@ -13,8 +13,8 @@ sa.ForeignKey( "projects.uuid", name="fk_projects_to_folders_to_projects_uuid", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), ), sa.Column( @@ -23,8 +23,8 @@ sa.ForeignKey( folders_v2.c.folder_id, name="fk_projects_to_folders_to_folders_id", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), ), sa.Column( @@ -32,8 +32,8 @@ sa.BigInteger, sa.ForeignKey( "users.id", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, name="fk_projects_to_folders_to_user_id", ), nullable=True, diff --git a/packages/postgres-database/src/simcore_postgres_database/models/projects_to_products.py b/packages/postgres-database/src/simcore_postgres_database/models/projects_to_products.py index e6a1d1cd530..47a430f0a00 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/projects_to_products.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/projects_to_products.py @@ -1,6 +1,6 @@ import sqlalchemy as sa -from ._common import column_created_datetime, column_modified_datetime +from ._common import RefActions, column_created_datetime, column_modified_datetime from .base import metadata projects_to_products = sa.Table( @@ -11,8 +11,8 @@ sa.String, sa.ForeignKey( "projects.uuid", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, name="fk_projects_to_products_product_uuid", ), nullable=False, @@ -23,8 +23,8 @@ sa.String, sa.ForeignKey( "products.name", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, name="fk_projects_to_products_product_name", ), nullable=False, diff --git a/packages/postgres-database/src/simcore_postgres_database/models/projects_to_wallet.py b/packages/postgres-database/src/simcore_postgres_database/models/projects_to_wallet.py index dfe3108a845..74e7a7ef635 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/projects_to_wallet.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/projects_to_wallet.py @@ -1,6 +1,6 @@ import sqlalchemy as sa -from ._common import column_created_datetime, column_modified_datetime +from ._common import RefActions, column_created_datetime, column_modified_datetime from .base import metadata from .projects import projects from .wallets import wallets @@ -14,8 +14,8 @@ sa.ForeignKey( projects.c.uuid, name="fk_projects_comments_project_uuid", - ondelete="CASCADE", - onupdate="CASCADE", + ondelete=RefActions.CASCADE, + onupdate=RefActions.CASCADE, ), index=True, primary_key=True, @@ -28,8 +28,8 @@ sa.ForeignKey( wallets.c.wallet_id, name="fk_projects_wallet_wallets_id", - ondelete="CASCADE", - onupdate="CASCADE", + ondelete=RefActions.CASCADE, + onupdate=RefActions.CASCADE, ), nullable=False, ), diff --git a/packages/postgres-database/src/simcore_postgres_database/models/projects_version_control.py b/packages/postgres-database/src/simcore_postgres_database/models/projects_version_control.py index c0fd0816e51..7d183f03942 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/projects_version_control.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/projects_version_control.py @@ -6,6 +6,7 @@ from sqlalchemy.dialects.postgresql import JSONB from sqlalchemy.sql import func +from ._common import RefActions from .base import metadata from .projects import projects @@ -32,8 +33,8 @@ sa.ForeignKey( projects.c.uuid, name="fk_projects_vc_repos_project_uuid", - ondelete="CASCADE", # if project is deleted, all references in project_vc_* tables are deleted except for projects_vc_snapshots. - onupdate="CASCADE", + ondelete=RefActions.CASCADE, # if project is deleted, all references in project_vc_* tables are deleted except for projects_vc_snapshots. + onupdate=RefActions.CASCADE, ), nullable=False, unique=True, @@ -113,8 +114,8 @@ sa.ForeignKey( projects_vc_repos.c.id, name="fk_projects_vc_commits_repo_id", - ondelete="CASCADE", - onupdate="CASCADE", + ondelete=RefActions.CASCADE, + onupdate=RefActions.CASCADE, ), nullable=False, doc="Repository to which this commit belongs", @@ -125,7 +126,7 @@ sa.ForeignKey( "projects_vc_commits.id", name="fk_projects_vc_commits_parent_commit_id", - onupdate="CASCADE", + onupdate=RefActions.CASCADE, ), nullable=True, doc="Preceding commit", @@ -136,8 +137,8 @@ sa.ForeignKey( projects_vc_snapshots.c.checksum, name="fk_projects_vc_commits_snapshot_checksum", - ondelete="RESTRICT", - onupdate="CASCADE", + ondelete=RefActions.RESTRICT, + onupdate=RefActions.CASCADE, ), nullable=False, doc="SHA-1 checksum of snapshot." @@ -175,8 +176,8 @@ sa.ForeignKey( projects_vc_repos.c.id, name="fk_projects_vc_tags_repo_id", - ondelete="CASCADE", - onupdate="CASCADE", + ondelete=RefActions.CASCADE, + onupdate=RefActions.CASCADE, ), nullable=False, doc="Repository to which this commit belongs", @@ -187,8 +188,8 @@ sa.ForeignKey( projects_vc_commits.c.id, name="fk_projects_vc_tags_commit_id", - ondelete="CASCADE", - onupdate="CASCADE", + ondelete=RefActions.CASCADE, + onupdate=RefActions.CASCADE, ), nullable=False, doc="Points to the tagged commit", @@ -243,8 +244,8 @@ sa.ForeignKey( projects_vc_repos.c.id, name="projects_vc_branches_repo_id", - ondelete="CASCADE", - onupdate="CASCADE", + ondelete=RefActions.CASCADE, + onupdate=RefActions.CASCADE, ), nullable=False, doc="Repository to which this branch belongs", @@ -255,8 +256,8 @@ sa.ForeignKey( projects_vc_commits.c.id, name="fk_projects_vc_branches_head_commit_id", - ondelete="RESTRICT", - onupdate="CASCADE", + ondelete=RefActions.RESTRICT, + onupdate=RefActions.CASCADE, ), nullable=True, doc="Points to the head commit of this branchNull heads are detached", @@ -299,8 +300,8 @@ sa.ForeignKey( projects_vc_repos.c.id, name="projects_vc_branches_repo_id", - ondelete="CASCADE", - onupdate="CASCADE", + ondelete=RefActions.CASCADE, + onupdate=RefActions.CASCADE, ), primary_key=True, nullable=False, @@ -312,8 +313,8 @@ sa.ForeignKey( projects_vc_branches.c.id, name="fk_projects_vc_heads_head_branch_id", - ondelete="CASCADE", - onupdate="CASCADE", + ondelete=RefActions.CASCADE, + onupdate=RefActions.CASCADE, ), unique=True, nullable=True, diff --git a/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_credit_transactions.py b/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_credit_transactions.py index d0a164c054d..d1501a42431 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_credit_transactions.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_credit_transactions.py @@ -5,7 +5,12 @@ import sqlalchemy as sa -from ._common import NUMERIC_KWARGS, column_created_datetime, column_modified_datetime +from ._common import ( + NUMERIC_KWARGS, + RefActions, + column_created_datetime, + column_modified_datetime, +) from .base import metadata @@ -130,7 +135,7 @@ class CreditTransactionClassification(str, enum.Enum): "resource_tracker_service_runs.service_run_id", ], name="resource_tracker_credit_trans_fkey", - onupdate="CASCADE", - ondelete="RESTRICT", + onupdate=RefActions.CASCADE, + ondelete=RefActions.RESTRICT, ), ) diff --git a/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_pricing_plan_to_service.py b/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_pricing_plan_to_service.py index 820ec42fc50..5fd77bbbaad 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_pricing_plan_to_service.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_pricing_plan_to_service.py @@ -4,7 +4,7 @@ import sqlalchemy as sa -from ._common import column_created_datetime, column_modified_datetime +from ._common import RefActions, column_created_datetime, column_modified_datetime from .base import metadata resource_tracker_pricing_plan_to_service = sa.Table( @@ -16,8 +16,8 @@ sa.ForeignKey( "resource_tracker_pricing_plans.pricing_plan_id", name="fk_resource_tracker_pricing_details_pricing_plan_id", - onupdate="CASCADE", - ondelete="RESTRICT", + onupdate=RefActions.CASCADE, + ondelete=RefActions.RESTRICT, ), nullable=False, doc="Identifier index", @@ -49,7 +49,7 @@ ["service_key", "service_version"], ["services_meta_data.key", "services_meta_data.version"], name="fk_rut_pricing_plan_to_service_key_and_version", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), ) diff --git a/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_pricing_plans.py b/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_pricing_plans.py index 81d98ebcac1..e0e1c69efa6 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_pricing_plans.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_pricing_plans.py @@ -4,7 +4,7 @@ import sqlalchemy as sa -from ._common import column_created_datetime, column_modified_datetime +from ._common import RefActions, column_created_datetime, column_modified_datetime from .base import metadata @@ -35,8 +35,8 @@ class PricingPlanClassification(str, enum.Enum): sa.String, sa.ForeignKey( "products.name", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, name="fk_rut_pricing_plans_product_name", ), nullable=False, diff --git a/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_pricing_unit_costs.py b/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_pricing_unit_costs.py index 46031532387..7a4c4e5f6a1 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_pricing_unit_costs.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_pricing_unit_costs.py @@ -6,7 +6,12 @@ """ import sqlalchemy as sa -from ._common import NUMERIC_KWARGS, column_created_datetime, column_modified_datetime +from ._common import ( + NUMERIC_KWARGS, + RefActions, + column_created_datetime, + column_modified_datetime, +) from .base import metadata resource_tracker_pricing_unit_costs = sa.Table( @@ -25,8 +30,8 @@ sa.ForeignKey( "resource_tracker_pricing_plans.pricing_plan_id", name="fk_resource_tracker_pricing_units_costs_pricing_plan_id", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), nullable=False, doc="Foreign key to pricing plan", @@ -44,8 +49,8 @@ sa.ForeignKey( "resource_tracker_pricing_units.pricing_unit_id", name="fk_resource_tracker_pricing_units_costs_pricing_unit_id", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), nullable=False, doc="Foreign key to pricing unit", diff --git a/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_pricing_units.py b/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_pricing_units.py index 6b047c2207a..aecbc1d07e1 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_pricing_units.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_pricing_units.py @@ -7,7 +7,7 @@ import sqlalchemy as sa from sqlalchemy.dialects.postgresql import JSONB -from ._common import column_created_datetime, column_modified_datetime +from ._common import RefActions, column_created_datetime, column_modified_datetime from .base import metadata resource_tracker_pricing_units = sa.Table( @@ -26,8 +26,8 @@ sa.ForeignKey( "resource_tracker_pricing_plans.pricing_plan_id", name="fk_resource_tracker_pricing_units_pricing_plan_id", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), nullable=False, doc="Foreign key to pricing plan", diff --git a/packages/postgres-database/src/simcore_postgres_database/models/services.py b/packages/postgres-database/src/simcore_postgres_database/models/services.py index b329a1e8156..30fbf5af696 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/services.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/services.py @@ -2,6 +2,7 @@ from sqlalchemy.dialects.postgresql import ARRAY, JSONB from sqlalchemy.sql import expression +from ._common import RefActions from .base import metadata services_meta_data = sa.Table( @@ -33,8 +34,8 @@ sa.ForeignKey( "groups.gid", name="fk_services_meta_data_gid_groups", - onupdate="CASCADE", - ondelete="RESTRICT", + onupdate=RefActions.CASCADE, + ondelete=RefActions.RESTRICT, ), nullable=True, doc="Identifier of the group that owns this service (editable)", @@ -141,8 +142,8 @@ sa.ForeignKey( "groups.gid", name="fk_services_gid_groups", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), doc="Group Identifier of user that get these access-rights", ), @@ -168,8 +169,8 @@ sa.ForeignKey( "products.name", name="fk_services_name_products", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), doc="Product Identifier", ), @@ -192,8 +193,8 @@ sa.ForeignKeyConstraint( ["key", "version"], ["services_meta_data.key", "services_meta_data.version"], - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), sa.PrimaryKeyConstraint( "key", "version", "gid", "product_name", name="services_access_pk" diff --git a/packages/postgres-database/src/simcore_postgres_database/models/services_compatibility.py b/packages/postgres-database/src/simcore_postgres_database/models/services_compatibility.py index aa3929385e3..d151b665885 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/services_compatibility.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/services_compatibility.py @@ -11,6 +11,7 @@ from typing_extensions import NotRequired, Required from ._common import ( + RefActions, column_created_datetime, column_modified_by_user, column_modified_datetime, @@ -61,8 +62,8 @@ class CompatiblePolicyDict(typing_extensions.TypedDict, total=False): sa.ForeignKeyConstraint( ["key", "version"], ["services_meta_data.key", "services_meta_data.version"], - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), sa.PrimaryKeyConstraint("key", "version", name="services_compatibility_pk"), ) diff --git a/packages/postgres-database/src/simcore_postgres_database/models/services_consume_filetypes.py b/packages/postgres-database/src/simcore_postgres_database/models/services_consume_filetypes.py index e46df8670e8..65c6c8546b3 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/services_consume_filetypes.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/services_consume_filetypes.py @@ -7,6 +7,7 @@ """ import sqlalchemy as sa +from ._common import RefActions from .base import metadata # @@ -75,8 +76,8 @@ sa.ForeignKeyConstraint( ["service_key", "service_version"], ["services_meta_data.key", "services_meta_data.version"], - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), # This table stores services (key:version) that consume filetype by AT LEAST one input_port # if more ports can consume, then it should only be added once in this table diff --git a/packages/postgres-database/src/simcore_postgres_database/models/services_environments.py b/packages/postgres-database/src/simcore_postgres_database/models/services_environments.py index 3248191e7a1..498191b7267 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/services_environments.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/services_environments.py @@ -3,7 +3,7 @@ import sqlalchemy as sa from sqlalchemy.dialects.postgresql import JSONB -from ._common import column_created_datetime, column_modified_datetime +from ._common import RefActions, column_created_datetime, column_modified_datetime from .base import metadata # Intentionally includes the term "SECRET" to avoid leaking this value on a public domain @@ -36,8 +36,8 @@ sa.ForeignKey( "products.name", name="fk_services_name_products", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), # NOTE: since this is part of the primary key this is required # NOTE: an alternative would be to not use this as a primary key @@ -59,8 +59,8 @@ sa.ForeignKeyConstraint( ["service_key", "service_base_version"], ["services_meta_data.key", "services_meta_data.version"], - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, # NOTE: this might be a problem: if a version in the metadata is deleted, # all versions above will take the secret_map for the previous one. ), diff --git a/packages/postgres-database/src/simcore_postgres_database/models/services_specifications.py b/packages/postgres-database/src/simcore_postgres_database/models/services_specifications.py index a8b16b06f91..452be5e25f0 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/services_specifications.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/services_specifications.py @@ -8,6 +8,7 @@ import sqlalchemy as sa from sqlalchemy.dialects.postgresql import JSONB +from ._common import RefActions from .base import metadata services_specifications = sa.Table( @@ -31,8 +32,8 @@ sa.ForeignKey( "groups.gid", name="fk_services_specifications_gid_groups", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), doc="Group Identifier", ), @@ -52,8 +53,8 @@ sa.ForeignKeyConstraint( ["service_key", "service_version"], ["services_meta_data.key", "services_meta_data.version"], - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), # This table stores services (key:version) that consume filetype by AT LEAST one input_port # if more ports can consume, then it should only be added once in this table diff --git a/packages/postgres-database/src/simcore_postgres_database/models/services_tags.py b/packages/postgres-database/src/simcore_postgres_database/models/services_tags.py index c774cdcd317..083ea9f2807 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/services_tags.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/services_tags.py @@ -1,5 +1,6 @@ import sqlalchemy as sa +from ._common import RefActions from .base import metadata from .tags import tags @@ -26,7 +27,9 @@ sa.Column( "tag_id", sa.BigInteger, - sa.ForeignKey(tags.c.id, onupdate="CASCADE", ondelete="CASCADE"), + sa.ForeignKey( + tags.c.id, onupdate=RefActions.CASCADE, ondelete=RefActions.CASCADE + ), nullable=False, doc="Identifier of the tag assigned to this specific service (service_key, service_version).", ), @@ -34,8 +37,8 @@ sa.ForeignKeyConstraint( ["service_key", "service_version"], ["services_meta_data.key", "services_meta_data.version"], - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), sa.UniqueConstraint( "service_key", "service_version", "tag_id", name="services_tags_uc" diff --git a/packages/postgres-database/src/simcore_postgres_database/models/tags_access_rights.py b/packages/postgres-database/src/simcore_postgres_database/models/tags_access_rights.py index 9078a9254f1..b818c975817 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/tags_access_rights.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/tags_access_rights.py @@ -1,6 +1,6 @@ import sqlalchemy as sa -from ._common import column_created_datetime, column_modified_datetime +from ._common import RefActions, column_created_datetime, column_modified_datetime from .base import metadata from .groups import groups from .tags import tags @@ -17,8 +17,8 @@ sa.BigInteger(), sa.ForeignKey( tags.c.id, - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, name="fk_tag_to_group_tag_id", ), nullable=False, @@ -29,8 +29,8 @@ sa.BigInteger, sa.ForeignKey( groups.c.gid, - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, name="fk_tag_to_group_group_id", ), nullable=False, diff --git a/packages/postgres-database/src/simcore_postgres_database/models/user_preferences.py b/packages/postgres-database/src/simcore_postgres_database/models/user_preferences.py index 8d3cdde98d5..e380cd23b94 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/user_preferences.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/user_preferences.py @@ -1,5 +1,6 @@ import sqlalchemy as sa +from ._common import RefActions from .base import metadata from .products import products from .users import users @@ -12,8 +13,8 @@ def _user_id_column(fk_name: str) -> sa.Column: sa.ForeignKey( users.c.id, name=fk_name, - ondelete="CASCADE", - onupdate="CASCADE", + ondelete=RefActions.CASCADE, + onupdate=RefActions.CASCADE, ), nullable=False, ) @@ -26,8 +27,8 @@ def _product_name_column(fk_name: str) -> sa.Column: sa.ForeignKey( products.c.name, name=fk_name, - ondelete="CASCADE", - onupdate="CASCADE", + ondelete=RefActions.CASCADE, + onupdate=RefActions.CASCADE, ), nullable=False, ) diff --git a/packages/postgres-database/src/simcore_postgres_database/models/user_to_projects.py b/packages/postgres-database/src/simcore_postgres_database/models/user_to_projects.py index 45147bef610..4a66e0be611 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/user_to_projects.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/user_to_projects.py @@ -1,5 +1,6 @@ import sqlalchemy as sa +from ._common import RefActions from .base import metadata from .projects import projects from .users import users @@ -15,8 +16,8 @@ sa.ForeignKey( users.c.id, name="fk_user_to_projects_id_users", - ondelete="CASCADE", - onupdate="CASCADE", + ondelete=RefActions.CASCADE, + onupdate=RefActions.CASCADE, ), nullable=False, ), @@ -26,8 +27,8 @@ sa.ForeignKey( projects.c.id, name="fk_user_to_projects_id_projects", - ondelete="CASCADE", - onupdate="CASCADE", + ondelete=RefActions.CASCADE, + onupdate=RefActions.CASCADE, ), nullable=False, ), diff --git a/packages/postgres-database/src/simcore_postgres_database/models/users.py b/packages/postgres-database/src/simcore_postgres_database/models/users.py index 90d5e063662..61b8c321130 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/users.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/users.py @@ -3,6 +3,7 @@ import sqlalchemy as sa +from ._common import RefActions from .base import metadata _USER_ROLE_TO_LEVEL = { @@ -113,8 +114,8 @@ class UserStatus(str, Enum): sa.ForeignKey( "groups.gid", name="fk_users_gid_groups", - onupdate="CASCADE", - ondelete="RESTRICT", + onupdate=RefActions.CASCADE, + ondelete=RefActions.RESTRICT, ), doc="User's group ID", ), diff --git a/packages/postgres-database/src/simcore_postgres_database/models/users_details.py b/packages/postgres-database/src/simcore_postgres_database/models/users_details.py index 2e7a7ab79c5..555e623dbdc 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/users_details.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/users_details.py @@ -2,6 +2,7 @@ from sqlalchemy.dialects import postgresql from ._common import ( + RefActions, column_created_datetime, column_modified_datetime, register_modified_datetime_auto_update_trigger, @@ -22,8 +23,8 @@ sa.Integer, sa.ForeignKey( users.c.id, - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), nullable=True, doc="None if row was added during pre-registration or join column with `users` after registration", @@ -71,8 +72,8 @@ sa.Integer, sa.ForeignKey( users.c.id, - onupdate="CASCADE", - ondelete="SET NULL", + onupdate=RefActions.CASCADE, + ondelete=RefActions.SET_NULL, ), nullable=True, doc="PO user that issued this pre-registration", diff --git a/packages/postgres-database/src/simcore_postgres_database/models/wallet_to_groups.py b/packages/postgres-database/src/simcore_postgres_database/models/wallet_to_groups.py index a5d4016fa51..7679b5f5285 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/wallet_to_groups.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/wallet_to_groups.py @@ -1,7 +1,7 @@ import sqlalchemy as sa from sqlalchemy.sql import expression -from ._common import column_created_datetime, column_modified_datetime +from ._common import RefActions, column_created_datetime, column_modified_datetime from .base import metadata from .groups import groups from .wallets import wallets @@ -15,8 +15,8 @@ sa.ForeignKey( wallets.c.wallet_id, name="fk_wallet_to_groups_id_wallets", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), doc="Wallet unique ID", ), @@ -26,8 +26,8 @@ sa.ForeignKey( groups.c.gid, name="fk_wallet_to_groups_gid_groups", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), doc="Group unique IDentifier", ), diff --git a/packages/postgres-database/src/simcore_postgres_database/models/wallets.py b/packages/postgres-database/src/simcore_postgres_database/models/wallets.py index 3c765529976..27fa821a6bf 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/wallets.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/wallets.py @@ -2,7 +2,7 @@ import sqlalchemy as sa -from ._common import column_created_datetime, column_modified_datetime +from ._common import RefActions, column_created_datetime, column_modified_datetime from .base import metadata @@ -30,8 +30,8 @@ class WalletStatus(str, enum.Enum): sa.ForeignKey( "groups.gid", name="fk_wallets_gid_groups", - onupdate="CASCADE", - ondelete="RESTRICT", + onupdate=RefActions.CASCADE, + ondelete=RefActions.RESTRICT, ), nullable=False, doc="Identifier of the group that owns this wallet (Should be just PRIMARY GROUP)", @@ -55,8 +55,8 @@ class WalletStatus(str, enum.Enum): sa.String, sa.ForeignKey( "products.name", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, name="fk_wallets_product_name", ), nullable=False, diff --git a/packages/postgres-database/src/simcore_postgres_database/models/workspaces.py b/packages/postgres-database/src/simcore_postgres_database/models/workspaces.py index 998c7676761..756bbe9642e 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/workspaces.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/workspaces.py @@ -1,7 +1,14 @@ import sqlalchemy as sa -from ._common import column_created_datetime, column_modified_datetime +from ._common import ( + RefActions, + column_created_datetime, + column_modified_datetime, + column_trashed_by_user, + column_trashed_datetime, +) from .base import metadata +from .users import users workspaces = sa.Table( "workspaces", @@ -28,8 +35,8 @@ sa.ForeignKey( "groups.gid", name="fk_workspaces_gid_groups", - onupdate="CASCADE", - ondelete="RESTRICT", + onupdate=RefActions.CASCADE, + ondelete=RefActions.RESTRICT, ), nullable=False, doc="Identifier of the group that owns this workspace (Should be just PRIMARY GROUP)", @@ -39,8 +46,8 @@ sa.String, sa.ForeignKey( "products.name", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, name="fk_workspaces_product_name", ), nullable=False, @@ -48,8 +55,11 @@ ), column_created_datetime(timezone=True), column_modified_datetime(timezone=True), + column_trashed_datetime("workspace"), + column_trashed_by_user("workspace", users_table=users), ) + # ------------------------ TRIGGERS new_workspace_trigger = sa.DDL( """ diff --git a/packages/postgres-database/src/simcore_postgres_database/models/workspaces_access_rights.py b/packages/postgres-database/src/simcore_postgres_database/models/workspaces_access_rights.py index 960ef643538..2a247fb477f 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/workspaces_access_rights.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/workspaces_access_rights.py @@ -1,7 +1,7 @@ import sqlalchemy as sa from sqlalchemy.sql import expression -from ._common import column_created_datetime, column_modified_datetime +from ._common import RefActions, column_created_datetime, column_modified_datetime from .base import metadata from .groups import groups from .workspaces import workspaces @@ -15,8 +15,8 @@ sa.ForeignKey( workspaces.c.workspace_id, name="fk_workspaces_access_rights_id_workspaces", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), doc="Workspace unique ID", ), @@ -26,8 +26,8 @@ sa.ForeignKey( groups.c.gid, name="fk_workspaces_access_rights_gid_groups", - onupdate="CASCADE", - ondelete="CASCADE", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, ), doc="Group unique IDentifier", ), diff --git a/packages/postgres-database/tests/test_models_tags.py b/packages/postgres-database/tests/test_models_tags.py index 71a7ba4702d..7b129e5edc7 100644 --- a/packages/postgres-database/tests/test_models_tags.py +++ b/packages/postgres-database/tests/test_models_tags.py @@ -6,6 +6,7 @@ import pytest import sqlalchemy as sa +from simcore_postgres_database.models._common import RefActions from simcore_postgres_database.models.base import metadata from simcore_postgres_database.models.tags_access_rights import tags_access_rights from simcore_postgres_database.models.users import users @@ -23,7 +24,9 @@ def test_migration_downgrade_script(): sa.Column( "user_id", sa.BigInteger, - sa.ForeignKey("users.id", onupdate="CASCADE", ondelete="CASCADE"), + sa.ForeignKey( + "users.id", onupdate=RefActions.CASCADE, ondelete=RefActions.CASCADE + ), nullable=False, ), sa.Column("name", sa.String, nullable=False), diff --git a/packages/pytest-simcore/src/pytest_simcore/openapi_specs.py b/packages/pytest-simcore/src/pytest_simcore/openapi_specs.py new file mode 100644 index 00000000000..fd9e6b878d6 --- /dev/null +++ b/packages/pytest-simcore/src/pytest_simcore/openapi_specs.py @@ -0,0 +1,113 @@ +# pylint: disable=redefined-outer-name +# pylint: disable=unused-argument +# pylint: disable=unused-variable +# pylint: disable=too-many-arguments + +import json +from collections.abc import Callable +from copy import deepcopy +from pathlib import Path +from typing import Any, NamedTuple + +import jsonref +import pytest +import yaml + +try: + from aiohttp import web + + has_aiohttp = True +except ImportError: + has_aiohttp = False + + +class Entrypoint(NamedTuple): + name: str + method: str + path: str + + +@pytest.fixture(scope="session") +def openapi_specs_path() -> Path: + # NOTE: cannot be defined as a session scope because it is designed to be overriden + pytest.fail(reason="Must be overriden in caller test suite") + + +def _load(file: Path, base_uri: str = "") -> dict: + match file.suffix: + case ".yaml" | ".yml": + loaded = yaml.safe_load(file.read_text()) + case "json": + loaded = json.loads(file.read_text()) + case _: + msg = f"Expect yaml or json, got {file.suffix}" + raise ValueError(msg) + + # SEE https://jsonref.readthedocs.io/en/latest/#lazy-load-and-load-on-repr + data: dict = jsonref.replace_refs( # type: ignore + loaded, + base_uri=base_uri, + lazy_load=True, # this data will be iterated + merge_props=False, + ) + return data + + +@pytest.fixture(scope="session") +def openapi_specs(openapi_specs_path: Path) -> dict[str, Any]: + assert openapi_specs_path.is_file() + openapi: dict[str, Any] = _load( + openapi_specs_path, base_uri=openapi_specs_path.as_uri() + ) + return deepcopy(openapi) + + +@pytest.fixture(scope="session") +def openapi_specs_entrypoints( + openapi_specs: dict, +) -> set[Entrypoint]: + entrypoints: set[Entrypoint] = set() + + # openapi-specifications, i.e. "contract" + for path, path_obj in openapi_specs["paths"].items(): + for operation, operation_obj in path_obj.items(): + entrypoints.add( + Entrypoint( + method=operation.upper(), + path=path, + name=operation_obj["operationId"], + ) + ) + return entrypoints + + +if has_aiohttp: + + @pytest.fixture + def create_aiohttp_app_rest_entrypoints() -> Callable[ + [web.Application], set[Entrypoint] + ]: + def _(app: web.Application): + entrypoints: set[Entrypoint] = set() + + # app routes, i.e. "exposed" + for resource_name, resource in app.router.named_resources().items(): + resource_path = resource.canonical + for route in resource: + assert route.name == resource_name + assert route.resource + assert route.name is not None + + if route.method == "HEAD": + continue + + entrypoints.add( + Entrypoint( + method=route.method, + path=resource_path, + name=route.name, + ) + ) + return entrypoints + + return _ diff --git a/packages/service-library/requirements/_aiohttp.in b/packages/service-library/requirements/_aiohttp.in index 6b04b964a6c..d829728aa81 100644 --- a/packages/service-library/requirements/_aiohttp.in +++ b/packages/service-library/requirements/_aiohttp.in @@ -9,7 +9,6 @@ aiohttp aiopg[sa] attrs jsonschema -openapi-core opentelemetry-instrumentation-aiohttp-client opentelemetry-instrumentation-aiohttp-server opentelemetry-instrumentation-aiopg diff --git a/packages/service-library/requirements/_aiohttp.txt b/packages/service-library/requirements/_aiohttp.txt index d3e27ed894b..22b862d533d 100644 --- a/packages/service-library/requirements/_aiohttp.txt +++ b/packages/service-library/requirements/_aiohttp.txt @@ -21,17 +21,6 @@ attrs==24.2.0 # aiohttp # jsonschema # referencing -certifi==2024.8.30 - # via - # -c requirements/../../../packages/common-library/requirements/../../../requirements/constraints.txt - # -c requirements/../../../packages/models-library/requirements/../../../packages/common-library/requirements/../../../requirements/constraints.txt - # -c requirements/../../../packages/models-library/requirements/../../../requirements/constraints.txt - # -c requirements/../../../packages/settings-library/requirements/../../../packages/common-library/requirements/../../../requirements/constraints.txt - # -c requirements/../../../packages/settings-library/requirements/../../../requirements/constraints.txt - # -c requirements/../../../requirements/constraints.txt - # requests -charset-normalizer==3.3.2 - # via requests deprecated==1.2.14 # via # opentelemetry-api @@ -43,45 +32,19 @@ frozenlist==1.4.1 greenlet==3.1.1 # via sqlalchemy idna==3.10 - # via - # requests - # yarl + # via yarl importlib-metadata==8.4.0 # via opentelemetry-api -isodate==0.6.1 - # via openapi-core jsonschema==4.23.0 - # via - # -r requirements/_aiohttp.in - # openapi-core - # openapi-schema-validator - # openapi-spec-validator -jsonschema-path==0.3.3 - # via - # openapi-core - # openapi-spec-validator + # via -r requirements/_aiohttp.in jsonschema-specifications==2023.7.1 - # via - # jsonschema - # openapi-schema-validator -lazy-object-proxy==1.10.0 - # via openapi-spec-validator + # via jsonschema markupsafe==2.1.5 # via werkzeug -more-itertools==10.5.0 - # via openapi-core multidict==6.1.0 # via # aiohttp # yarl -openapi-core==0.19.4 - # via -r requirements/_aiohttp.in -openapi-schema-validator==0.6.2 - # via - # openapi-core - # openapi-spec-validator -openapi-spec-validator==0.7.1 - # via openapi-core opentelemetry-api==1.27.0 # via # opentelemetry-instrumentation @@ -113,45 +76,22 @@ opentelemetry-util-http==0.48b0 # via # opentelemetry-instrumentation-aiohttp-client # opentelemetry-instrumentation-aiohttp-server -parse==1.20.2 - # via openapi-core -pathable==0.4.3 - # via jsonschema-path prometheus-client==0.21.0 # via -r requirements/_aiohttp.in psycopg2-binary==2.9.9 # via # aiopg # sqlalchemy -pyyaml==6.0.2 - # via - # -c requirements/../../../packages/common-library/requirements/../../../requirements/constraints.txt - # -c requirements/../../../packages/models-library/requirements/../../../packages/common-library/requirements/../../../requirements/constraints.txt - # -c requirements/../../../packages/models-library/requirements/../../../requirements/constraints.txt - # -c requirements/../../../packages/settings-library/requirements/../../../packages/common-library/requirements/../../../requirements/constraints.txt - # -c requirements/../../../packages/settings-library/requirements/../../../requirements/constraints.txt - # -c requirements/../../../requirements/constraints.txt - # jsonschema-path referencing==0.29.3 # via - # -c requirements/./constraints.txt # jsonschema - # jsonschema-path # jsonschema-specifications -requests==2.32.3 - # via jsonschema-path -rfc3339-validator==0.1.4 - # via openapi-schema-validator rpds-py==0.20.0 # via # jsonschema # referencing setuptools==75.1.0 # via opentelemetry-instrumentation -six==1.16.0 - # via - # isodate - # rfc3339-validator sqlalchemy==1.4.54 # via # -c requirements/../../../packages/common-library/requirements/../../../requirements/constraints.txt @@ -161,19 +101,8 @@ sqlalchemy==1.4.54 # -c requirements/../../../packages/settings-library/requirements/../../../requirements/constraints.txt # -c requirements/../../../requirements/constraints.txt # aiopg -urllib3==2.2.3 - # via - # -c requirements/../../../packages/common-library/requirements/../../../requirements/constraints.txt - # -c requirements/../../../packages/models-library/requirements/../../../packages/common-library/requirements/../../../requirements/constraints.txt - # -c requirements/../../../packages/models-library/requirements/../../../requirements/constraints.txt - # -c requirements/../../../packages/settings-library/requirements/../../../packages/common-library/requirements/../../../requirements/constraints.txt - # -c requirements/../../../packages/settings-library/requirements/../../../requirements/constraints.txt - # -c requirements/../../../requirements/constraints.txt - # requests werkzeug==3.0.4 - # via - # -r requirements/_aiohttp.in - # openapi-core + # via -r requirements/_aiohttp.in wrapt==1.16.0 # via # deprecated diff --git a/packages/service-library/requirements/_base.txt b/packages/service-library/requirements/_base.txt index 7bfebd08206..d4a84148c40 100644 --- a/packages/service-library/requirements/_base.txt +++ b/packages/service-library/requirements/_base.txt @@ -217,7 +217,6 @@ redis==5.0.4 # -r requirements/_base.in referencing==0.29.3 # via - # -c requirements/./constraints.txt # jsonschema # jsonschema-specifications repro-zipfile==0.3.1 diff --git a/packages/service-library/requirements/_test.txt b/packages/service-library/requirements/_test.txt index 70fa21a3a6a..d07f3213ccf 100644 --- a/packages/service-library/requirements/_test.txt +++ b/packages/service-library/requirements/_test.txt @@ -34,7 +34,6 @@ botocore==1.35.50 certifi==2024.8.30 # via # -c requirements/../../../requirements/constraints.txt - # -c requirements/_aiohttp.txt # -c requirements/_base.txt # -c requirements/_fastapi.txt # httpcore @@ -42,7 +41,6 @@ certifi==2024.8.30 # requests charset-normalizer==3.3.2 # via - # -c requirements/_aiohttp.txt # -c requirements/_base.txt # requests coverage==7.6.1 @@ -102,9 +100,7 @@ jsonschema==4.23.0 # openapi-schema-validator # openapi-spec-validator jsonschema-path==0.3.3 - # via - # -c requirements/_aiohttp.txt - # openapi-spec-validator + # via openapi-spec-validator jsonschema-specifications==2023.7.1 # via # -c requirements/_aiohttp.txt @@ -112,9 +108,7 @@ jsonschema-specifications==2023.7.1 # jsonschema # openapi-schema-validator lazy-object-proxy==1.10.0 - # via - # -c requirements/_aiohttp.txt - # openapi-spec-validator + # via openapi-spec-validator multidict==6.1.0 # via # -c requirements/_aiohttp.txt @@ -128,21 +122,15 @@ mypy-extensions==1.0.0 numpy==2.1.1 # via -r requirements/_test.in openapi-schema-validator==0.6.2 - # via - # -c requirements/_aiohttp.txt - # openapi-spec-validator + # via openapi-spec-validator openapi-spec-validator==0.7.1 - # via - # -c requirements/_aiohttp.txt - # -r requirements/_test.in + # via -r requirements/_test.in packaging==24.1 # via # pytest # pytest-sugar pathable==0.4.3 - # via - # -c requirements/_aiohttp.txt - # jsonschema-path + # via jsonschema-path pillow==10.4.0 # via -r requirements/_test.in pip==24.3.1 @@ -203,7 +191,6 @@ python-dotenv==1.0.1 pyyaml==6.0.2 # via # -c requirements/../../../requirements/constraints.txt - # -c requirements/_aiohttp.txt # -c requirements/_base.txt # jsonschema-path referencing==0.29.3 @@ -215,16 +202,13 @@ referencing==0.29.3 # jsonschema-specifications requests==2.32.3 # via - # -c requirements/_aiohttp.txt # -c requirements/_base.txt # docker # jsonschema-path respx==0.21.1 # via -r requirements/_test.in rfc3339-validator==0.1.4 - # via - # -c requirements/_aiohttp.txt - # openapi-schema-validator + # via openapi-schema-validator rpds-py==0.20.0 # via # -c requirements/_aiohttp.txt @@ -233,7 +217,6 @@ rpds-py==0.20.0 # referencing six==1.16.0 # via - # -c requirements/_aiohttp.txt # -c requirements/_base.txt # python-dateutil # rfc3339-validator @@ -270,7 +253,6 @@ typing-extensions==4.12.2 urllib3==2.2.3 # via # -c requirements/../../../requirements/constraints.txt - # -c requirements/_aiohttp.txt # -c requirements/_base.txt # botocore # docker diff --git a/packages/service-library/requirements/constraints.txt b/packages/service-library/requirements/constraints.txt index 39a3ce672ba..e69de29bb2d 100644 --- a/packages/service-library/requirements/constraints.txt +++ b/packages/service-library/requirements/constraints.txt @@ -1,29 +0,0 @@ -# due to openapi-core -> jsonschema-spec -> (see _aiohttp.txt) -referencing<0.30.0 - -# openapi-core==0.18.0 -# ├── asgiref [required: >=3.6.0,<4.0.0, installed: 3.7.2] -# │ └── typing-extensions [required: >=4, installed: 4.7.1] -# ├── isodate [required: Any, installed: 0.6.1] -# │ └── six [required: Any, installed: 1.16.0] -# ├── jsonschema [required: >=4.18.0,<5.0.0, installed: 4.18.4] -# │ ├── attrs [required: >=22.2.0, installed: 23.1.0] -# │ ├── jsonschema-specifications [required: >=2023.03.6, installed: 2023.7.1] -# │ │ └── referencing [required: >=0.28.0, installed: 0.29.3] <-- -# │ │ ├── attrs [required: >=22.2.0, installed: 23.1.0] -# │ │ └── rpds-py [required: >=0.7.0, installed: 0.9.2] -# │ ├── referencing [required: >=0.28.4, installed: 0.29.3] <-- -# │ │ ├── attrs [required: >=22.2.0, installed: 23.1.0] -# │ │ └── rpds-py [required: >=0.7.0, installed: 0.9.2] -# │ └── rpds-py [required: >=0.7.1, installed: 0.9.2] -# ├── jsonschema-spec [required: >=0.2.3,<0.3.0, installed: 0.2.3] -# │ ├── pathable [required: >=0.4.1,<0.5.0, installed: 0.4.3] -# │ ├── PyYAML [required: >=5.1, installed: 6.0.1] -# │ ├── referencing [required: >=0.28.0,<0.30.0, installed: 0.29.3] <-- limiting! -# │ │ ├── attrs [required: >=22.2.0, installed: 23.1.0] -# │ │ └── rpds-py [required: >=0.7.0, installed: 0.9.2] -# │ └── requests [required: >=2.31.0,<3.0.0, installed: 2.31.0] -# │ ├── certifi [required: >=2017.4.17, installed: 2023.5.7] -# │ ├── charset-normalizer [required: >=2,<4, installed: 3.2.0] -# │ ├── idna [required: >=2.5,<4, installed: 3.4] -# │ └── urllib3 [required: >=1.21.1,<3, installed: 2.0.4] diff --git a/packages/service-library/src/servicelib/fastapi/openapi.py b/packages/service-library/src/servicelib/fastapi/openapi.py index dc01e2452b1..218d3301cc0 100644 --- a/packages/service-library/src/servicelib/fastapi/openapi.py +++ b/packages/service-library/src/servicelib/fastapi/openapi.py @@ -166,3 +166,37 @@ def _custom_openapi_method(self: FastAPI) -> dict: return output setattr(app, "openapi", types.MethodType(_custom_openapi_method, app)) # noqa: B010 + + +def create_openapi_specs( + app: FastAPI, + *, + drop_fastapi_default_422: bool = True, + remove_main_sections: bool = True, +): + """ + Includes some patches used in the api/specs generators + """ + override_fastapi_openapi_method(app) + openapi = app.openapi() + + # Remove these sections + if remove_main_sections: + for section in ("info", "openapi"): + openapi.pop(section, None) + + schemas = openapi["components"]["schemas"] + for section in ("HTTPValidationError", "ValidationError"): + schemas.pop(section, None) + + # Removes default response 422 + if drop_fastapi_default_422: + for method_item in openapi.get("paths", {}).values(): + for param in method_item.values(): + # NOTE: If description is like this, + # it assumes it is the default HTTPValidationError from fastapi + if (e422 := param.get("responses", {}).get("422", None)) and e422.get( + "description" + ) == "Validation Error": + param.get("responses", {}).pop("422", None) + return openapi diff --git a/services.md b/services.md deleted file mode 100644 index 9aff3159909..00000000000 --- a/services.md +++ /dev/null @@ -1,62 +0,0 @@ -# services -> -> Auto generated on `2024-11-21 10:29:41` using -```cmd -cd osparc-simcore -python ./scripts/echo_services_markdown.py -``` -| Name|Files| | -| ----------|----------|---------- | -| **AGENT**|| | -| |[services/agent/Dockerfile](./services/agent/Dockerfile)|[![Docker Image Size](https://img.shields.io/docker/image-size/itisfoundation/agent)](https://hub.docker.com/r/itisfoundation/agent/tags) | -| **API-SERVER**|| | -| |[services/api-server/openapi.json](./services/api-server/openapi.json)|[![ReDoc](https://img.shields.io/badge/OpenAPI-ReDoc-85ea2d?logo=openapiinitiative)](https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/ITISFoundation/osparc-simcore/refs/heads/master/services/api-server/openapi.json) [![Swagger UI](https://img.shields.io/badge/OpenAPI-Swagger_UI-85ea2d?logo=swagger)](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/ITISFoundation/osparc-simcore/refs/heads/master/services/api-server/openapi.json) | -| |[services/api-server/Dockerfile](./services/api-server/Dockerfile)|[![Docker Image Size](https://img.shields.io/docker/image-size/itisfoundation/api-server)](https://hub.docker.com/r/itisfoundation/api-server/tags) | -| **AUTOSCALING**|| | -| |[services/autoscaling/Dockerfile](./services/autoscaling/Dockerfile)|[![Docker Image Size](https://img.shields.io/docker/image-size/itisfoundation/autoscaling)](https://hub.docker.com/r/itisfoundation/autoscaling/tags) | -| **CATALOG**|| | -| |[services/catalog/openapi.json](./services/catalog/openapi.json)|[![ReDoc](https://img.shields.io/badge/OpenAPI-ReDoc-85ea2d?logo=openapiinitiative)](https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/ITISFoundation/osparc-simcore/refs/heads/master/services/catalog/openapi.json) [![Swagger UI](https://img.shields.io/badge/OpenAPI-Swagger_UI-85ea2d?logo=swagger)](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/ITISFoundation/osparc-simcore/refs/heads/master/services/catalog/openapi.json) | -| |[services/catalog/Dockerfile](./services/catalog/Dockerfile)|[![Docker Image Size](https://img.shields.io/docker/image-size/itisfoundation/catalog)](https://hub.docker.com/r/itisfoundation/catalog/tags) | -| **CLUSTERS-KEEPER**|| | -| |[services/clusters-keeper/Dockerfile](./services/clusters-keeper/Dockerfile)|[![Docker Image Size](https://img.shields.io/docker/image-size/itisfoundation/clusters-keeper)](https://hub.docker.com/r/itisfoundation/clusters-keeper/tags) | -| **DASK-SIDECAR**|| | -| |[services/dask-sidecar/Dockerfile](./services/dask-sidecar/Dockerfile)|[![Docker Image Size](https://img.shields.io/docker/image-size/itisfoundation/dask-sidecar)](https://hub.docker.com/r/itisfoundation/dask-sidecar/tags) | -| **DATCORE-ADAPTER**|| | -| |[services/datcore-adapter/Dockerfile](./services/datcore-adapter/Dockerfile)|[![Docker Image Size](https://img.shields.io/docker/image-size/itisfoundation/datcore-adapter)](https://hub.docker.com/r/itisfoundation/datcore-adapter/tags) | -| **DIRECTOR**|| | -| |[services/director/src/simcore_service_director/api/v0/openapi.yaml](./services/director/src/simcore_service_director/api/v0/openapi.yaml)|[![ReDoc](https://img.shields.io/badge/OpenAPI-ReDoc-85ea2d?logo=openapiinitiative)](https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/ITISFoundation/osparc-simcore/refs/heads/master/services/director/src/simcore_service_director/api/v0/openapi.yaml) [![Swagger UI](https://img.shields.io/badge/OpenAPI-Swagger_UI-85ea2d?logo=swagger)](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/ITISFoundation/osparc-simcore/refs/heads/master/services/director/src/simcore_service_director/api/v0/openapi.yaml) | -| |[services/director/Dockerfile](./services/director/Dockerfile)|[![Docker Image Size](https://img.shields.io/docker/image-size/itisfoundation/director)](https://hub.docker.com/r/itisfoundation/director/tags) | -| **DIRECTOR-V2**|| | -| |[services/director-v2/openapi.json](./services/director-v2/openapi.json)|[![ReDoc](https://img.shields.io/badge/OpenAPI-ReDoc-85ea2d?logo=openapiinitiative)](https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/ITISFoundation/osparc-simcore/refs/heads/master/services/director-v2/openapi.json) [![Swagger UI](https://img.shields.io/badge/OpenAPI-Swagger_UI-85ea2d?logo=swagger)](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/ITISFoundation/osparc-simcore/refs/heads/master/services/director-v2/openapi.json) | -| |[services/director-v2/Dockerfile](./services/director-v2/Dockerfile)|[![Docker Image Size](https://img.shields.io/docker/image-size/itisfoundation/director-v2)](https://hub.docker.com/r/itisfoundation/director-v2/tags) | -| **DYNAMIC-SCHEDULER**|| | -| |[services/dynamic-scheduler/openapi.json](./services/dynamic-scheduler/openapi.json)|[![ReDoc](https://img.shields.io/badge/OpenAPI-ReDoc-85ea2d?logo=openapiinitiative)](https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/ITISFoundation/osparc-simcore/refs/heads/master/services/dynamic-scheduler/openapi.json) [![Swagger UI](https://img.shields.io/badge/OpenAPI-Swagger_UI-85ea2d?logo=swagger)](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/ITISFoundation/osparc-simcore/refs/heads/master/services/dynamic-scheduler/openapi.json) | -| |[services/dynamic-scheduler/Dockerfile](./services/dynamic-scheduler/Dockerfile)|[![Docker Image Size](https://img.shields.io/docker/image-size/itisfoundation/dynamic-scheduler)](https://hub.docker.com/r/itisfoundation/dynamic-scheduler/tags) | -| **DYNAMIC-SIDECAR**|| | -| |[services/dynamic-sidecar/openapi.json](./services/dynamic-sidecar/openapi.json)|[![ReDoc](https://img.shields.io/badge/OpenAPI-ReDoc-85ea2d?logo=openapiinitiative)](https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/ITISFoundation/osparc-simcore/refs/heads/master/services/dynamic-sidecar/openapi.json) [![Swagger UI](https://img.shields.io/badge/OpenAPI-Swagger_UI-85ea2d?logo=swagger)](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/ITISFoundation/osparc-simcore/refs/heads/master/services/dynamic-sidecar/openapi.json) | -| |[services/dynamic-sidecar/Dockerfile](./services/dynamic-sidecar/Dockerfile)|[![Docker Image Size](https://img.shields.io/docker/image-size/itisfoundation/dynamic-sidecar)](https://hub.docker.com/r/itisfoundation/dynamic-sidecar/tags) | -| **EFS-GUARDIAN**|| | -| |[services/efs-guardian/Dockerfile](./services/efs-guardian/Dockerfile)|[![Docker Image Size](https://img.shields.io/docker/image-size/itisfoundation/efs-guardian)](https://hub.docker.com/r/itisfoundation/efs-guardian/tags) | -| **INVITATIONS**|| | -| |[services/invitations/openapi.json](./services/invitations/openapi.json)|[![ReDoc](https://img.shields.io/badge/OpenAPI-ReDoc-85ea2d?logo=openapiinitiative)](https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/ITISFoundation/osparc-simcore/refs/heads/master/services/invitations/openapi.json) [![Swagger UI](https://img.shields.io/badge/OpenAPI-Swagger_UI-85ea2d?logo=swagger)](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/ITISFoundation/osparc-simcore/refs/heads/master/services/invitations/openapi.json) | -| |[services/invitations/Dockerfile](./services/invitations/Dockerfile)|[![Docker Image Size](https://img.shields.io/docker/image-size/itisfoundation/invitations)](https://hub.docker.com/r/itisfoundation/invitations/tags) | -| **MIGRATION**|| | -| |[services/migration/Dockerfile](./services/migration/Dockerfile)|[![Docker Image Size](https://img.shields.io/docker/image-size/itisfoundation/migration)](https://hub.docker.com/r/itisfoundation/migration/tags) | -| **OSPARC-GATEWAY-SERVER**|| | -| |[services/osparc-gateway-server/Dockerfile](./services/osparc-gateway-server/Dockerfile)|[![Docker Image Size](https://img.shields.io/docker/image-size/itisfoundation/osparc-gateway-server)](https://hub.docker.com/r/itisfoundation/osparc-gateway-server/tags) | -| **PAYMENTS**|| | -| |[services/payments/openapi.json](./services/payments/openapi.json)|[![ReDoc](https://img.shields.io/badge/OpenAPI-ReDoc-85ea2d?logo=openapiinitiative)](https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/ITISFoundation/osparc-simcore/refs/heads/master/services/payments/openapi.json) [![Swagger UI](https://img.shields.io/badge/OpenAPI-Swagger_UI-85ea2d?logo=swagger)](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/ITISFoundation/osparc-simcore/refs/heads/master/services/payments/openapi.json) | -| |[services/payments/gateway/openapi.json](./services/payments/gateway/openapi.json)|[![ReDoc](https://img.shields.io/badge/OpenAPI-ReDoc-85ea2d?logo=openapiinitiative)](https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/ITISFoundation/osparc-simcore/refs/heads/master/services/payments/gateway/openapi.json) [![Swagger UI](https://img.shields.io/badge/OpenAPI-Swagger_UI-85ea2d?logo=swagger)](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/ITISFoundation/osparc-simcore/refs/heads/master/services/payments/gateway/openapi.json) | -| |[services/payments/Dockerfile](./services/payments/Dockerfile)|[![Docker Image Size](https://img.shields.io/docker/image-size/itisfoundation/payments)](https://hub.docker.com/r/itisfoundation/payments/tags) | -| **RESOURCE-USAGE-TRACKER**|| | -| |[services/resource-usage-tracker/openapi.json](./services/resource-usage-tracker/openapi.json)|[![ReDoc](https://img.shields.io/badge/OpenAPI-ReDoc-85ea2d?logo=openapiinitiative)](https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/ITISFoundation/osparc-simcore/refs/heads/master/services/resource-usage-tracker/openapi.json) [![Swagger UI](https://img.shields.io/badge/OpenAPI-Swagger_UI-85ea2d?logo=swagger)](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/ITISFoundation/osparc-simcore/refs/heads/master/services/resource-usage-tracker/openapi.json) | -| |[services/resource-usage-tracker/Dockerfile](./services/resource-usage-tracker/Dockerfile)|[![Docker Image Size](https://img.shields.io/docker/image-size/itisfoundation/resource-usage-tracker)](https://hub.docker.com/r/itisfoundation/resource-usage-tracker/tags) | -| **STATIC-WEBSERVER**|| | -| |[services/static-webserver/client/tools/qooxdoo-kit/builder/Dockerfile](./services/static-webserver/client/tools/qooxdoo-kit/builder/Dockerfile)|[![Docker Image Size](https://img.shields.io/docker/image-size/itisfoundation/static-webserver)](https://hub.docker.com/r/itisfoundation/static-webserver/tags) | -| **STORAGE**|| | -| |[services/storage/src/simcore_service_storage/api/v0/openapi.yaml](./services/storage/src/simcore_service_storage/api/v0/openapi.yaml)|[![ReDoc](https://img.shields.io/badge/OpenAPI-ReDoc-85ea2d?logo=openapiinitiative)](https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/ITISFoundation/osparc-simcore/refs/heads/master/services/storage/src/simcore_service_storage/api/v0/openapi.yaml) [![Swagger UI](https://img.shields.io/badge/OpenAPI-Swagger_UI-85ea2d?logo=swagger)](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/ITISFoundation/osparc-simcore/refs/heads/master/services/storage/src/simcore_service_storage/api/v0/openapi.yaml) | -| |[services/storage/Dockerfile](./services/storage/Dockerfile)|[![Docker Image Size](https://img.shields.io/docker/image-size/itisfoundation/storage)](https://hub.docker.com/r/itisfoundation/storage/tags) | -| **WEB**|| | -| |[services/web/server/src/simcore_service_webserver/api/v0/openapi.yaml](./services/web/server/src/simcore_service_webserver/api/v0/openapi.yaml)|[![ReDoc](https://img.shields.io/badge/OpenAPI-ReDoc-85ea2d?logo=openapiinitiative)](https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/ITISFoundation/osparc-simcore/refs/heads/master/services/web/server/src/simcore_service_webserver/api/v0/openapi.yaml) [![Swagger UI](https://img.shields.io/badge/OpenAPI-Swagger_UI-85ea2d?logo=swagger)](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/ITISFoundation/osparc-simcore/refs/heads/master/services/web/server/src/simcore_service_webserver/api/v0/openapi.yaml) | -| |[services/web/Dockerfile](./services/web/Dockerfile)|[![Docker Image Size](https://img.shields.io/docker/image-size/itisfoundation/webserver)](https://hub.docker.com/r/itisfoundation/webserver/tags) | -| || | diff --git a/services/clusters-keeper/src/simcore_service_clusters_keeper/core/settings.py b/services/clusters-keeper/src/simcore_service_clusters_keeper/core/settings.py index 6595827ea6b..3e85015ee4a 100644 --- a/services/clusters-keeper/src/simcore_service_clusters_keeper/core/settings.py +++ b/services/clusters-keeper/src/simcore_service_clusters_keeper/core/settings.py @@ -381,9 +381,7 @@ def LOG_LEVEL(self) -> LogLevel: # noqa: N802 def _valid_log_level(cls, value: str) -> str: return cls.validate_log_level(value) - @field_validator( - "CLUSTERS_KEEPER_TASK_INTERVAL", "SERVICE_TRACKING_HEARTBEAT", mode="before" - ) + @field_validator("SERVICE_TRACKING_HEARTBEAT", mode="before") @classmethod def _validate_interval( cls, value: str | datetime.timedelta diff --git a/services/clusters-keeper/tests/unit/test_modules_clusters_management_task.py b/services/clusters-keeper/tests/unit/test_modules_clusters_management_task.py index d22bdce1f76..66bbf12c42e 100644 --- a/services/clusters-keeper/tests/unit/test_modules_clusters_management_task.py +++ b/services/clusters-keeper/tests/unit/test_modules_clusters_management_task.py @@ -13,8 +13,6 @@ from pytest_simcore.helpers.monkeypatch_envs import EnvVarsDict, setenvs_from_dict from simcore_service_clusters_keeper.core.settings import ApplicationSettings -_FAST_POLL_INTERVAL = 1 - @pytest.fixture def app_environment( @@ -22,7 +20,7 @@ def app_environment( monkeypatch: pytest.MonkeyPatch, ) -> EnvVarsDict: return app_environment | setenvs_from_dict( - monkeypatch, {"CLUSTERS_KEEPER_TASK_INTERVAL": f"{_FAST_POLL_INTERVAL}"} + monkeypatch, {"CLUSTERS_KEEPER_TASK_INTERVAL": "00:00:01"} ) @@ -43,10 +41,7 @@ async def test_clusters_management_task_created_and_deleted( initialized_app: FastAPI, app_settings: ApplicationSettings, ): - assert ( - app_settings.CLUSTERS_KEEPER_TASK_INTERVAL.total_seconds() - == _FAST_POLL_INTERVAL - ) + assert app_settings.CLUSTERS_KEEPER_TASK_INTERVAL.total_seconds() == 1 assert hasattr(initialized_app.state, "clusters_cleaning_task") - await asyncio.sleep(5 * _FAST_POLL_INTERVAL) + await asyncio.sleep(5) mock_background_task.assert_called() diff --git a/services/storage/Makefile b/services/storage/Makefile index 78686bd37b0..87234a46b62 100644 --- a/services/storage/Makefile +++ b/services/storage/Makefile @@ -4,10 +4,14 @@ include ../../scripts/common.Makefile include ../../scripts/common-service.Makefile +APP_OPENAPI_RELPATH=src/$(APP_PACKAGE_NAME)/api/v0/openapi.yaml + .PHONY: openapi-specs openapi-specs: ## updates and validates openapi specifications - $(MAKE) -C $(CURDIR)/src/simcore_service_${APP_NAME}/api $@ + $(MAKE_C) $(REPO_BASE_DIR)/api/specs/$(APP_NAME) all + # validates OAS file: $(APP_OPENAPI_RELPATH) + $(call validate_openapi_specs,$(APP_OPENAPI_RELPATH)) .PHONY: tests diff --git a/services/storage/VERSION b/services/storage/VERSION index 1d0ba9ea182..8f0916f768f 100644 --- a/services/storage/VERSION +++ b/services/storage/VERSION @@ -1 +1 @@ -0.4.0 +0.5.0 diff --git a/services/storage/requirements/_base.txt b/services/storage/requirements/_base.txt index 3c341f221f9..a3513a00a8f 100644 --- a/services/storage/requirements/_base.txt +++ b/services/storage/requirements/_base.txt @@ -179,8 +179,6 @@ idna==3.6 # yarl importlib-metadata==8.0.0 # via opentelemetry-api -isodate==0.6.1 - # via openapi-core jinja2==3.1.3 # via # -c requirements/../../../packages/aws-library/requirements/../../../packages/common-library/requirements/../../../requirements/constraints.txt @@ -221,19 +219,8 @@ jsonschema==4.21.1 # -r requirements/../../../packages/models-library/requirements/_base.in # -r requirements/../../../packages/service-library/requirements/../../../packages/models-library/requirements/_base.in # -r requirements/../../../packages/service-library/requirements/_aiohttp.in - # openapi-core - # openapi-schema-validator - # openapi-spec-validator -jsonschema-path==0.3.2 - # via - # openapi-core - # openapi-spec-validator jsonschema-specifications==2023.7.1 - # via - # jsonschema - # openapi-schema-validator -lazy-object-proxy==1.10.0 - # via openapi-spec-validator + # via jsonschema mako==1.3.2 # via # -c requirements/../../../packages/aws-library/requirements/../../../packages/common-library/requirements/../../../requirements/constraints.txt @@ -272,20 +259,10 @@ markupsafe==2.1.5 # werkzeug mdurl==0.1.2 # via markdown-it-py -more-itertools==10.2.0 - # via openapi-core multidict==6.0.5 # via # aiohttp # yarl -openapi-core==0.19.0 - # via -r requirements/../../../packages/service-library/requirements/_aiohttp.in -openapi-schema-validator==0.6.2 - # via - # openapi-core - # openapi-spec-validator -openapi-spec-validator==0.7.1 - # via openapi-core opentelemetry-api==1.26.0 # via # -r requirements/../../../packages/aws-library/requirements/../../../packages/service-library/requirements/_base.in @@ -425,10 +402,6 @@ packaging==24.0 # via -r requirements/_base.in pamqp==3.3.0 # via aiormq -parse==1.20.1 - # via openapi-core -pathable==0.4.3 - # via jsonschema-path prometheus-client==0.20.0 # via -r requirements/../../../packages/service-library/requirements/_aiohttp.in protobuf==4.25.4 @@ -573,7 +546,6 @@ pyyaml==6.0.1 # -r requirements/../../../packages/aws-library/requirements/../../../packages/service-library/requirements/_base.in # -r requirements/../../../packages/service-library/requirements/_base.in # aiohttp-swagger - # jsonschema-path redis==5.0.4 # via # -c requirements/../../../packages/aws-library/requirements/../../../packages/common-library/requirements/../../../requirements/constraints.txt @@ -606,21 +578,14 @@ redis==5.0.4 # -r requirements/../../../packages/service-library/requirements/_base.in referencing==0.29.3 # via - # -c requirements/../../../packages/aws-library/requirements/../../../packages/service-library/requirements/./constraints.txt - # -c requirements/../../../packages/service-library/requirements/./constraints.txt # jsonschema - # jsonschema-path # jsonschema-specifications repro-zipfile==0.3.1 # via # -r requirements/../../../packages/aws-library/requirements/../../../packages/service-library/requirements/_base.in # -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.2 - # via - # jsonschema-path - # opentelemetry-exporter-otlp-proto-http -rfc3339-validator==0.1.4 - # via openapi-schema-validator + # via opentelemetry-exporter-otlp-proto-http rich==13.7.1 # via # -r requirements/../../../packages/aws-library/requirements/../../../packages/service-library/requirements/../../../packages/settings-library/requirements/_base.in @@ -641,10 +606,7 @@ sh==2.0.6 shellingham==1.5.4 # via typer six==1.16.0 - # via - # isodate - # python-dateutil - # rfc3339-validator + # via python-dateutil sniffio==1.3.1 # via anyio sqlalchemy==1.4.52 @@ -786,9 +748,7 @@ urllib3==2.2.3 # botocore # requests werkzeug==3.0.2 - # via - # -r requirements/../../../packages/service-library/requirements/_aiohttp.in - # openapi-core + # via -r requirements/../../../packages/service-library/requirements/_aiohttp.in wrapt==1.16.0 # via # aiobotocore diff --git a/services/storage/requirements/_test.in b/services/storage/requirements/_test.in index be2d7cbf464..33b53a495bc 100644 --- a/services/storage/requirements/_test.in +++ b/services/storage/requirements/_test.in @@ -11,6 +11,7 @@ coverage docker faker fakeredis[lua] +jsonref moto[server] pandas pytest diff --git a/services/storage/requirements/_test.txt b/services/storage/requirements/_test.txt index 6157f084c4d..4d1791cf9e2 100644 --- a/services/storage/requirements/_test.txt +++ b/services/storage/requirements/_test.txt @@ -125,6 +125,8 @@ jsonpath-ng==1.6.1 # via moto jsonpointer==3.0.0 # via jsonpatch +jsonref==1.1.0 + # via -r requirements/_test.in jsonschema==4.21.1 # via # -c requirements/_base.txt @@ -132,18 +134,14 @@ jsonschema==4.21.1 # openapi-schema-validator # openapi-spec-validator jsonschema-path==0.3.2 - # via - # -c requirements/_base.txt - # openapi-spec-validator + # via openapi-spec-validator jsonschema-specifications==2023.7.1 # via # -c requirements/_base.txt # jsonschema # openapi-schema-validator lazy-object-proxy==1.10.0 - # via - # -c requirements/_base.txt - # openapi-spec-validator + # via openapi-spec-validator lupa==2.2 # via fakeredis markupsafe==2.1.5 @@ -169,13 +167,9 @@ networkx==3.3 numpy==2.1.1 # via pandas openapi-schema-validator==0.6.2 - # via - # -c requirements/_base.txt - # openapi-spec-validator + # via openapi-spec-validator openapi-spec-validator==0.7.1 - # via - # -c requirements/_base.txt - # moto + # via moto packaging==24.0 # via # -c requirements/_base.txt @@ -184,9 +178,7 @@ packaging==24.0 pandas==2.2.3 # via -r requirements/_test.in pathable==0.4.3 - # via - # -c requirements/_base.txt - # jsonschema-path + # via jsonschema-path pluggy==1.5.0 # via pytest ply==3.11 @@ -283,9 +275,7 @@ requests==2.32.2 responses==0.25.3 # via moto rfc3339-validator==0.1.4 - # via - # -c requirements/_base.txt - # openapi-schema-validator + # via openapi-schema-validator rpds-py==0.18.0 # via # -c requirements/_base.txt diff --git a/services/storage/setup.cfg b/services/storage/setup.cfg index 00a25d58eb4..c703b2e8101 100644 --- a/services/storage/setup.cfg +++ b/services/storage/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.4.0 +current_version = 0.5.0 commit = True message = services/storage api version: {current_version} → {new_version} tag = False @@ -7,19 +7,17 @@ commit_args = --no-verify [bumpversion:file:VERSION] -[bumpversion:file:../../api/specs/storage/openapi.yaml] - [bumpversion:file:./src/simcore_service_storage/api/v0/openapi.yaml] [tool:pytest] asyncio_mode = auto -markers = +markers = slow: marks tests as slow (deselect with '-m "not slow"') acceptance_test: "marks tests as 'acceptance tests' i.e. does the system do what the user expects? Typically those are workflows." testit: "marks test to run during development" heavy_load: "mark tests that require large amount of data" [mypy] -plugins = +plugins = pydantic.mypy sqlalchemy.ext.mypy.plugin diff --git a/services/storage/src/simcore_service_storage/api/Makefile b/services/storage/src/simcore_service_storage/api/Makefile deleted file mode 100644 index 078f7fdb898..00000000000 --- a/services/storage/src/simcore_service_storage/api/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -.DEFAULT_GOAL := openapi-specs - -APP_DIR := $(abspath $(CURDIR)../../../../) -APP_NAME := $(notdir $(APP_DIR)) - -API_MAJOR_VERSION := $(shell cat ${APP_DIR}/VERSION | cut -f1 -d.) -APP_API_DIR := $(CURDIR)/v${API_MAJOR_VERSION} -OAS_TARGET := ${APP_API_DIR}/openapi.yaml - -API_SPECS_DIR = $(abspath $(CURDIR)../../../../../../api/specs) -API_PARTS_DIR = ${API_SPECS_DIR}/${APP_NAME} -OAS_SOURCES = $(shell find ${API_PARTS_DIR} -type f -name '*.y*ml') - - -${OAS_TARGET}: ${OAS_SOURCES} - # bundling '${API_SPECS_DIR}/${APP_NAME}' to '${OAS_TARGET}' ... - @swagger-cli bundle \ - --outfile $@ \ - --type yaml \ - "${API_SPECS_DIR}/${APP_NAME}/openapi.yaml" - - -.PHONY: openapi-specs -openapi-specs: ${OAS_TARGET} ## creates and validates OpenAPI specs - # Validating bundled '${OAS_TARGET}' - @swagger-cli validate $< diff --git a/services/storage/src/simcore_service_storage/api/v0/openapi.yaml b/services/storage/src/simcore_service_storage/api/v0/openapi.yaml index 0fcd16aa29a..22f27d960ac 100644 --- a/services/storage/src/simcore_service_storage/api/v0/openapi.yaml +++ b/services/storage/src/simcore_service_storage/api/v0/openapi.yaml @@ -1,4 +1,4 @@ -openapi: 3.0.0 +openapi: 3.1.0 info: title: simcore-service-storage API description: API definition for simcore-service-storage service @@ -8,7 +8,7 @@ info: license: name: MIT url: https://github.com/ITISFoundation/osparc-simcore/blob/master/LICENSE - version: 0.4.0 + version: 0.5.0 servers: - url: / description: 'Default server: requests directed to serving url' @@ -28,27 +28,27 @@ paths: description: returns all the top level datasets a user has access to operationId: get_datasets_metadata parameters: - - required: true + - name: location_id + in: path + required: true schema: type: integer title: Location Id - name: location_id - in: path - - required: true + - name: user_id + in: query + required: true schema: type: integer exclusiveMinimum: true title: User Id minimum: 0 - name: user_id - in: query responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_simcore_service_storage.models.DatasetMetaData__' + $ref: '#/components/schemas/Envelope_list_DatasetMetaData__' /v0/locations/{location_id}/datasets/{dataset_id}/metadata: get: tags: @@ -57,44 +57,44 @@ paths: description: returns all the file meta data inside dataset with dataset_id operationId: get_files_metadata_dataset parameters: - - required: true + - name: location_id + in: path + required: true schema: type: integer title: Location Id - name: location_id + - name: dataset_id in: path - - required: true + required: true schema: type: string title: Dataset Id - name: dataset_id - in: path - - required: true + - name: user_id + in: query + required: true schema: type: integer exclusiveMinimum: true title: User Id minimum: 0 - name: user_id + - name: expand_dirs in: query - - description: Automatic directory expansion. This will be replaced by pagination - the future required: false schema: type: boolean - title: Expand Dirs description: Automatic directory expansion. This will be replaced by pagination the future default: true - name: expand_dirs - in: query + title: Expand Dirs + description: Automatic directory expansion. This will be replaced by pagination + the future responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_models_library.api_schemas_storage.FileMetaDataGet__' + $ref: '#/components/schemas/Envelope_list_FileMetaDataGet__' /v0/locations: get: tags: @@ -103,23 +103,23 @@ paths: description: Returns the list of available storage locations operationId: get_storage_locations parameters: - - required: true + - name: user_id + in: query + required: true schema: type: integer exclusiveMinimum: true title: User Id minimum: 0 - name: user_id - in: query responses: '200': description: Successful Response content: application/json: schema: + type: array items: $ref: '#/components/schemas/DatasetMetaData' - type: array title: Response Get Storage Locations /v0/locations/{location_id}:sync: post: @@ -130,26 +130,26 @@ paths: description: Returns an object containing added, changed and removed paths operationId: synchronise_meta_data_table parameters: - - required: true + - name: location_id + in: path + required: true schema: type: integer title: Location Id - name: location_id - in: path - - required: false + - name: dry_run + in: query + required: false schema: type: boolean - title: Dry Run default: false - name: dry_run + title: Dry Run + - name: fire_and_forget in: query - - required: false + required: false schema: type: boolean - title: Fire And Forget default: false - name: fire_and_forget - in: query + title: Fire And Forget responses: '200': description: Successful Response @@ -166,37 +166,37 @@ paths: may be used) operationId: get_files_metadata parameters: - - required: true + - name: location_id + in: path + required: true schema: type: integer title: Location Id - name: location_id - in: path - - required: false + - name: uuid_filter + in: query + required: false schema: type: string - title: Uuid Filter default: '' - name: uuid_filter + title: Uuid Filter + - name: expand_dirs in: query - - description: Automatic directory expansion. This will be replaced by pagination - the future required: false schema: type: boolean - title: Expand Dirs description: Automatic directory expansion. This will be replaced by pagination the future default: true - name: expand_dirs - in: query + title: Expand Dirs + description: Automatic directory expansion. This will be replaced by pagination + the future responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_simcore_service_storage.models.DatasetMetaData__' + $ref: '#/components/schemas/Envelope_list_DatasetMetaData__' /v0/locations/{location_id}/files/{file_id}/metadata: get: tags: @@ -206,13 +206,15 @@ paths: to operationId: get_file_metadata parameters: - - required: true + - name: location_id + in: path + required: true schema: type: integer title: Location Id - name: location_id + - name: file_id in: path - - required: true + required: true schema: anyOf: - type: string @@ -220,16 +222,14 @@ paths: - type: string pattern: ^N:package:[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}$ title: File Id - name: file_id - in: path - - required: true + - name: user_id + in: query + required: true schema: type: integer exclusiveMinimum: true title: User Id minimum: 0 - name: user_id - in: query responses: '200': description: Successful Response @@ -248,13 +248,15 @@ paths: description: creates a download file link if user has the rights to operationId: download_file parameters: - - required: true + - name: location_id + in: path + required: true schema: type: integer title: Location Id - name: location_id + - name: file_id in: path - - required: true + required: true schema: anyOf: - type: string @@ -262,23 +264,20 @@ paths: - type: string pattern: ^N:package:[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}$ title: File Id - name: file_id - in: path - - required: true + - name: user_id + in: query + required: true schema: type: integer exclusiveMinimum: true title: User Id minimum: 0 - name: user_id + - name: link_type in: query - - required: false + required: false schema: - allOf: - - $ref: '#/components/schemas/LinkType' + $ref: '#/components/schemas/LinkType' default: PRESIGNED - name: link_type - in: query responses: '200': description: Successful Response @@ -294,13 +293,15 @@ paths: expects the client to complete/abort upload operationId: upload_file parameters: - - required: true + - name: location_id + in: path + required: true schema: type: integer title: Location Id - name: location_id + - name: file_id in: path - - required: true + required: true schema: anyOf: - type: string @@ -308,28 +309,30 @@ paths: - type: string pattern: ^N:package:[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}$ title: File Id - name: file_id - in: path - - required: true + - name: file_size + in: query + required: true schema: - type: integer + anyOf: + - type: string + pattern: ^\s*(\d*\.?\d+)\s*(\w+)? + - type: integer + minimum: 0 + - type: 'null' title: File Size - name: file_size + - name: link_type in: query - - required: false + required: false schema: - allOf: - - $ref: '#/components/schemas/LinkType' + $ref: '#/components/schemas/LinkType' default: PRESIGNED - name: link_type + - name: is_directory in: query - - required: false + required: false schema: type: boolean - title: Is Directory default: false - name: is_directory - in: query + title: Is Directory responses: '200': description: Successful Response @@ -338,7 +341,7 @@ paths: schema: anyOf: - $ref: '#/components/schemas/Envelope_FileUploadSchema_' - - $ref: '#/components/schemas/Envelope_AnyUrl_' + - $ref: '#/components/schemas/Envelope_Url_' title: Response Upload File delete: tags: @@ -347,13 +350,15 @@ paths: description: deletes file if user has the rights to operationId: delete_file parameters: - - required: true + - name: location_id + in: path + required: true schema: type: integer title: Location Id - name: location_id + - name: file_id in: path - - required: true + required: true schema: anyOf: - type: string @@ -361,16 +366,14 @@ paths: - type: string pattern: ^N:package:[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}$ title: File Id - name: file_id - in: path - - required: true + - name: user_id + in: query + required: true schema: type: integer exclusiveMinimum: true title: User Id minimum: 0 - name: user_id - in: query responses: '204': description: Successful Response @@ -384,13 +387,15 @@ paths: to the latest version if available, else will delete the file' operationId: abort_upload_file parameters: - - required: true + - name: location_id + in: path + required: true schema: type: integer title: Location Id - name: location_id + - name: file_id in: path - - required: true + required: true schema: anyOf: - type: string @@ -398,16 +403,14 @@ paths: - type: string pattern: ^N:package:[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}$ title: File Id - name: file_id - in: path - - required: true + - name: user_id + in: query + required: true schema: type: integer exclusiveMinimum: true title: User Id minimum: 0 - name: user_id - in: query responses: '204': description: Successful Response @@ -419,13 +422,15 @@ paths: description: completes an upload if the user has the rights to operationId: complete_upload_file parameters: - - required: true + - name: location_id + in: path + required: true schema: type: integer title: Location Id - name: location_id + - name: file_id in: path - - required: true + required: true schema: anyOf: - type: string @@ -433,22 +438,20 @@ paths: - type: string pattern: ^N:package:[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}$ title: File Id - name: file_id - in: path - - required: true + - name: user_id + in: query + required: true schema: type: integer exclusiveMinimum: true title: User Id minimum: 0 - name: user_id - in: query requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/Envelope_FileUploadCompletionBody_' - required: true responses: '202': description: Successful Response @@ -464,13 +467,15 @@ paths: description: Returns state of upload completion operationId: is_completed_upload_file parameters: - - required: true + - name: location_id + in: path + required: true schema: type: integer title: Location Id - name: location_id + - name: file_id in: path - - required: true + required: true schema: anyOf: - type: string @@ -478,22 +483,20 @@ paths: - type: string pattern: ^N:package:[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}$ title: File Id - name: file_id + - name: future_id in: path - - required: true + required: true schema: type: string title: Future Id - name: future_id - in: path - - required: true + - name: user_id + in: query + required: true schema: type: integer exclusiveMinimum: true title: User Id minimum: 0 - name: user_id - in: query responses: '200': description: Successful Response @@ -537,7 +540,9 @@ paths: description: creates and returns a soft link operationId: copy_as_soft_link parameters: - - required: true + - name: file_id + in: path + required: true schema: anyOf: - type: string @@ -545,22 +550,20 @@ paths: - type: string pattern: ^N:package:[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}$ title: File Id - name: file_id - in: path - - required: true + - name: user_id + in: query + required: true schema: type: integer exclusiveMinimum: true title: User Id minimum: 0 - name: user_id - in: query requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/SoftCopyBody' - required: true responses: '200': description: Successful Response @@ -576,14 +579,14 @@ paths: description: returns a set of S3 credentials operationId: get_or_create_temporary_s3_access parameters: - - required: true + - name: user_id + in: query + required: true schema: type: integer exclusiveMinimum: true title: User Id minimum: 0 - name: user_id - in: query responses: '200': description: Successful Response @@ -599,20 +602,20 @@ paths: description: copies folders from project operationId: copy_folders_from_project parameters: - - required: true + - name: user_id + in: query + required: true schema: type: integer exclusiveMinimum: true title: User Id minimum: 0 - name: user_id - in: query requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/FoldersBody' - required: true responses: '200': description: Successful Response @@ -628,27 +631,29 @@ paths: description: removes folders from a project operationId: delete_folders_of_project parameters: - - required: true + - name: folder_id + in: path + required: true schema: type: string title: Folder Id - name: folder_id - in: path - - required: true + - name: user_id + in: query + required: true schema: type: integer exclusiveMinimum: true title: User Id minimum: 0 - name: user_id + - name: node_id in: query - - required: false + required: false schema: - type: string - format: uuid + anyOf: + - type: string + format: uuid + - type: 'null' title: Node Id - name: node_id - in: query responses: '204': description: Successful Response @@ -656,43 +661,62 @@ paths: post: tags: - simcore-s3 - summary: search for files starting with + summary: search for owned files description: search for files starting with `startswith` and/or matching a sha256_checksum in the file_meta_data table operationId: search_files parameters: - - required: true + - name: user_id + in: query + required: true schema: type: integer exclusiveMinimum: true title: User Id minimum: 0 - name: user_id + - name: startswith in: query - - required: false + required: false schema: - type: string + anyOf: + - type: string + - type: 'null' title: Startswith - default: '' - name: startswith + - name: sha256_checksum in: query - - required: false + required: false schema: - type: string - pattern: ^[a-fA-F0-9]{64}$ + anyOf: + - type: string + pattern: ^[a-fA-F0-9]{64}$ + - type: 'null' title: Sha256 Checksum - name: sha256_checksum + - name: kind in: query - - required: false + required: true schema: - type: string enum: - - read - - write - title: Access Right - default: read - name: access_right + - owned + const: owned + type: string + title: Kind + - name: limit + in: query + required: false + schema: + type: integer + maximum: 50 + minimum: 1 + default: 20 + title: Limit + - name: offset in: query + required: false + schema: + type: integer + minimum: 0 + default: 0 + title: Offset responses: '200': description: Successful Response @@ -722,12 +746,12 @@ paths: description: gets the status of the task operationId: get_task_status parameters: - - required: true + - name: task_id + in: path + required: true schema: type: string title: Task Id - name: task_id - in: path responses: '200': description: Successful Response @@ -742,12 +766,12 @@ paths: description: cancels and removes the task operationId: cancel_and_delete_task parameters: - - required: true + - name: task_id + in: path + required: true schema: type: string title: Task Id - name: task_id - in: path responses: '204': description: Successful Response @@ -759,12 +783,12 @@ paths: description: get result of the task operationId: get_task_result parameters: - - required: true + - name: task_id + in: path + required: true schema: type: string title: Task Id - name: task_id - in: path responses: '200': description: Successful Response @@ -790,23 +814,27 @@ components: description: Other backend services connected from this service default: {} sessions: - type: object + anyOf: + - type: object + - type: 'null' title: Sessions description: Client sessions info. If single session per app, then is denoted as main default: {} url: - type: string - maxLength: 65536 - minLength: 1 - format: uri + anyOf: + - type: string + minLength: 1 + format: uri + - type: 'null' title: Url description: Link to current resource diagnostics_url: - type: string - maxLength: 65536 - minLength: 1 - format: uri + anyOf: + - type: string + minLength: 1 + format: uri + - type: 'null' title: Diagnostics Url description: Link to diagnostics report sub-resource. This MIGHT take some time to compute @@ -833,136 +861,210 @@ components: - dataset_id - display_name title: DatasetMetaData - Envelope_AnyUrl_: - properties: - data: - type: string - maxLength: 65536 - minLength: 1 - format: uri - title: Data - error: - title: Error - type: object - title: Envelope[AnyUrl] Envelope_AppStatusCheck_: properties: data: - $ref: '#/components/schemas/AppStatusCheck' + anyOf: + - $ref: '#/components/schemas/AppStatusCheck' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error type: object title: Envelope[AppStatusCheck] Envelope_FileMetaDataGet_: properties: data: - $ref: '#/components/schemas/FileMetaDataGet' + anyOf: + - $ref: '#/components/schemas/FileMetaDataGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error type: object title: Envelope[FileMetaDataGet] Envelope_FileUploadCompleteFutureResponse_: properties: data: - $ref: '#/components/schemas/FileUploadCompleteFutureResponse' + anyOf: + - $ref: '#/components/schemas/FileUploadCompleteFutureResponse' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error type: object title: Envelope[FileUploadCompleteFutureResponse] Envelope_FileUploadCompleteResponse_: properties: data: - $ref: '#/components/schemas/FileUploadCompleteResponse' + anyOf: + - $ref: '#/components/schemas/FileUploadCompleteResponse' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error type: object title: Envelope[FileUploadCompleteResponse] Envelope_FileUploadCompletionBody_: properties: data: - $ref: '#/components/schemas/FileUploadCompletionBody' + anyOf: + - $ref: '#/components/schemas/FileUploadCompletionBody' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error type: object title: Envelope[FileUploadCompletionBody] Envelope_FileUploadSchema_: properties: data: - $ref: '#/components/schemas/FileUploadSchema' + anyOf: + - $ref: '#/components/schemas/FileUploadSchema' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error type: object title: Envelope[FileUploadSchema] Envelope_HealthCheck_: properties: data: - $ref: '#/components/schemas/HealthCheck' + anyOf: + - $ref: '#/components/schemas/HealthCheck' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error type: object title: Envelope[HealthCheck] Envelope_PresignedLink_: properties: data: - $ref: '#/components/schemas/PresignedLink' + anyOf: + - $ref: '#/components/schemas/PresignedLink' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error type: object title: Envelope[PresignedLink] Envelope_S3Settings_: properties: data: - $ref: '#/components/schemas/S3Settings' + anyOf: + - $ref: '#/components/schemas/S3Settings' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error type: object title: Envelope[S3Settings] Envelope_TableSynchronisation_: properties: data: - $ref: '#/components/schemas/TableSynchronisation' + anyOf: + - $ref: '#/components/schemas/TableSynchronisation' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error type: object title: Envelope[TableSynchronisation] Envelope_TaskGet_: properties: data: - $ref: '#/components/schemas/TaskGet' + anyOf: + - $ref: '#/components/schemas/TaskGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error type: object title: Envelope[TaskGet] Envelope_TaskStatus_: properties: data: - $ref: '#/components/schemas/TaskStatus' + anyOf: + - $ref: '#/components/schemas/TaskStatus' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error type: object title: Envelope[TaskStatus] - Envelope_list_models_library.api_schemas_storage.FileMetaDataGet__: + Envelope_Url_: properties: data: - items: - $ref: '#/components/schemas/FileMetaDataGet' - type: array + anyOf: + - type: string + minLength: 1 + format: uri + - type: 'null' title: Data error: + anyOf: + - {} + - type: 'null' title: Error type: object - title: Envelope[list[models_library.api_schemas_storage.FileMetaDataGet]] - Envelope_list_simcore_service_storage.models.DatasetMetaData__: + title: Envelope[Url] + Envelope_list_DatasetMetaData__: properties: data: - items: - $ref: '#/components/schemas/DatasetMetaData' - type: array + anyOf: + - items: + $ref: '#/components/schemas/DatasetMetaData' + type: array + - type: 'null' title: Data error: + anyOf: + - {} + - type: 'null' title: Error type: object - title: Envelope[list[simcore_service_storage.models.DatasetMetaData]] + title: Envelope[list[DatasetMetaData]] + Envelope_list_FileMetaDataGet__: + properties: + data: + anyOf: + - items: + $ref: '#/components/schemas/FileMetaDataGet' + type: array + - type: 'null' + title: Data + error: + anyOf: + - {} + - type: 'null' + title: Error + type: object + title: Envelope[list[FileMetaDataGet]] FileMetaData: properties: file_uuid: @@ -975,11 +1077,15 @@ components: title: Location Id description: Storage location project_name: - type: string + anyOf: + - type: string + - type: 'null' title: Project Name description: optional project name, used by frontend to display path node_name: - type: string + anyOf: + - type: string + - type: 'null' title: Node Name description: optional node name, used by frontend to display path file_name: @@ -1006,12 +1112,18 @@ components: file_size: anyOf: - type: integer + enum: + - -1 + const: -1 - type: integer + minimum: 0 title: File Size description: File size in bytes (-1 means invalid) default: -1 entity_tag: - type: string + anyOf: + - type: string + - type: 'null' title: Entity Tag description: Entity tag (or ETag), represents a specific version of the file, None if invalid upload or datcore @@ -1027,15 +1139,21 @@ components: description: if True this is a directory default: false sha256_checksum: - type: string - pattern: ^[a-fA-F0-9]{64}$ + anyOf: + - type: string + pattern: ^[a-fA-F0-9]{64}$ + - type: 'null' title: Sha256 Checksum upload_id: - type: string + anyOf: + - type: string + - type: 'null' title: Upload Id upload_expires_at: - type: string - format: date-time + anyOf: + - type: string + format: date-time + - type: 'null' title: Upload Expires At location: type: string @@ -1047,19 +1165,24 @@ components: type: string title: Object Name project_id: - type: string - format: uuid + anyOf: + - type: string + format: uuid + - type: 'null' title: Project Id node_id: - type: string - format: uuid + anyOf: + - type: string + format: uuid + - type: 'null' title: Node Id user_id: - type: integer - exclusiveMinimum: true + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' title: User Id - minimum: 0 - additionalProperties: false type: object required: - file_uuid @@ -1068,9 +1191,13 @@ components: - file_id - created_at - last_modified + - sha256_checksum - location - bucket_name - object_name + - project_id + - node_id + - user_id title: FileMetaData FileMetaDataGet: properties: @@ -1084,11 +1211,15 @@ components: title: Location Id description: Storage location project_name: - type: string + anyOf: + - type: string + - type: 'null' title: Project Name description: optional project name, used by frontend to display path node_name: - type: string + anyOf: + - type: string + - type: 'null' title: Node Name description: optional node name, used by frontend to display path file_name: @@ -1115,12 +1246,18 @@ components: file_size: anyOf: - type: integer + enum: + - -1 + const: -1 - type: integer + minimum: 0 title: File Size description: File size in bytes (-1 means invalid) default: -1 entity_tag: - type: string + anyOf: + - type: string + - type: 'null' title: Entity Tag description: Entity tag (or ETag), represents a specific version of the file, None if invalid upload or datcore @@ -1136,12 +1273,13 @@ components: description: if True this is a directory default: false sha256_checksum: - type: string - pattern: ^[a-fA-F0-9]{64}$ + anyOf: + - type: string + pattern: ^[a-fA-F0-9]{64}$ + - type: 'null' title: Sha256 Checksum description: 'SHA256 message digest of the file content. Main purpose: cheap lookup.' - additionalProperties: false type: object required: - file_uuid @@ -1156,7 +1294,9 @@ components: state: $ref: '#/components/schemas/FileUploadCompleteState' e_tag: - type: string + anyOf: + - type: string + - type: 'null' title: E Tag type: object required: @@ -1166,7 +1306,6 @@ components: properties: state: type: string - maxLength: 65536 minLength: 1 format: uri title: State @@ -1183,11 +1322,11 @@ components: - links title: FileUploadCompleteResponse FileUploadCompleteState: + type: string enum: - ok - nok title: FileUploadCompleteState - description: An enumeration. FileUploadCompletionBody: properties: parts: @@ -1203,13 +1342,11 @@ components: properties: abort_upload: type: string - maxLength: 65536 minLength: 1 format: uri title: Abort Upload complete_upload: type: string - maxLength: 65536 minLength: 1 format: uri title: Complete Upload @@ -1222,11 +1359,11 @@ components: properties: chunk_size: type: integer + minimum: 0 title: Chunk Size urls: items: type: string - maxLength: 65536 minLength: 1 format: uri type: array @@ -1258,18 +1395,31 @@ components: HealthCheck: properties: name: - type: string + anyOf: + - type: string + - type: 'null' title: Name status: - type: string + anyOf: + - type: string + - type: 'null' title: Status api_version: - type: string + anyOf: + - type: string + - type: 'null' title: Api Version version: - type: string + anyOf: + - type: string + - type: 'null' title: Version type: object + required: + - name + - status + - api_version + - version title: HealthCheck LinkType: type: string @@ -1277,12 +1427,10 @@ components: - PRESIGNED - S3 title: LinkType - description: An enumeration. PresignedLink: properties: link: type: string - maxLength: 65536 minLength: 1 format: uri title: Link @@ -1292,41 +1440,42 @@ components: title: PresignedLink S3Settings: properties: - S3_SECURE: - type: boolean - title: S3 Secure - default: false - S3_ENDPOINT: - type: string - title: S3 Endpoint S3_ACCESS_KEY: type: string + maxLength: 50 + minLength: 1 title: S3 Access Key - S3_SECRET_KEY: - type: string - title: S3 Secret Key - S3_ACCESS_TOKEN: - type: string - title: S3 Access Token S3_BUCKET_NAME: type: string + maxLength: 50 + minLength: 1 title: S3 Bucket Name + S3_ENDPOINT: + anyOf: + - type: string + minLength: 1 + format: uri + - type: 'null' + title: S3 Endpoint + description: do not define if using standard AWS S3_REGION: type: string + maxLength: 50 + minLength: 1 title: S3 Region - default: us-east-1 + S3_SECRET_KEY: + type: string + maxLength: 50 + minLength: 1 + title: S3 Secret Key additionalProperties: false type: object required: - - S3_ENDPOINT - S3_ACCESS_KEY - - S3_SECRET_KEY - S3_BUCKET_NAME + - S3_REGION + - S3_SECRET_KEY title: S3Settings - description: "- Customized configuration for all settings\n- If a field is a\ - \ BaseCustomSettings subclass, it allows creating a default from env vars\ - \ setting the Field\n option 'auto_default_from_env=True'.\n\nSEE tests for\ - \ details." SoftCopyBody: properties: link_id: @@ -1340,10 +1489,14 @@ components: TableSynchronisation: properties: dry_run: - type: boolean + anyOf: + - type: boolean + - type: 'null' title: Dry Run fire_and_forget: - type: boolean + anyOf: + - type: boolean + - type: 'null' title: Fire And Forget removed: items: @@ -1381,6 +1534,11 @@ components: title: TaskGet TaskProgress: properties: + task_id: + anyOf: + - type: string + - type: 'null' + title: Task Id message: type: string title: Message diff --git a/services/storage/tests/conftest.py b/services/storage/tests/conftest.py index 1fc8719cfa7..8dc4a95b488 100644 --- a/services/storage/tests/conftest.py +++ b/services/storage/tests/conftest.py @@ -75,6 +75,7 @@ "pytest_simcore.file_extra", "pytest_simcore.httpbin_service", "pytest_simcore.minio_service", + "pytest_simcore.openapi_specs", "pytest_simcore.postgres_service", "pytest_simcore.pytest_global_environs", "pytest_simcore.repository_paths", diff --git a/services/storage/tests/unit/test__openapi_specs.py b/services/storage/tests/unit/test__openapi_specs.py index 5e35ff7a7cf..a32ae3ace6e 100644 --- a/services/storage/tests/unit/test__openapi_specs.py +++ b/services/storage/tests/unit/test__openapi_specs.py @@ -3,26 +3,26 @@ # pylint: disable=unused-argument # pylint: disable=unused-variable +from collections.abc import Callable from pathlib import Path -from typing import NamedTuple -import openapi_core import pytest import simcore_service_storage.application from aiohttp import web from faker import Faker -from openapi_core import Spec as OpenApiSpecs from pytest_simcore.helpers.monkeypatch_envs import setenvs_from_dict from pytest_simcore.helpers.typing_env import EnvVarsDict +from pytest_simcore.openapi_specs import Entrypoint from simcore_service_storage._meta import API_VTAG from simcore_service_storage.resources import storage_resources from simcore_service_storage.settings import Settings -class Entrypoint(NamedTuple): - name: str - method: str - path: str +@pytest.fixture(scope="session") +def openapi_specs_path() -> Path: + # overrides pytest_simcore.openapi_specs.app_openapi_specs_path fixture + spec_path: Path = storage_resources.get_path(f"api/{API_VTAG}/openapi.yaml") + return spec_path @pytest.fixture @@ -42,6 +42,7 @@ def app_environment( @pytest.fixture def app(app_environment: EnvVarsDict) -> web.Application: + assert app_environment # Expects that: # - routings happen during setup! # - all plugins are setup but app is NOT started (i.e events are not triggered) @@ -50,61 +51,20 @@ def app(app_environment: EnvVarsDict) -> web.Application: return simcore_service_storage.application.create(settings) -@pytest.fixture(scope="module") -def openapi_specs() -> openapi_core.Spec: - spec_path: Path = storage_resources.get_path(f"api/{API_VTAG}/openapi.yaml") - return openapi_core.Spec.from_path(spec_path) - - -@pytest.fixture -def expected_openapi_entrypoints(openapi_specs: OpenApiSpecs) -> set[Entrypoint]: - entrypoints: set[Entrypoint] = set() - - # openapi-specifications, i.e. "contract" - for path, path_obj in openapi_specs["paths"].items(): - for operation, operation_obj in path_obj.items(): - entrypoints.add( - Entrypoint( - method=operation.upper(), - path=path, - name=operation_obj["operationId"], - ) - ) - return entrypoints - - @pytest.fixture -def app_entrypoints(app: web.Application) -> set[Entrypoint]: - entrypoints: set[Entrypoint] = set() - - # app routes, i.e. "exposed" - for resource_name, resource in app.router.named_resources().items(): - resource_path = resource.canonical - for route in resource: - assert route.name == resource_name - assert route.resource - assert route.name is not None - - if route.method == "HEAD": - continue - - entrypoints.add( - Entrypoint( - method=route.method, - path=resource_path, - name=route.name, - ) - ) - return entrypoints +def app_rest_entrypoints( + app: web.Application, + create_aiohttp_app_rest_entrypoints: Callable[[web.Application], set[Entrypoint]], +) -> set[Entrypoint]: + # check whether exposed routes implements openapi.json contract + return create_aiohttp_app_rest_entrypoints(app) def test_app_named_resources_against_openapi_specs( - expected_openapi_entrypoints: set[Entrypoint], - app_entrypoints: set[Entrypoint], + openapi_specs_entrypoints: set[Entrypoint], + app_rest_entrypoints: set[Entrypoint], ): - # check whether exposed routes implements openapi.json contract - - assert app_entrypoints == expected_openapi_entrypoints + assert app_rest_entrypoints == openapi_specs_entrypoints # NOTE: missing here is: # - input schemas (path, query and body) diff --git a/services/web/server/Makefile b/services/web/server/Makefile index 8455f0267e9..f09876cf523 100644 --- a/services/web/server/Makefile +++ b/services/web/server/Makefile @@ -13,6 +13,10 @@ requirements: ## compiles pip requirements (.in -> .txt) @$(MAKE_C) requirements reqs +APP_OPENAPI_RELPATH=src/$(PY_PACKAGE_NAME)/api/v0/openapi.yaml + .PHONY: openapi-specs openapi-specs: ## updates and validates openapi specifications $(MAKE_C) $(REPO_BASE_DIR)/api/specs/web-server all + # validates OAS file: $(APP_OPENAPI_RELPATH) + $(call validate_openapi_specs,$(APP_OPENAPI_RELPATH)) diff --git a/services/web/server/VERSION b/services/web/server/VERSION index bcce5d06b8a..301092317fe 100644 --- a/services/web/server/VERSION +++ b/services/web/server/VERSION @@ -1 +1 @@ -0.45.0 +0.46.0 diff --git a/services/web/server/requirements/_base.txt b/services/web/server/requirements/_base.txt index bacb3f9dced..11bc97fb4bb 100644 --- a/services/web/server/requirements/_base.txt +++ b/services/web/server/requirements/_base.txt @@ -114,7 +114,6 @@ attrs==21.4.0 # -r requirements/../../../../packages/service-library/requirements/_aiohttp.in # aiohttp # jsonschema - # openapi-core bidict==0.22.0 # via python-socketio captcha==0.5.0 @@ -237,8 +236,6 @@ idna==3.3 # yarl importlib-metadata==8.0.0 # via opentelemetry-api -isodate==0.6.1 - # via openapi-core jinja-app-loader==1.0.2 # via -r requirements/_base.in jinja2==3.1.2 @@ -284,10 +281,6 @@ jsonschema==3.2.0 # -r requirements/../../../../packages/service-library/requirements/_aiohttp.in # -r requirements/../../../../packages/simcore-sdk/requirements/../../../packages/models-library/requirements/_base.in # -r requirements/../../../../packages/simcore-sdk/requirements/../../../packages/service-library/requirements/../../../packages/models-library/requirements/_base.in - # openapi-schema-validator - # openapi-spec-validator -lazy-object-proxy==1.7.1 - # via openapi-core mako==1.2.2 # via # -c requirements/../../../../packages/common-library/requirements/../../../requirements/constraints.txt @@ -333,12 +326,6 @@ multidict==6.1.0 # via # aiohttp # yarl -openapi-core==0.12.0 - # via -r requirements/../../../../packages/service-library/requirements/_aiohttp.in -openapi-schema-validator==0.2.3 - # via openapi-spec-validator -openapi-spec-validator==0.4.0 - # via openapi-core openpyxl==3.0.9 # via -r requirements/_base.in opentelemetry-api==1.27.0 @@ -594,7 +581,6 @@ pydantic-extra-types==2.9.0 # -r requirements/../../../../packages/simcore-sdk/requirements/../../../packages/settings-library/requirements/../../../packages/common-library/requirements/_base.in pydantic-settings==2.5.2 # via - # -c requirements/./constraints.txt # -r requirements/../../../../packages/models-library/requirements/_base.in # -r requirements/../../../../packages/service-library/requirements/../../../packages/models-library/requirements/_base.in # -r requirements/../../../../packages/service-library/requirements/../../../packages/settings-library/requirements/_base.in @@ -660,7 +646,6 @@ pyyaml==6.0.1 # -r requirements/../../../../packages/service-library/requirements/_base.in # -r requirements/../../../../packages/simcore-sdk/requirements/../../../packages/service-library/requirements/_base.in # aiohttp-swagger - # openapi-spec-validator redis==5.0.4 # via # -c requirements/../../../../packages/common-library/requirements/../../../requirements/constraints.txt @@ -714,15 +699,12 @@ setproctitle==1.3.3 setuptools==69.1.1 # via # jsonschema - # openapi-spec-validator # opentelemetry-instrumentation shellingham==1.5.4 # via typer six==1.16.0 # via - # isodate # jsonschema - # openapi-core # python-dateutil sniffio==1.3.1 # via anyio @@ -760,8 +742,6 @@ sqlalchemy==1.4.47 # -r requirements/../../../../packages/simcore-sdk/requirements/../../../packages/postgres-database/requirements/_base.in # aiopg # alembic -strict-rfc3339==0.7 - # via openapi-core tenacity==8.5.0 # via # -r requirements/../../../../packages/service-library/requirements/_base.in diff --git a/services/web/server/requirements/_test.txt b/services/web/server/requirements/_test.txt index 54ecb02f5e4..6ac8bbec1e1 100644 --- a/services/web/server/requirements/_test.txt +++ b/services/web/server/requirements/_test.txt @@ -107,13 +107,9 @@ mypy==1.12.0 mypy-extensions==1.0.0 # via mypy openapi-schema-validator==0.2.3 - # via - # -c requirements/_base.txt - # openapi-spec-validator + # via openapi-spec-validator openapi-spec-validator==0.4.0 - # via - # -c requirements/_base.txt - # -r requirements/_test.in + # via -r requirements/_test.in packaging==24.1 # via # -c requirements/_base.txt diff --git a/services/web/server/setup.cfg b/services/web/server/setup.cfg index 2b54478220b..0c5bbbcb6b3 100644 --- a/services/web/server/setup.cfg +++ b/services/web/server/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.45.0 +current_version = 0.46.0 commit = True message = services/webserver api version: {current_version} → {new_version} tag = False diff --git a/services/web/server/src/simcore_service_webserver/api/v0/openapi.yaml b/services/web/server/src/simcore_service_webserver/api/v0/openapi.yaml index df35af2db92..688d2187cb3 100644 --- a/services/web/server/src/simcore_service_webserver/api/v0/openapi.yaml +++ b/services/web/server/src/simcore_service_webserver/api/v0/openapi.yaml @@ -1,8 +1,8 @@ -openapi: 3.0.2 +openapi: 3.1.0 info: title: simcore-service-webserver description: Main service with an interface (http-API & websockets) to the web front-end - version: 0.45.0 + version: 0.46.0 servers: - url: '' description: webserver @@ -283,18 +283,18 @@ paths: description: changes password using a token code without being logged in operationId: auth_reset_password_allowed parameters: - - required: true + - name: code + in: path + required: true schema: - title: Code type: string - name: code - in: path + title: Code requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/ResetPasswordConfirmation' - required: true responses: '200': description: Successful Response @@ -354,12 +354,12 @@ paths: description: email link sent to user to confirm an action operationId: auth_confirmation parameters: - - required: true + - name: code + in: path + required: true schema: - title: Code type: string - name: code - in: path + title: Code responses: '200': description: Successful Response @@ -382,10 +382,10 @@ paths: content: application/json: schema: - title: Response 200 List Api Keys - type: array items: type: string + type: array + title: Response 200 List Api Keys '400': description: key name requested is invalid '401': @@ -491,14 +491,14 @@ paths: description: Get an organization group operationId: get_group parameters: - - required: true + - name: gid + in: path + required: true schema: - title: Gid - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Gid minimum: 0 - name: gid - in: path responses: '200': description: Successful Response @@ -506,24 +506,6 @@ paths: application/json: schema: $ref: '#/components/schemas/Envelope_GroupGet_' - delete: - tags: - - groups - summary: Delete Group - description: Deletes organization groups - operationId: delete_group - parameters: - - required: true - schema: - title: Gid - exclusiveMinimum: true - type: integer - minimum: 0 - name: gid - in: path - responses: - '204': - description: Successful Response patch: tags: - groups @@ -531,20 +513,20 @@ paths: description: Updates organization groups operationId: update_group parameters: - - required: true + - name: gid + in: path + required: true schema: - title: Gid - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Gid minimum: 0 - name: gid - in: path requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/GroupUpdate' - required: true responses: '200': description: Successful Response @@ -552,6 +534,24 @@ paths: application/json: schema: $ref: '#/components/schemas/Envelope_GroupGet_' + delete: + tags: + - groups + summary: Delete Group + description: Deletes organization groups + operationId: delete_group + parameters: + - name: gid + in: path + required: true + schema: + type: integer + exclusiveMinimum: true + title: Gid + minimum: 0 + responses: + '204': + description: Successful Response /v0/groups/{gid}/users: get: tags: @@ -560,21 +560,21 @@ paths: description: Gets users in organization groups operationId: get_all_group_users parameters: - - required: true + - name: gid + in: path + required: true schema: - title: Gid - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Gid minimum: 0 - name: gid - in: path responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_models_library.api_schemas_webserver.groups.GroupUserGet__' + $ref: '#/components/schemas/Envelope_list_GroupUserGet__' post: tags: - groups @@ -582,20 +582,20 @@ paths: description: Adds a user to an organization group operationId: add_group_user parameters: - - required: true + - name: gid + in: path + required: true schema: - title: Gid - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Gid minimum: 0 - name: gid - in: path requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/GroupUserAdd' - required: true responses: '204': description: Successful Response @@ -607,22 +607,22 @@ paths: description: Gets specific user in an organization group operationId: get_group_user parameters: - - required: true + - name: gid + in: path + required: true schema: - title: Gid - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Gid minimum: 0 - name: gid + - name: uid in: path - - required: true + required: true schema: - title: Uid - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Uid minimum: 0 - name: uid - in: path responses: '200': description: Successful Response @@ -630,32 +630,6 @@ paths: application/json: schema: $ref: '#/components/schemas/Envelope_GroupUserGet_' - delete: - tags: - - groups - summary: Delete Group User - description: Removes a user from an organization group - operationId: delete_group_user - parameters: - - required: true - schema: - title: Gid - exclusiveMinimum: true - type: integer - minimum: 0 - name: gid - in: path - - required: true - schema: - title: Uid - exclusiveMinimum: true - type: integer - minimum: 0 - name: uid - in: path - responses: - '204': - description: Successful Response patch: tags: - groups @@ -663,28 +637,28 @@ paths: description: Updates user (access-rights) to an organization group operationId: update_group_user parameters: - - required: true + - name: gid + in: path + required: true schema: - title: Gid - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Gid minimum: 0 - name: gid + - name: uid in: path - - required: true + required: true schema: - title: Uid - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Uid minimum: 0 - name: uid - in: path requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/GroupUserUpdate' - required: true responses: '200': description: Successful Response @@ -692,6 +666,32 @@ paths: application/json: schema: $ref: '#/components/schemas/Envelope_GroupUserGet_' + delete: + tags: + - groups + summary: Delete Group User + description: Removes a user from an organization group + operationId: delete_group_user + parameters: + - name: gid + in: path + required: true + schema: + type: integer + exclusiveMinimum: true + title: Gid + minimum: 0 + - name: uid + in: path + required: true + schema: + type: integer + exclusiveMinimum: true + title: Uid + minimum: 0 + responses: + '204': + description: Successful Response /v0/groups/{gid}/classifiers: get: tags: @@ -699,23 +699,24 @@ paths: summary: Get Group Classifiers operationId: get_group_classifiers parameters: - - required: true + - name: gid + in: path + required: true schema: - title: Gid - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Gid minimum: 0 - name: gid - in: path - - required: false + - name: tree_view + in: query + required: false schema: - title: Tree View enum: - std + const: std type: string default: std - name: tree_view - in: query + title: Tree View responses: '200': description: Successful Response @@ -730,12 +731,12 @@ paths: summary: Get Scicrunch Resource operationId: get_scicrunch_resource parameters: - - required: true + - name: rrid + in: path + required: true schema: - title: Rrid type: string - name: rrid - in: path + title: Rrid responses: '200': description: Successful Response @@ -749,12 +750,12 @@ paths: summary: Add Scicrunch Resource operationId: add_scicrunch_resource parameters: - - required: true + - name: rrid + in: path + required: true schema: - title: Rrid type: string - name: rrid - in: path + title: Rrid responses: '200': description: Successful Response @@ -769,19 +770,19 @@ paths: summary: Search Scicrunch Resources operationId: search_scicrunch_resources parameters: - - required: true + - name: guess_name + in: query + required: true schema: - title: Guess Name type: string - name: guess_name - in: query + title: Guess Name responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_simcore_service_webserver.scicrunch.models.ResourceHit__' + $ref: '#/components/schemas/Envelope_list_ResourceHit__' /v0/tags: get: tags: @@ -794,7 +795,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_simcore_service_webserver.tags.schemas.TagGet__' + $ref: '#/components/schemas/Envelope_list_TagGet__' post: tags: - tags @@ -814,43 +815,26 @@ paths: schema: $ref: '#/components/schemas/Envelope_TagGet_' /v0/tags/{tag_id}: - delete: - tags: - - tags - summary: Delete Tag - operationId: delete_tag - parameters: - - required: true - schema: - title: Tag Id - exclusiveMinimum: true - type: integer - minimum: 0 - name: tag_id - in: path - responses: - '204': - description: Successful Response patch: tags: - tags summary: Update Tag operationId: update_tag parameters: - - required: true + - name: tag_id + in: path + required: true schema: - title: Tag Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Tag Id minimum: 0 - name: tag_id - in: path requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/TagUpdate' - required: true responses: '200': description: Successful Response @@ -858,6 +842,23 @@ paths: application/json: schema: $ref: '#/components/schemas/Envelope_TagGet_' + delete: + tags: + - tags + summary: Delete Tag + operationId: delete_tag + parameters: + - name: tag_id + in: path + required: true + schema: + type: integer + exclusiveMinimum: true + title: Tag Id + minimum: 0 + responses: + '204': + description: Successful Response /v0/tags/{tag_id}/groups: get: tags: @@ -866,94 +867,94 @@ paths: summary: List Tag Groups operationId: list_tag_groups parameters: - - required: true + - name: tag_id + in: path + required: true schema: - title: Tag Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Tag Id minimum: 0 - name: tag_id - in: path responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_simcore_service_webserver.tags.schemas.TagGroupGet__' + $ref: '#/components/schemas/Envelope_list_TagGroupGet__' /v0/tags/{tag_id}/groups/{group_id}: - put: + post: tags: - tags - groups - summary: Replace Tag Groups - operationId: replace_tag_groups + summary: Create Tag Group + operationId: create_tag_group parameters: - - required: true + - name: tag_id + in: path + required: true schema: - title: Tag Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Tag Id minimum: 0 - name: tag_id + - name: group_id in: path - - required: true + required: true schema: - title: Group Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Group Id minimum: 0 - name: group_id - in: path requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/TagGroupCreate' - required: true responses: - '200': + '201': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_simcore_service_webserver.tags.schemas.TagGroupGet__' - post: + $ref: '#/components/schemas/Envelope_TagGet_' + put: tags: - tags - groups - summary: Create Tag Group - operationId: create_tag_group + summary: Replace Tag Groups + operationId: replace_tag_groups parameters: - - required: true + - name: tag_id + in: path + required: true schema: - title: Tag Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Tag Id minimum: 0 - name: tag_id + - name: group_id in: path - - required: true + required: true schema: - title: Group Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Group Id minimum: 0 - name: group_id - in: path requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/TagGroupCreate' - required: true responses: - '201': + '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_TagGet_' + $ref: '#/components/schemas/Envelope_list_TagGroupGet__' delete: tags: - tags @@ -961,22 +962,22 @@ paths: summary: Delete Tag Group operationId: delete_tag_group parameters: - - required: true + - name: tag_id + in: path + required: true schema: - title: Tag Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Tag Id minimum: 0 - name: tag_id + - name: group_id in: path - - required: true + required: true schema: - title: Group Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Group Id minimum: 0 - name: group_id - in: path responses: '204': description: Successful Response @@ -1001,18 +1002,19 @@ paths: summary: Get Product operationId: get_product parameters: - - required: true + - name: product_name + in: path + required: true schema: - title: Product Name anyOf: - - maxLength: 100 + - type: string minLength: 1 - type: string + maxLength: 100 - enum: - current + const: current type: string - name: product_name - in: path + title: Product Name responses: '200': description: Successful Response @@ -1028,32 +1030,33 @@ paths: summary: Update Product Template operationId: update_product_template parameters: - - required: true + - name: product_name + in: path + required: true schema: - title: Product Name anyOf: - - maxLength: 100 + - type: string minLength: 1 - type: string + maxLength: 100 - enum: - current + const: current type: string - name: product_name + title: Product Name + - name: template_id in: path - - required: true + required: true schema: - title: Template Id - maxLength: 100 - minLength: 1 type: string - name: template_id - in: path + minLength: 1 + maxLength: 100 + title: Template Id requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/UpdateProductTemplate' - required: true responses: '204': description: Successful Response @@ -1111,18 +1114,18 @@ paths: summary: Set Frontend Preference operationId: set_frontend_preference parameters: - - required: true + - name: preference_id + in: path + required: true schema: - title: Preference Id type: string - name: preference_id - in: path + title: Preference Id requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/PatchRequestBody' - required: true responses: '204': description: Successful Response @@ -1138,7 +1141,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_simcore_service_webserver.users.schemas.ThirdPartyToken__' + $ref: '#/components/schemas/Envelope_list_ThirdPartyToken__' post: tags: - user @@ -1164,12 +1167,12 @@ paths: summary: Get Token operationId: get_token parameters: - - required: true + - name: service + in: path + required: true schema: - title: Service type: string - name: service - in: path + title: Service responses: '200': description: Successful Response @@ -1183,12 +1186,12 @@ paths: summary: Delete Token operationId: delete_token parameters: - - required: true + - name: service + in: path + required: true schema: - title: Service type: string - name: service - in: path + title: Service responses: '204': description: Successful Response @@ -1204,7 +1207,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_simcore_service_webserver.users._notifications.UserNotification__' + $ref: '#/components/schemas/Envelope_list_UserNotification__' post: tags: - user @@ -1226,18 +1229,18 @@ paths: summary: Mark Notification As Read operationId: mark_notification_as_read parameters: - - required: true + - name: notification_id + in: path + required: true schema: - title: Notification Id type: string - name: notification_id - in: path + title: Notification Id requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/UserNotificationPatch' - required: true responses: '204': description: Successful Response @@ -1253,7 +1256,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_simcore_service_webserver.users.schemas.PermissionGet__' + $ref: '#/components/schemas/Envelope_list_PermissionGet__' /v0/users:search: get: tags: @@ -1262,21 +1265,21 @@ paths: summary: Search Users operationId: search_users parameters: - - required: true + - name: email + in: query + required: true schema: - title: Email - maxLength: 200 - minLength: 3 type: string - name: email - in: query + minLength: 3 + maxLength: 200 + title: Email responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_simcore_service_webserver.users._schemas.UserProfile__' + $ref: '#/components/schemas/Envelope_list_UserProfile__' /v0/users:pre-register: post: tags: @@ -1309,7 +1312,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_models_library.api_schemas_webserver.wallets.WalletGetWithAvailableCredits__' + $ref: '#/components/schemas/Envelope_list_WalletGetWithAvailableCredits__' post: tags: - wallets @@ -1348,14 +1351,14 @@ paths: summary: Get Wallet operationId: get_wallet parameters: - - required: true + - name: wallet_id + in: path + required: true schema: - title: Wallet Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Wallet Id minimum: 0 - name: wallet_id - in: path responses: '200': description: Successful Response @@ -1369,20 +1372,20 @@ paths: summary: Update Wallet operationId: update_wallet parameters: - - required: true + - name: wallet_id + in: path + required: true schema: - title: Wallet Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Wallet Id minimum: 0 - name: wallet_id - in: path requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/PutWalletBodyParams' - required: true responses: '200': description: Successful Response @@ -1398,20 +1401,20 @@ paths: description: Creates payment to wallet `wallet_id` operationId: create_payment parameters: - - required: true + - name: wallet_id + in: path + required: true schema: - title: Wallet Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Wallet Id minimum: 0 - name: wallet_id - in: path requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/CreateWalletPayment' - required: true responses: '202': description: Payment initialized @@ -1428,24 +1431,24 @@ paths: created) operationId: list_all_payments parameters: - - required: false + - name: limit + in: query + required: false schema: - title: Limit - exclusiveMaximum: true - minimum: 1 type: integer + minimum: 1 + exclusiveMaximum: true default: 20 + title: Limit maximum: 50 - name: limit + - name: offset in: query - - required: false + required: false schema: - title: Offset - minimum: 0 type: integer + minimum: 0 default: 0 - name: offset - in: query + title: Offset responses: '200': description: Successful Response @@ -1460,22 +1463,22 @@ paths: summary: Get Payment Invoice Link operationId: get_payment_invoice_link parameters: - - required: true + - name: wallet_id + in: path + required: true schema: - title: Wallet Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Wallet Id minimum: 0 - name: wallet_id + - name: payment_id in: path - - required: true + required: true schema: - title: Payment Id - maxLength: 100 - minLength: 1 type: string - name: payment_id - in: path + minLength: 1 + maxLength: 100 + title: Payment Id responses: '302': description: redirection to invoice download link @@ -1489,22 +1492,22 @@ paths: summary: Cancel Payment operationId: cancel_payment parameters: - - required: true + - name: wallet_id + in: path + required: true schema: - title: Wallet Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Wallet Id minimum: 0 - name: wallet_id + - name: payment_id in: path - - required: true + required: true schema: - title: Payment Id - maxLength: 100 - minLength: 1 type: string - name: payment_id - in: path + minLength: 1 + maxLength: 100 + title: Payment Id responses: '204': description: Successfully cancelled @@ -1515,14 +1518,14 @@ paths: summary: Init Creation Of Payment Method operationId: init_creation_of_payment_method parameters: - - required: true + - name: wallet_id + in: path + required: true schema: - title: Wallet Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Wallet Id minimum: 0 - name: wallet_id - in: path responses: '202': description: Successfully initialized @@ -1537,22 +1540,22 @@ paths: summary: Cancel Creation Of Payment Method operationId: cancel_creation_of_payment_method parameters: - - required: true + - name: wallet_id + in: path + required: true schema: - title: Wallet Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Wallet Id minimum: 0 - name: wallet_id + - name: payment_method_id in: path - - required: true + required: true schema: - title: Payment Method Id - maxLength: 100 - minLength: 1 type: string - name: payment_method_id - in: path + minLength: 1 + maxLength: 100 + title: Payment Method Id responses: '204': description: Successfully cancelled @@ -1564,21 +1567,21 @@ paths: description: Lists all payments method associated to `wallet_id` operationId: list_payments_methods parameters: - - required: true + - name: wallet_id + in: path + required: true schema: - title: Wallet Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Wallet Id minimum: 0 - name: wallet_id - in: path responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_models_library.api_schemas_webserver.wallets.PaymentMethodGet__' + $ref: '#/components/schemas/Envelope_list_PaymentMethodGet__' /v0/wallets/{wallet_id}/payments-methods/{payment_method_id}: get: tags: @@ -1586,22 +1589,22 @@ paths: summary: Get Payment Method operationId: get_payment_method parameters: - - required: true + - name: wallet_id + in: path + required: true schema: - title: Wallet Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Wallet Id minimum: 0 - name: wallet_id + - name: payment_method_id in: path - - required: true + required: true schema: - title: Payment Method Id - maxLength: 100 - minLength: 1 type: string - name: payment_method_id - in: path + minLength: 1 + maxLength: 100 + title: Payment Method Id responses: '200': description: Successful Response @@ -1615,22 +1618,22 @@ paths: summary: Delete Payment Method operationId: delete_payment_method parameters: - - required: true + - name: wallet_id + in: path + required: true schema: - title: Wallet Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Wallet Id minimum: 0 - name: wallet_id + - name: payment_method_id in: path - - required: true + required: true schema: - title: Payment Method Id - maxLength: 100 - minLength: 1 type: string - name: payment_method_id - in: path + minLength: 1 + maxLength: 100 + title: Payment Method Id responses: '204': description: Successfully deleted @@ -1641,28 +1644,28 @@ paths: summary: Pay With Payment Method operationId: pay_with_payment_method parameters: - - required: true + - name: wallet_id + in: path + required: true schema: - title: Wallet Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Wallet Id minimum: 0 - name: wallet_id + - name: payment_method_id in: path - - required: true + required: true schema: - title: Payment Method Id - maxLength: 100 - minLength: 1 type: string - name: payment_method_id - in: path + minLength: 1 + maxLength: 100 + title: Payment Method Id requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/CreateWalletPayment' - required: true responses: '202': description: Pay with payment-method @@ -1677,14 +1680,14 @@ paths: summary: Get Wallet Autorecharge operationId: get_wallet_autorecharge parameters: - - required: true + - name: wallet_id + in: path + required: true schema: - title: Wallet Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Wallet Id minimum: 0 - name: wallet_id - in: path responses: '200': description: Successful Response @@ -1698,20 +1701,20 @@ paths: summary: Replace Wallet Autorecharge operationId: replace_wallet_autorecharge parameters: - - required: true + - name: wallet_id + in: path + required: true schema: - title: Wallet Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Wallet Id minimum: 0 - name: wallet_id - in: path requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/ReplaceWalletAutoRecharge' - required: true responses: '200': description: Successful Response @@ -1720,73 +1723,73 @@ paths: schema: $ref: '#/components/schemas/Envelope_GetWalletAutoRecharge_' /v0/wallets/{wallet_id}/groups/{group_id}: - put: + post: tags: - wallets - groups - summary: Update Wallet Group - operationId: update_wallet_group + summary: Create Wallet Group + operationId: create_wallet_group parameters: - - required: true + - name: wallet_id + in: path + required: true schema: - title: Wallet Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Wallet Id minimum: 0 - name: wallet_id + - name: group_id in: path - - required: true + required: true schema: - title: Group Id - exclusiveMinimum: true type: integer - minimum: 0 - name: group_id - in: path + exclusiveMinimum: true + title: Group Id + minimum: 0 requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/_WalletsGroupsBodyParams' - required: true responses: - '200': + '201': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/Envelope_WalletGroupGet_' - post: + put: tags: - wallets - groups - summary: Create Wallet Group - operationId: create_wallet_group + summary: Update Wallet Group + operationId: update_wallet_group parameters: - - required: true + - name: wallet_id + in: path + required: true schema: - title: Wallet Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Wallet Id minimum: 0 - name: wallet_id + - name: group_id in: path - - required: true + required: true schema: - title: Group Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Group Id minimum: 0 - name: group_id - in: path requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/_WalletsGroupsBodyParams' - required: true responses: - '201': + '200': description: Successful Response content: application/json: @@ -1799,22 +1802,22 @@ paths: summary: Delete Wallet Group operationId: delete_wallet_group parameters: - - required: true + - name: wallet_id + in: path + required: true schema: - title: Wallet Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Wallet Id minimum: 0 - name: wallet_id + - name: group_id in: path - - required: true + required: true schema: - title: Group Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Group Id minimum: 0 - name: group_id - in: path responses: '204': description: Successful Response @@ -1826,21 +1829,21 @@ paths: summary: List Wallet Groups operationId: list_wallet_groups parameters: - - required: true + - name: wallet_id + in: path + required: true schema: - title: Wallet Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Wallet Id minimum: 0 - name: wallet_id - in: path responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_simcore_service_webserver.wallets._groups_api.WalletGroupGet__' + $ref: '#/components/schemas/Envelope_list_WalletGroupGet__' /v0/activity/status: get: tags: @@ -1853,7 +1856,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Envelope_dict_uuid.UUID__models_library.api_schemas_webserver.activity.Activity__' + $ref: '#/components/schemas/Envelope_dict_UUID__Activity__' /v0/announcements: get: tags: @@ -1866,7 +1869,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_simcore_service_webserver.announcements._models.Announcement__' + $ref: '#/components/schemas/Envelope_list_Announcement__' /v0/catalog/services/-/latest: get: tags: @@ -1874,24 +1877,24 @@ paths: summary: List Services Latest operationId: list_services_latest parameters: - - required: false + - name: limit + in: query + required: false schema: - title: Limit - exclusiveMaximum: true - minimum: 1 type: integer + minimum: 1 + exclusiveMaximum: true default: 20 + title: Limit maximum: 50 - name: limit + - name: offset in: query - - required: false + required: false schema: - title: Offset - minimum: 0 type: integer + minimum: 0 default: 0 - name: offset - in: query + title: Offset responses: '200': description: Successful Response @@ -1906,20 +1909,20 @@ paths: summary: Get Service operationId: get_service parameters: - - required: true + - name: service_key + in: path + required: true schema: - title: Service Key - pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ type: string - name: service_key + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + title: Service Key + - name: service_version in: path - - required: true + required: true schema: - title: Service Version - pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ type: string - name: service_version - in: path + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + title: Service Version responses: '200': description: Successful Response @@ -1933,26 +1936,26 @@ paths: summary: Update Service operationId: update_service parameters: - - required: true + - name: service_key + in: path + required: true schema: - title: Service Key - pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ type: string - name: service_key + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + title: Service Key + - name: service_version in: path - - required: true + required: true schema: - title: Service Version - pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ type: string - name: service_version - in: path + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + title: Service Version requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/CatalogServiceUpdate' - required: true responses: '200': description: Successful Response @@ -1967,27 +1970,27 @@ paths: summary: List Service Inputs operationId: list_service_inputs parameters: - - required: true + - name: service_key + in: path + required: true schema: - title: Service Key - pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ type: string - name: service_key + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + title: Service Key + - name: service_version in: path - - required: true + required: true schema: - title: Service Version - pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ type: string - name: service_version - in: path + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + title: Service Version responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_models_library.api_schemas_webserver.catalog.ServiceInputGet__' + $ref: '#/components/schemas/Envelope_list_ServiceInputGet__' /v0/catalog/services/{service_key}/{service_version}/inputs/{input_key}: get: tags: @@ -1995,27 +1998,27 @@ paths: summary: Get Service Input operationId: get_service_input parameters: - - required: true + - name: service_key + in: path + required: true schema: - title: Service Key - pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ type: string - name: service_key + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + title: Service Key + - name: service_version in: path - - required: true + required: true schema: - title: Service Version - pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ type: string - name: service_version + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + title: Service Version + - name: input_key in: path - - required: true + required: true schema: - title: Input Key - pattern: ^[-_a-zA-Z0-9]+$ type: string - name: input_key - in: path + pattern: ^[-_a-zA-Z0-9]+$ + title: Input Key responses: '200': description: Successful Response @@ -2030,48 +2033,48 @@ paths: summary: Get Compatible Inputs Given Source Output operationId: get_compatible_inputs_given_source_output parameters: - - required: true - schema: - title: Service Key - pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ - type: string - name: service_key + - name: service_key in: path - - required: true + required: true schema: - title: Service Version - pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ type: string - name: service_version + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + title: Service Key + - name: service_version in: path - - required: true + required: true schema: - title: Fromservice - pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ type: string - name: fromService + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + title: Service Version + - name: fromService in: query - - required: true + required: true schema: - title: Fromversion - pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ type: string - name: fromVersion + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + title: Fromservice + - name: fromVersion in: query - - required: true + required: true schema: - title: Fromoutput - pattern: ^[-_a-zA-Z0-9]+$ type: string - name: fromOutput + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + title: Fromversion + - name: fromOutput in: query + required: true + schema: + type: string + pattern: ^[-_a-zA-Z0-9]+$ + title: Fromoutput responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_models_library.services_types.ServicePortKey__' + $ref: '#/components/schemas/Envelope_list_Annotated_str__StringConstraints___' /v0/catalog/services/{service_key}/{service_version}/outputs: get: tags: @@ -2079,27 +2082,27 @@ paths: summary: List Service Outputs operationId: list_service_outputs parameters: - - required: true + - name: service_key + in: path + required: true schema: - title: Service Key - pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ type: string - name: service_key + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + title: Service Key + - name: service_version in: path - - required: true + required: true schema: - title: Service Version - pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ type: string - name: service_version - in: path + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + title: Service Version responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_models_library.services_types.ServicePortKey__' + $ref: '#/components/schemas/Envelope_list_Annotated_str__StringConstraints___' /v0/catalog/services/{service_key}/{service_version}/outputs/{output_key}: get: tags: @@ -2107,34 +2110,34 @@ paths: summary: Get Service Output operationId: get_service_output parameters: - - required: true + - name: service_key + in: path + required: true schema: - title: Service Key - pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ type: string - name: service_key + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + title: Service Key + - name: service_version in: path - - required: true + required: true schema: - title: Service Version - pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ type: string - name: service_version + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + title: Service Version + - name: output_key in: path - - required: true + required: true schema: - title: Output Key - pattern: ^[-_a-zA-Z0-9]+$ type: string - name: output_key - in: path + pattern: ^[-_a-zA-Z0-9]+$ + title: Output Key responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_models_library.api_schemas_webserver.catalog.ServiceOutputGet__' + $ref: '#/components/schemas/Envelope_list_ServiceOutputGet__' /v0/catalog/services/{service_key}/{service_version}/outputs:match: get: tags: @@ -2142,48 +2145,48 @@ paths: summary: Get Compatible Outputs Given Target Input operationId: get_compatible_outputs_given_target_input parameters: - - required: true - schema: - title: Service Key - pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ - type: string - name: service_key + - name: service_key in: path - - required: true + required: true schema: - title: Service Version - pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ type: string - name: service_version + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + title: Service Key + - name: service_version in: path - - required: true + required: true schema: - title: Toservice - pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ type: string - name: toService + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + title: Service Version + - name: toService in: query - - required: true + required: true schema: - title: Toversion - pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ type: string - name: toVersion + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + title: Toservice + - name: toVersion in: query - - required: true + required: true schema: - title: Toinput - pattern: ^[-_a-zA-Z0-9]+$ type: string - name: toInput + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + title: Toversion + - name: toInput in: query + required: true + schema: + type: string + pattern: ^[-_a-zA-Z0-9]+$ + title: Toinput responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_models_library.services_types.ServicePortKey__' + $ref: '#/components/schemas/Envelope_list_Annotated_str__StringConstraints___' /v0/catalog/services/{service_key}/{service_version}/resources: get: tags: @@ -2191,28 +2194,27 @@ paths: summary: Get Service Resources operationId: get_service_resources parameters: - - required: true + - name: service_key + in: path + required: true schema: - title: Service Key - pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ type: string - name: service_key + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + title: Service Key + - name: service_version in: path - - required: true + required: true schema: - title: Service Version - pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ type: string - name: service_version - in: path + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + title: Service Version responses: '200': description: Successful Response content: application/json: schema: - title: Response Get Service Resources - type: object + $ref: '#/components/schemas/Envelope_dict_Annotated_str__StringConstraints___ImageResources__' /v0/catalog/services/{service_key}/{service_version}/pricing-plan: get: tags: @@ -2221,20 +2223,20 @@ paths: summary: Retrieve default pricing plan for provided service operationId: get_service_pricing_plan parameters: - - required: true + - name: service_key + in: path + required: true schema: - title: Service Key - pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ type: string - name: service_key + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + title: Service Key + - name: service_version in: path - - required: true + required: true schema: - title: Service Version - pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ type: string - name: service_version - in: path + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + title: Service Version responses: '200': description: Successful Response @@ -2250,27 +2252,27 @@ paths: summary: List Service Tags operationId: list_service_tags parameters: - - required: true + - name: service_key + in: path + required: true schema: - title: Service Key - pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ type: string - name: service_key + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + title: Service Key + - name: service_version in: path - - required: true + required: true schema: - title: Service Version - pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ type: string - name: service_version - in: path + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + title: Service Version responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_simcore_service_webserver.tags.schemas.TagGet__' + $ref: '#/components/schemas/Envelope_list_TagGet__' /v0/catalog/services/{service_key}/{service_version}/tags/{tag_id}:add: post: tags: @@ -2279,28 +2281,28 @@ paths: summary: Add Service Tag operationId: add_service_tag parameters: - - required: true + - name: service_key + in: path + required: true schema: - title: Service Key - pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ type: string - name: service_key + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + title: Service Key + - name: service_version in: path - - required: true + required: true schema: - title: Service Version - pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ type: string - name: service_version + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + title: Service Version + - name: tag_id in: path - - required: true + required: true schema: - title: Tag Id - exclusiveMinimum: true type: integer - minimum: 0 - name: tag_id - in: path + exclusiveMinimum: true + title: Tag Id + minimum: 0 responses: '200': description: Successful Response @@ -2316,28 +2318,28 @@ paths: summary: Remove Service Tag operationId: remove_service_tag parameters: - - required: true + - name: service_key + in: path + required: true schema: - title: Service Key - pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ type: string - name: service_key + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + title: Service Key + - name: service_version in: path - - required: true + required: true schema: - title: Service Version - pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ type: string - name: service_version + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + title: Service Version + - name: tag_id in: path - - required: true + required: true schema: - title: Tag Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Tag Id minimum: 0 - name: tag_id - in: path responses: '200': description: Successful Response @@ -2357,7 +2359,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_models_library.api_schemas_webserver.clusters.ClusterGet__' + $ref: '#/components/schemas/Envelope_list_ClusterGet__' post: tags: - clusters @@ -2399,13 +2401,13 @@ paths: summary: Get Cluster operationId: get_cluster parameters: - - required: true + - name: cluster_id + in: path + required: true schema: - title: Cluster Id - minimum: 0 type: integer - name: cluster_id - in: path + minimum: 0 + title: Cluster Id responses: '200': description: Successful Response @@ -2413,41 +2415,25 @@ paths: application/json: schema: $ref: '#/components/schemas/Envelope_ClusterGet_' - delete: - tags: - - clusters - summary: Delete Cluster - operationId: delete_cluster - parameters: - - required: true - schema: - title: Cluster Id - minimum: 0 - type: integer - name: cluster_id - in: path - responses: - '204': - description: Successful Response patch: tags: - clusters summary: Update Cluster operationId: update_cluster parameters: - - required: true + - name: cluster_id + in: path + required: true schema: - title: Cluster Id - minimum: 0 type: integer - name: cluster_id - in: path + minimum: 0 + title: Cluster Id requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/ClusterPatch' - required: true responses: '200': description: Successful Response @@ -2455,6 +2441,22 @@ paths: application/json: schema: $ref: '#/components/schemas/Envelope_ClusterGet_' + delete: + tags: + - clusters + summary: Delete Cluster + operationId: delete_cluster + parameters: + - name: cluster_id + in: path + required: true + schema: + type: integer + minimum: 0 + title: Cluster Id + responses: + '204': + description: Successful Response /v0/clusters/{cluster_id}/details: get: tags: @@ -2462,13 +2464,13 @@ paths: summary: Get Cluster Details operationId: get_cluster_details parameters: - - required: true + - name: cluster_id + in: path + required: true schema: - title: Cluster Id - minimum: 0 type: integer - name: cluster_id - in: path + minimum: 0 + title: Cluster Id responses: '200': description: Successful Response @@ -2484,13 +2486,13 @@ paths: description: Tests connectivity with cluster operationId: ping_cluster_cluster_id parameters: - - required: true + - name: cluster_id + in: path + required: true schema: - title: Cluster Id - minimum: 0 type: integer - name: cluster_id - in: path + minimum: 0 + title: Cluster Id responses: '204': description: Successful Response @@ -2502,13 +2504,13 @@ paths: summary: Get Computation operationId: get_computation parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id - in: path + title: Project Id responses: '200': description: Successful Response @@ -2524,19 +2526,19 @@ paths: summary: Start Computation operationId: start_computation parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id - in: path + title: Project Id requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/ComputationStart' - required: true responses: '200': description: Successful Response @@ -2564,13 +2566,13 @@ paths: summary: Stop Computation operationId: stop_computation parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id - in: path + title: Project Id responses: '204': description: Successful Response @@ -2583,98 +2585,100 @@ paths: description: creates an archive of the project and downloads it operationId: export_project parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string - name: project_id - in: path + title: Project Id responses: '200': description: Successful Response /v0/folders: + post: + tags: + - folders + summary: Create Folder + operationId: create_folder + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/FolderCreateBodyParams' + responses: + '201': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/Envelope_FolderGet_' get: tags: - folders summary: List Folders operationId: list_folders parameters: - - required: false + - name: filters + in: query + required: false schema: + anyOf: + - type: string + contentMediaType: application/json + contentSchema: {} + - type: 'null' title: Filters - type: string - description: Custom filter query parameter encoded as JSON - name: filters + - name: order_by in: query - - required: false + required: false schema: - title: Order By type: string - description: Order by field (`description|modified|name`) and direction - (`asc|desc`). The default sorting order is `{"field":"modified","direction":"desc"}`. + contentMediaType: application/json + contentSchema: {} default: '{"field":"modified","direction":"desc"}' - example: '{"field":"some_field_name","direction":"desc"}' - name: order_by + title: Order By + - name: limit in: query - - required: false + required: false schema: - title: Limit - exclusiveMaximum: true - minimum: 1 type: integer default: 20 - maximum: 50 - name: limit + title: Limit + - name: offset in: query - - required: false + required: false schema: - title: Offset - minimum: 0 type: integer default: 0 - name: offset + title: Offset + - name: folder_id in: query - - required: false + required: false schema: + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' title: Folder Id - exclusiveMinimum: true - type: integer - minimum: 0 - name: folder_id + - name: workspace_id in: query - - required: false + required: false schema: + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' title: Workspace Id - exclusiveMinimum: true - type: integer - minimum: 0 - name: workspace_id - in: query responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_models_library.api_schemas_webserver.folders_v2.FolderGet__' - post: - tags: - - folders - summary: Create Folder - operationId: create_folder - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/CreateFolderBodyParams' - required: true - responses: - '201': - description: Successful Response - content: - application/json: - schema: - $ref: '#/components/schemas/Envelope_FolderGet_' + $ref: '#/components/schemas/Envelope_list_FolderGet__' /v0/folders:search: get: tags: @@ -2682,55 +2686,54 @@ paths: summary: List Folders Full Search operationId: list_folders_full_search parameters: - - required: false + - name: filters + in: query + required: false schema: + anyOf: + - type: string + contentMediaType: application/json + contentSchema: {} + - type: 'null' title: Filters - type: string - description: Custom filter query parameter encoded as JSON - name: filters + - name: order_by in: query - - required: false + required: false schema: - title: Order By type: string - description: Order by field (`description|modified|name`) and direction - (`asc|desc`). The default sorting order is `{"field":"modified","direction":"desc"}`. + contentMediaType: application/json + contentSchema: {} default: '{"field":"modified","direction":"desc"}' - example: '{"field":"some_field_name","direction":"desc"}' - name: order_by + title: Order By + - name: limit in: query - - required: false + required: false schema: - title: Limit - exclusiveMaximum: true - minimum: 1 type: integer default: 20 - maximum: 50 - name: limit + title: Limit + - name: offset in: query - - required: false + required: false schema: - title: Offset - minimum: 0 type: integer default: 0 - name: offset + title: Offset + - name: text in: query - - required: false + required: false schema: + anyOf: + - type: string + - type: 'null' title: Text - maxLength: 100 - type: string - name: text - in: query responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_models_library.api_schemas_webserver.folders_v2.FolderGet__' + $ref: '#/components/schemas/Envelope_list_FolderGet__' /v0/folders/{folder_id}: get: tags: @@ -2738,14 +2741,14 @@ paths: summary: Get Folder operationId: get_folder parameters: - - required: true + - name: folder_id + in: path + required: true schema: - title: Folder Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Folder Id minimum: 0 - name: folder_id - in: path responses: '200': description: Successful Response @@ -2759,20 +2762,20 @@ paths: summary: Replace Folder operationId: replace_folder parameters: - - required: true + - name: folder_id + in: path + required: true schema: - title: Folder Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Folder Id minimum: 0 - name: folder_id - in: path requestBody: + required: true content: application/json: schema: - $ref: '#/components/schemas/PutFolderBodyParams' - required: true + $ref: '#/components/schemas/FolderReplaceBodyParams' responses: '200': description: Successful Response @@ -2786,14 +2789,14 @@ paths: summary: Delete Folder operationId: delete_folder parameters: - - required: true + - name: folder_id + in: path + required: true schema: - title: Folder Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Folder Id minimum: 0 - name: folder_id - in: path responses: '204': description: Successful Response @@ -2809,7 +2812,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_models_library.api_schemas_long_running_tasks.tasks.TaskGet__' + $ref: '#/components/schemas/Envelope_list_TaskGet__' /v0/tasks/{task_id}: get: tags: @@ -2817,12 +2820,12 @@ paths: summary: Get Task Status operationId: get_task_status parameters: - - required: true + - name: task_id + in: path + required: true schema: - title: Task Id type: string - name: task_id - in: path + title: Task Id responses: '200': description: Successful Response @@ -2836,12 +2839,12 @@ paths: summary: Cancel And Delete Task operationId: cancel_and_delete_task parameters: - - required: true + - name: task_id + in: path + required: true schema: - title: Task Id type: string - name: task_id - in: path + title: Task Id responses: '204': description: Successful Response @@ -2852,12 +2855,12 @@ paths: summary: Get Task Result operationId: get_task_result parameters: - - required: true + - name: task_id + in: path + required: true schema: - title: Task Id type: string - name: task_id - in: path + title: Task Id responses: '200': description: Successful Response @@ -2872,37 +2875,37 @@ paths: summary: List Project Iterations operationId: list_project_iterations parameters: - - required: true + - name: project_uuid + in: path + required: true schema: - title: Project Uuid type: string format: uuid - name: project_uuid + title: Project Uuid + - name: ref_id in: path - - required: true + required: true schema: - title: Ref Id type: integer - name: ref_id - in: path - - required: false + title: Ref Id + - name: limit + in: query + required: false schema: - title: Limit - exclusiveMaximum: true - minimum: 1 type: integer + minimum: 1 + exclusiveMaximum: true default: 20 + title: Limit maximum: 50 - name: limit + - name: offset in: query - - required: false + required: false schema: - title: Offset - minimum: 0 type: integer + minimum: 0 default: 0 - name: offset - in: query + title: Offset responses: '200': description: Successful Response @@ -2918,37 +2921,37 @@ paths: summary: List Project Iterations Results operationId: list_project_iterations_results parameters: - - required: true - schema: - title: Project Uuid + - name: project_uuid + in: path + required: true + schema: type: string format: uuid - name: project_uuid + title: Project Uuid + - name: ref_id in: path - - required: true + required: true schema: - title: Ref Id type: integer - name: ref_id - in: path - - required: false + title: Ref Id + - name: limit + in: query + required: false schema: - title: Limit - exclusiveMaximum: true - minimum: 1 type: integer + minimum: 1 + exclusiveMaximum: true default: 20 + title: Limit maximum: 50 - name: limit + - name: offset in: query - - required: false + required: false schema: - title: Offset - minimum: 0 type: integer + minimum: 0 default: 0 - name: offset - in: query + title: Offset responses: '200': description: Successful Response @@ -2969,7 +2972,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_simcore_service_webserver.studies_dispatcher._rest_handlers.ServiceGet__' + $ref: '#/components/schemas/Envelope_list_ServiceGet__' /v0/viewers: get: tags: @@ -2984,19 +2987,21 @@ paths: If file_type is provided, then it filters viewer for that filetype' operationId: list_viewers parameters: - - required: false + - name: file_type + in: query + required: false schema: + anyOf: + - type: string + - type: 'null' title: File Type - type: string - name: file_type - in: query responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_simcore_service_webserver.studies_dispatcher._rest_handlers.Viewer__' + $ref: '#/components/schemas/Envelope_list_Viewer__' /v0/viewers/default: get: tags: @@ -3015,19 +3020,21 @@ paths: If file_type is provided, then it filters viewer for that filetype' operationId: list_default_viewers parameters: - - required: false + - name: file_type + in: query + required: false schema: + anyOf: + - type: string + - type: 'null' title: File Type - type: string - name: file_type - in: query responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_simcore_service_webserver.studies_dispatcher._rest_handlers.Viewer__' + $ref: '#/components/schemas/Envelope_list_Viewer__' /view: get: tags: @@ -3036,49 +3043,51 @@ paths: description: Opens a viewer in osparc for data in the NIH-sparc portal operationId: get_redirection_to_viewer parameters: - - required: true + - name: file_type + in: query + required: true schema: - title: File Type type: string - name: file_type + title: File Type + - name: viewer_key in: query - - required: true + required: true schema: - title: Viewer Key - pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ type: string - name: viewer_key + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + title: Viewer Key + - name: file_size in: query - - required: true + required: true schema: - title: File Size - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: File Size minimum: 0 - name: file_size + - name: download_link in: query - - required: true + required: true schema: - title: Download Link - maxLength: 2083 - minLength: 1 type: string format: uri - name: download_link + minLength: 1 + maxLength: 2083 + title: Download Link + - name: file_name in: query - - required: false + required: false schema: - title: File Name - type: string + anyOf: + - type: string + - type: 'null' default: unknown - name: file_name - in: query + title: File Name requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/ServiceKeyVersion' - required: true responses: '302': description: Opens osparc and starts viewer for selected data @@ -3090,183 +3099,183 @@ paths: description: Opens a study published in osparc operationId: get_redirection_to_study_page parameters: - - required: true + - name: id + in: path + required: true schema: - title: Id type: string format: uuid - name: id - in: path + title: Id responses: '302': description: Opens osparc and opens a copy of publised study /v0/projects: - get: + post: tags: - projects - summary: List Projects - operationId: list_projects + summary: Creates a new project or copies an existing one + operationId: create_project parameters: - - required: false - schema: - allOf: - - $ref: '#/components/schemas/ProjectTypeAPI' - default: all - name: type - in: query - - required: false - schema: - title: Show Hidden - type: boolean - default: false - name: show_hidden + - name: x_simcore_user_agent in: query - - required: false + required: false schema: - title: Search - maxLength: 100 - type: string - name: search + anyOf: + - type: string + - type: 'null' + default: undefined + title: X Simcore User Agent + - name: x_simcore_parent_project_uuid in: query - - required: false + required: false schema: - title: Folder Id - exclusiveMinimum: true - type: integer - minimum: 0 - name: folder_id + anyOf: + - type: string + format: uuid + - type: 'null' + title: X Simcore Parent Project Uuid + - name: x_simcore_parent_node_id in: query - - required: false + required: false schema: - title: Workspace Id - exclusiveMinimum: true - type: integer - minimum: 0 - name: workspace_id + anyOf: + - type: string + format: uuid + - type: 'null' + title: X Simcore Parent Node Id + - name: from_study in: query - - required: false + required: false schema: - title: Filters - type: string - description: Custom filter query parameter encoded as JSON - name: filters + anyOf: + - type: string + format: uuid + - type: 'null' + title: From Study + - name: as_template in: query - - required: false + required: false schema: - title: Order By - type: string - description: Order by field (`creation_date|description|last_change_date|name|prj_owner|type|uuid`) - and direction (`asc|desc`). The default sorting order is `{"field":"last_change_date","direction":"desc"}`. - default: '{"field":"last_change_date","direction":"desc"}' - example: '{"field":"some_field_name","direction":"desc"}' - name: order_by + type: boolean + default: false + title: As Template + - name: copy_data in: query - - required: false + required: false schema: - title: Limit - exclusiveMaximum: true - minimum: 1 - type: integer - default: 20 - maximum: 50 - name: limit + type: boolean + default: true + title: Copy Data + - name: hidden in: query - - required: false + required: false schema: - title: Offset - minimum: 0 - type: integer - default: 0 - name: offset - in: query + type: boolean + default: false + title: Hidden + requestBody: + required: true + content: + application/json: + schema: + anyOf: + - $ref: '#/components/schemas/ProjectCreateNew' + - $ref: '#/components/schemas/ProjectCopyOverride' + title: ' Body' responses: - '200': + '201': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Page_ProjectListItem_' - post: + $ref: '#/components/schemas/Envelope_TaskGet_' + get: tags: - projects - summary: Creates a new project or copies an existing one - operationId: create_project + summary: List Projects + operationId: list_projects parameters: - - required: false + - name: type + in: query + required: false schema: - title: From Study - type: string - format: uuid - name: from_study + $ref: '#/components/schemas/ProjectTypeAPI' + default: all + - name: show_hidden in: query - - required: false + required: false schema: - title: As Template type: boolean default: false - name: as_template + title: Show Hidden + - name: search in: query - - required: false + required: false schema: - title: Copy Data - type: boolean - default: true - name: copy_data + anyOf: + - type: string + - type: 'null' + title: Search + - name: folder_id in: query - - required: false + required: false schema: - title: Hidden - type: boolean - default: false - name: hidden + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' + title: Folder Id + - name: workspace_id in: query - - description: Optional simcore user agent required: false schema: - title: X-Simcore-User-Agent - type: string - description: Optional simcore user agent - default: undefined - name: x-simcore-user-agent - in: header - - description: Optionally sets a parent project UUID (both project and node - must be set) + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' + title: Workspace Id + - name: filters + in: query required: false schema: - title: X-Simcore-Parent-Project-Uuid - type: string - description: Optionally sets a parent project UUID (both project and node - must be set) - format: uuid - name: x-simcore-parent-project-uuid - in: header - - description: Optionally sets a parent node ID (both project and node must - be set) + anyOf: + - type: string + contentMediaType: application/json + contentSchema: {} + - type: 'null' + title: Filters + - name: order_by + in: query required: false schema: - title: X-Simcore-Parent-Node-Id type: string - description: Optionally sets a parent node ID (both project and node must - be set) - format: uuid - name: x-simcore-parent-node-id - in: header - requestBody: - content: - application/json: - schema: - title: ' Body' - anyOf: - - $ref: '#/components/schemas/ProjectCreateNew' - - $ref: '#/components/schemas/ProjectCopyOverride' - required: true + contentMediaType: application/json + contentSchema: {} + default: '{"field":"last_change_date","direction":"desc"}' + title: Order By + - name: limit + in: query + required: false + schema: + type: integer + default: 20 + title: Limit + - name: offset + in: query + required: false + schema: + type: integer + default: 0 + title: Offset responses: - '201': + '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_TaskGet_' + $ref: '#/components/schemas/Page_ProjectListItem_' /v0/projects/active: get: tags: @@ -3274,12 +3283,12 @@ paths: summary: Get Active Project operationId: get_active_project parameters: - - required: true + - name: client_session_id + in: query + required: true schema: - title: Client Session Id type: string - name: client_session_id - in: query + title: Client Session Id responses: '200': description: Successful Response @@ -3294,13 +3303,13 @@ paths: summary: Get Project operationId: get_project parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id - in: path + title: Project Id responses: '200': description: Successful Response @@ -3308,41 +3317,41 @@ paths: application/json: schema: $ref: '#/components/schemas/Envelope_ProjectGet_' - delete: - tags: - - projects - summary: Delete Project - operationId: delete_project - parameters: - - required: true - schema: - title: Project Id - type: string - format: uuid - name: project_id - in: path - responses: - '204': - description: Successful Response patch: tags: - projects summary: Patch Project operationId: patch_project parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id - in: path + title: Project Id requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/ProjectPatch' + responses: + '204': + description: Successful Response + delete: + tags: + - projects + summary: Delete Project + operationId: delete_project + parameters: + - name: project_id + in: path required: true + schema: + type: string + format: uuid + title: Project Id responses: '204': description: Successful Response @@ -3353,13 +3362,13 @@ paths: summary: Clone Project operationId: clone_project parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id - in: path + title: Project Id responses: '201': description: Successful Response @@ -3374,47 +3383,45 @@ paths: summary: List Projects Full Search operationId: list_projects_full_search parameters: - - required: false + - name: order_by + in: query + required: false schema: - title: Order By type: string - description: Order by field (`creation_date|description|last_change_date|name|prj_owner|type|uuid`) - and direction (`asc|desc`). The default sorting order is `{"field":"last_change_date","direction":"desc"}`. + contentMediaType: application/json + contentSchema: {} default: '{"field":"last_change_date","direction":"desc"}' - example: '{"field":"some_field_name","direction":"desc"}' - name: order_by + title: Order By + - name: limit in: query - - required: false + required: false schema: - title: Limit - exclusiveMaximum: true - minimum: 1 type: integer default: 20 - maximum: 50 - name: limit + title: Limit + - name: offset in: query - - required: false + required: false schema: - title: Offset - minimum: 0 type: integer default: 0 - name: offset + title: Offset + - name: text in: query - - required: false + required: false schema: + anyOf: + - type: string + - type: 'null' title: Text - maxLength: 100 - type: string - name: text + - name: tag_ids in: query - - required: false + required: false schema: + anyOf: + - type: string + - type: 'null' title: Tag Ids - type: string - name: tag_ids - in: query responses: '200': description: Successful Response @@ -3429,13 +3436,13 @@ paths: summary: Get Project Inactivity operationId: get_project_inactivity parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id - in: path + title: Project Id responses: '200': description: Successful Response @@ -3444,42 +3451,6 @@ paths: schema: $ref: '#/components/schemas/Envelope_GetProjectInactivityResponse_' /v0/projects/{project_uuid}/comments: - get: - tags: - - projects - - comments - summary: Retrieve all comments for a specific project. - operationId: list_project_comments - parameters: - - required: true - schema: - title: Project Uuid - type: string - format: uuid - name: project_uuid - in: path - - required: false - schema: - title: Limit - type: integer - default: 20 - name: limit - in: query - - required: false - schema: - title: Offset - minimum: 0 - type: integer - default: 0 - name: offset - in: query - responses: - '200': - description: Successful Response - content: - application/json: - schema: - $ref: '#/components/schemas/Envelope_list_models_library.projects_comments.ProjectsCommentsAPI__' post: tags: - projects @@ -3488,56 +3459,63 @@ paths: contain the comment contents and user information. operationId: create_project_comment parameters: - - required: true + - name: project_uuid + in: path + required: true schema: - title: Project Uuid type: string format: uuid - name: project_uuid - in: path + title: Project Uuid requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/_ProjectCommentsBodyParams' - required: true responses: '201': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_dict_Literal__comment_id____pydantic.types.PositiveInt__' - /v0/projects/{project_uuid}/comments/{comment_id}: + $ref: '#/components/schemas/Envelope_dict_Literal__comment_id____Annotated_int__Gt___' get: tags: - projects - comments - summary: Retrieve a specific comment by its ID within a project. - operationId: get_project_comment + summary: Retrieve all comments for a specific project. + operationId: list_project_comments parameters: - - required: true + - name: project_uuid + in: path + required: true schema: - title: Project Uuid type: string format: uuid - name: project_uuid - in: path - - required: true + title: Project Uuid + - name: limit + in: query + required: false + schema: + type: integer + default: 20 + title: Limit + - name: offset + in: query + required: false schema: - title: Comment Id - exclusiveMinimum: true type: integer minimum: 0 - name: comment_id - in: path + default: 0 + title: Offset responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_ProjectsCommentsAPI_' + $ref: '#/components/schemas/Envelope_list_ProjectsCommentsAPI__' + /v0/projects/{project_uuid}/comments/{comment_id}: put: tags: - projects @@ -3546,27 +3524,27 @@ paths: body should contain the updated comment contents. operationId: update_project_comment parameters: - - required: true + - name: project_uuid + in: path + required: true schema: - title: Project Uuid type: string format: uuid - name: project_uuid + title: Project Uuid + - name: comment_id in: path - - required: true + required: true schema: - title: Comment Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Comment Id minimum: 0 - name: comment_id - in: path requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/_ProjectCommentsBodyParams' - required: true responses: '200': description: Successful Response @@ -3581,24 +3559,53 @@ paths: summary: Delete a specific comment associated with a project. operationId: delete_project_comment parameters: - - required: true + - name: project_uuid + in: path + required: true schema: - title: Project Uuid type: string format: uuid - name: project_uuid + title: Project Uuid + - name: comment_id in: path - - required: true + required: true schema: - title: Comment Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Comment Id minimum: 0 - name: comment_id - in: path responses: '204': description: Successful Response + get: + tags: + - projects + - comments + summary: Retrieve a specific comment by its ID within a project. + operationId: get_project_comment + parameters: + - name: project_uuid + in: path + required: true + schema: + type: string + format: uuid + title: Project Uuid + - name: comment_id + in: path + required: true + schema: + type: integer + exclusiveMinimum: true + title: Comment Id + minimum: 0 + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/Envelope_ProjectsCommentsAPI_' /v0/projects/{project_id}/folders/{folder_id}: put: tags: @@ -3607,90 +3614,92 @@ paths: summary: Move project to the folder operationId: replace_project_folder parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id + title: Project Id + - name: folder_id in: path - - required: true + required: true schema: + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' title: Folder Id - exclusiveMinimum: true - type: integer - minimum: 0 - name: folder_id - in: path responses: '204': description: Successful Response /v0/projects/{project_id}/groups/{group_id}: - put: + post: tags: - projects - groups - summary: Replace Project Group - operationId: replace_project_group + summary: Create Project Group + operationId: create_project_group parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id + title: Project Id + - name: group_id in: path - - required: true + required: true schema: - title: Group Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Group Id minimum: 0 - name: group_id - in: path requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/_ProjectsGroupsBodyParams' - required: true responses: - '200': + '201': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/Envelope_ProjectGroupGet_' - post: + put: tags: - projects - groups - summary: Create Project Group - operationId: create_project_group + summary: Replace Project Group + operationId: replace_project_group parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id + title: Project Id + - name: group_id in: path - - required: true + required: true schema: - title: Group Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Group Id minimum: 0 - name: group_id - in: path requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/_ProjectsGroupsBodyParams' - required: true responses: - '201': + '200': description: Successful Response content: application/json: @@ -3703,21 +3712,21 @@ paths: summary: Delete Project Group operationId: delete_project_group parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id + title: Project Id + - name: group_id in: path - - required: true + required: true schema: - title: Group Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Group Id minimum: 0 - name: group_id - in: path responses: '204': description: Successful Response @@ -3729,20 +3738,20 @@ paths: summary: List Project Groups operationId: list_project_groups parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id - in: path + title: Project Id responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_simcore_service_webserver.projects._groups_api.ProjectGroupGet__' + $ref: '#/components/schemas/Envelope_list_ProjectGroupGet__' /v0/projects/{project_id}/metadata: get: tags: @@ -3751,13 +3760,13 @@ paths: summary: Get Project Metadata operationId: get_project_metadata parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id - in: path + title: Project Id responses: '200': description: Successful Response @@ -3772,19 +3781,19 @@ paths: summary: Update Project Metadata operationId: update_project_metadata parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id - in: path + title: Project Id requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/ProjectMetadataUpdate' - required: true responses: '200': description: Successful Response @@ -3800,18 +3809,18 @@ paths: summary: Create Node operationId: create_node parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string - name: project_id - in: path + title: Project Id requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/NodeCreate' - required: true responses: '201': description: Successful Response @@ -3827,18 +3836,18 @@ paths: summary: Get Node operationId: get_node parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string - name: project_id + title: Project Id + - name: node_id in: path - - required: true + required: true schema: - title: Node Id type: string - name: node_id - in: path + title: Node Id responses: '200': description: Successful Response @@ -3853,18 +3862,18 @@ paths: summary: Delete Node operationId: delete_node parameters: - - required: true - schema: - title: Project Id - type: string - name: project_id + - name: project_id in: path - - required: true + required: true schema: - title: Node Id type: string - name: node_id + title: Project Id + - name: node_id in: path + required: true + schema: + type: string + title: Node Id responses: '204': description: Successful Response @@ -3875,25 +3884,25 @@ paths: summary: Patch Project Node operationId: patch_project_node parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id + title: Project Id + - name: node_id in: path - - required: true + required: true schema: - title: Node Id type: string - name: node_id - in: path + title: Node Id requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/NodePatch' - required: true responses: '204': description: Successful Response @@ -3905,24 +3914,24 @@ paths: summary: Retrieve Node operationId: retrieve_node parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string - name: project_id + title: Project Id + - name: node_id in: path - - required: true + required: true schema: - title: Node Id type: string - name: node_id - in: path + title: Node Id requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/NodeRetrieve' - required: true responses: '200': description: Successful Response @@ -3938,18 +3947,18 @@ paths: summary: Start Node operationId: start_node parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string - name: project_id + title: Project Id + - name: node_id in: path - - required: true + required: true schema: - title: Node Id type: string - name: node_id - in: path + title: Node Id responses: '204': description: Successful Response @@ -3961,18 +3970,18 @@ paths: summary: Stop Node operationId: stop_node parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string - name: project_id + title: Project Id + - name: node_id in: path - - required: true + required: true schema: - title: Node Id type: string - name: node_id - in: path + title: Node Id responses: '200': description: Successful Response @@ -3989,18 +3998,18 @@ paths: description: Note that it has only effect on nodes associated to dynamic services operationId: restart_node parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string - name: project_id + title: Project Id + - name: node_id in: path - - required: true + required: true schema: - title: Node Id type: string - name: node_id - in: path + title: Node Id responses: '204': description: Successful Response @@ -4012,24 +4021,24 @@ paths: summary: Update Node Outputs operationId: update_node_outputs parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string - name: project_id + title: Project Id + - name: node_id in: path - - required: true + required: true schema: - title: Node Id type: string - name: node_id - in: path + title: Node Id requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/NodeOutputs' - required: true responses: '204': description: Successful Response @@ -4041,25 +4050,25 @@ paths: summary: Get Node Resources operationId: get_node_resources parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string - name: project_id + title: Project Id + - name: node_id in: path - - required: true + required: true schema: - title: Node Id type: string - name: node_id - in: path + title: Node Id responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_dict_models_library.docker.DockerGenericTag__models_library.services_resources.ImageResources__' + $ref: '#/components/schemas/Envelope_dict_Annotated_str__StringConstraints___ImageResources__' put: tags: - projects @@ -4067,34 +4076,32 @@ paths: summary: Replace Node Resources operationId: replace_node_resources parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string - name: project_id + title: Project Id + - name: node_id in: path - - required: true + required: true schema: - title: Node Id type: string - name: node_id - in: path + title: Node Id requestBody: + required: true content: application/json: schema: - title: ' New' type: object - additionalProperties: - $ref: '#/components/schemas/ImageResources' - required: true + title: ' New' responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_dict_models_library.docker.DockerGenericTag__models_library.services_resources.ImageResources__' + $ref: '#/components/schemas/Envelope_dict_Annotated_str__StringConstraints___ImageResources__' /v0/projects/{project_id}/nodes/-/services:access: get: tags: @@ -4103,21 +4110,21 @@ paths: summary: Check whether provided group has access to the project services operationId: get_project_services_access_for_gid parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id - in: path - - required: true + title: Project Id + - name: for_gid + in: query + required: true schema: - title: For Gid - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: For Gid minimum: 0 - name: for_gid - in: query responses: '200': description: Successful Response @@ -4133,20 +4140,20 @@ paths: summary: Lists all previews in the node's project operationId: list_project_nodes_previews parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id - in: path + title: Project Id responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_simcore_service_webserver.projects._nodes_handlers._ProjectNodePreview__' + $ref: '#/components/schemas/Envelope_list__ProjectNodePreview__' /v0/projects/{project_id}/nodes/{node_id}/preview: get: tags: @@ -4155,20 +4162,20 @@ paths: summary: Gets a give node's preview operationId: get_project_node_preview parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id + title: Project Id + - name: node_id in: path - - required: true + required: true schema: - title: Node Id type: string format: uuid - name: node_id - in: path + title: Node Id responses: '200': description: Successful Response @@ -4185,20 +4192,20 @@ paths: summary: Get currently connected pricing unit to the project node. operationId: get_project_node_pricing_unit parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id + title: Project Id + - name: node_id in: path - - required: true + required: true schema: - title: Node Id type: string format: uuid - name: node_id - in: path + title: Node Id responses: '200': description: Successful Response @@ -4214,36 +4221,36 @@ paths: one pricing unit) operationId: connect_pricing_unit_to_project_node parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id + title: Project Id + - name: node_id in: path - - required: true + required: true schema: - title: Node Id type: string format: uuid - name: node_id + title: Node Id + - name: pricing_plan_id in: path - - required: true + required: true schema: - title: Pricing Plan Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Pricing Plan Id minimum: 0 - name: pricing_plan_id + - name: pricing_unit_id in: path - - required: true + required: true schema: - title: Pricing Unit Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Pricing Unit Id minimum: 0 - name: pricing_unit_id - in: path responses: '204': description: Successful Response @@ -4256,20 +4263,20 @@ paths: description: New in version *0.10* operationId: get_project_inputs parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id - in: path + title: Project Id responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_dict_uuid.UUID__models_library.api_schemas_webserver.projects_ports.ProjectInputGet__' + $ref: '#/components/schemas/Envelope_dict_UUID__ProjectInputGet__' patch: tags: - projects @@ -4278,29 +4285,29 @@ paths: description: New in version *0.10* operationId: update_project_inputs parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id - in: path + title: Project Id requestBody: + required: true content: application/json: schema: - title: ' Updates' type: array items: $ref: '#/components/schemas/ProjectInputUpdate' - required: true + title: ' Updates' responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_dict_uuid.UUID__models_library.api_schemas_webserver.projects_ports.ProjectInputGet__' + $ref: '#/components/schemas/Envelope_dict_UUID__ProjectInputGet__' /v0/projects/{project_id}/outputs: get: tags: @@ -4310,20 +4317,20 @@ paths: description: New in version *0.10* operationId: get_project_outputs parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id - in: path + title: Project Id responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_dict_uuid.UUID__models_library.api_schemas_webserver.projects_ports.ProjectOutputGet__' + $ref: '#/components/schemas/Envelope_dict_UUID__ProjectOutputGet__' /v0/projects/{project_id}/metadata/ports: get: tags: @@ -4333,20 +4340,20 @@ paths: description: New in version *0.12* operationId: list_project_metadata_ports parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id - in: path + title: Project Id responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_simcore_service_webserver.projects._ports_handlers.ProjectMetadataPortGet__' + $ref: '#/components/schemas/Envelope_list_ProjectMetadataPortGet__' /v0/projects/{project_id}:open: post: tags: @@ -4354,27 +4361,27 @@ paths: summary: Open Project operationId: open_project parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id - in: path - - required: false + title: Project Id + - name: disable_service_auto_start + in: query + required: false schema: - title: Disable Service Auto Start type: boolean default: false - name: disable_service_auto_start - in: query + title: Disable Service Auto Start requestBody: + required: true content: application/json: schema: - title: Client Session Id type: string - required: true + title: Client Session Id responses: '200': description: Successful Response @@ -4389,7 +4396,7 @@ paths: '403': description: ProjectInvalidRightsError '404': - description: UserDefaultWalletNotFoundError, ProjectNotFoundError + description: ProjectNotFoundError, UserDefaultWalletNotFoundError '409': description: ProjectTooManyProjectOpenedError '422': @@ -4403,20 +4410,20 @@ paths: summary: Close Project operationId: close_project parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id - in: path + title: Project Id requestBody: + required: true content: application/json: schema: - title: Client Session Id type: string - required: true + title: Client Session Id responses: '204': description: Successful Response @@ -4427,13 +4434,13 @@ paths: summary: Get Project State operationId: get_project_state parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id - in: path + title: Project Id responses: '200': description: Successful Response @@ -4453,19 +4460,19 @@ paths: NOTE: that the tag is not created here' operationId: add_project_tag parameters: - - required: true + - name: project_uuid + in: path + required: true schema: - title: Project Uuid type: string format: uuid - name: project_uuid + title: Project Uuid + - name: tag_id in: path - - required: true + required: true schema: - title: Tag Id type: integer - name: tag_id - in: path + title: Tag Id responses: '200': description: Successful Response @@ -4485,19 +4492,19 @@ paths: NOTE: that the tag is not deleted here' operationId: remove_project_tag parameters: - - required: true + - name: project_uuid + in: path + required: true schema: - title: Project Uuid type: string format: uuid - name: project_uuid + title: Project Uuid + - name: tag_id in: path - - required: true + required: true schema: - title: Tag Id type: integer - name: tag_id - in: path + title: Tag Id responses: '200': description: Successful Response @@ -4512,13 +4519,13 @@ paths: summary: Get current connected wallet to the project. operationId: get_project_wallet parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id - in: path + title: Project Id responses: '200': description: Successful Response @@ -4533,21 +4540,21 @@ paths: summary: Connect wallet to the project (Project can have only one wallet) operationId: connect_wallet_to_project parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id + title: Project Id + - name: wallet_id in: path - - required: true + required: true schema: - title: Wallet Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Wallet Id minimum: 0 - name: wallet_id - in: path responses: '200': description: Successful Response @@ -4563,21 +4570,23 @@ paths: summary: Move project to the workspace operationId: replace_project_workspace parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id + title: Project Id + - name: workspace_id in: path - - required: true + required: true schema: + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' title: Workspace Id - exclusiveMinimum: true - type: integer - minimum: 0 - name: workspace_id - in: path responses: '204': description: Successful Response @@ -4605,59 +4614,56 @@ paths: are taken from context, optionally wallet_id parameter might be provided). operationId: list_resource_usage_services parameters: - - required: false + - name: order_by + in: query + required: false schema: - title: Order By type: string - description: Order by field (`credit_cost|node_id|node_name|project_id|project_name|root_parent_project_id|root_parent_project_name|service_key|service_run_status|service_type|service_version|started_at|stopped_at|transaction_status|user_email|user_id|wallet_id|wallet_name`) - and direction (`asc|desc`). The default sorting order is `{"field":"started_at","direction":"desc"}`. + contentMediaType: application/json + contentSchema: {} default: '{"field":"started_at","direction":"desc"}' - example: '{"field":"some_field_name","direction":"desc"}' - name: order_by + title: Order By + - name: wallet_id in: query - - required: false + required: false schema: + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' title: Wallet Id - exclusiveMinimum: true - type: integer - minimum: 0 - name: wallet_id + - name: filters in: query - - required: false + required: false schema: + anyOf: + - type: string + contentMediaType: application/json + contentSchema: {} + - type: 'null' title: Filters - type: string - description: Filters to process on the resource usages list, encoded as - JSON. Currently supports the filtering of 'started_at' field with 'from' - and 'until' parameters in ISO 8601 format. The date range - specified is inclusive. - name: filters + - name: limit in: query - - required: false + required: false schema: - title: Limit - exclusiveMaximum: true - minimum: 1 type: integer default: 20 - maximum: 50 - name: limit + title: Limit + - name: offset in: query - - required: false + required: false schema: - title: Offset - minimum: 0 type: integer default: 0 - name: offset - in: query + title: Offset responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_models_library.api_schemas_webserver.resource_usage.ServiceRunGet__' + $ref: '#/components/schemas/Envelope_list_ServiceRunGet__' /v0/services/-/aggregated-usages: get: tags: @@ -4667,49 +4673,43 @@ paths: be provided). operationId: list_osparc_credits_aggregated_usages parameters: - - required: false + - name: limit + in: query + required: false schema: - title: Limit - exclusiveMaximum: true - minimum: 1 type: integer default: 20 - maximum: 50 - name: limit + title: Limit + - name: offset in: query - - required: false + required: false schema: - title: Offset - minimum: 0 type: integer default: 0 - name: offset + title: Offset + - name: aggregated_by in: query - - required: false + required: true schema: $ref: '#/components/schemas/ServicesAggregatedUsagesType' - name: aggregated_by + - name: time_period in: query - - required: false + required: true schema: $ref: '#/components/schemas/ServicesAggregatedUsagesTimePeriod' - name: time_period + - name: wallet_id in: query - - required: false + required: true schema: - title: Wallet Id - exclusiveMinimum: true type: integer - minimum: 0 - name: wallet_id - in: query + title: Wallet Id responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_models_library.api_schemas_resource_usage_tracker.service_runs.OsparcCreditsAggregatedByServiceGet__' + $ref: '#/components/schemas/Envelope_list_OsparcCreditsAggregatedByServiceGet__' /v0/services/-/usage-report: get: tags: @@ -4719,34 +4719,35 @@ paths: wallet_id parameter might be provided). operationId: export_resource_usage_services parameters: - - required: false + - name: order_by + in: query + required: false schema: - title: Order By type: string - description: Order by field (`credit_cost|node_id|node_name|project_id|project_name|root_parent_project_id|root_parent_project_name|service_key|service_run_status|service_type|service_version|started_at|stopped_at|transaction_status|user_email|user_id|wallet_id|wallet_name`) - and direction (`asc|desc`). The default sorting order is `{"field":"started_at","direction":"desc"}`. + contentMediaType: application/json + contentSchema: {} default: '{"field":"started_at","direction":"desc"}' - example: '{"field":"some_field_name","direction":"desc"}' - name: order_by + title: Order By + - name: wallet_id in: query - - required: false + required: false schema: + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' title: Wallet Id - exclusiveMinimum: true - type: integer - minimum: 0 - name: wallet_id + - name: filters in: query - - required: false + required: false schema: + anyOf: + - type: string + contentMediaType: application/json + contentSchema: {} + - type: 'null' title: Filters - type: string - description: Filters to process on the resource usages list, encoded as - JSON. Currently supports the filtering of 'started_at' field with 'from' - and 'until' parameters in ISO 8601 format. The date range - specified is inclusive. - name: filters - in: query responses: '302': description: redirection to download link @@ -4760,22 +4761,22 @@ paths: summary: Retrieve detail information about pricing unit operationId: get_pricing_plan_unit parameters: - - required: true + - name: pricing_plan_id + in: path + required: true schema: - title: Pricing Plan Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Pricing Plan Id minimum: 0 - name: pricing_plan_id + - name: pricing_unit_id in: path - - required: true + required: true schema: - title: Pricing Unit Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Pricing Unit Id minimum: 0 - name: pricing_unit_id - in: path responses: '200': description: Successful Response @@ -4796,7 +4797,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_models_library.api_schemas_webserver.resource_usage.PricingPlanAdminGet__' + $ref: '#/components/schemas/Envelope_list_PricingPlanAdminGet__' post: tags: - admin @@ -4822,14 +4823,14 @@ paths: summary: Retrieve detail information about pricing plan operationId: get_pricing_plan parameters: - - required: true + - name: pricing_plan_id + in: path + required: true schema: - title: Pricing Plan Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Pricing Plan Id minimum: 0 - name: pricing_plan_id - in: path responses: '200': description: Successful Response @@ -4843,20 +4844,20 @@ paths: summary: Update detail information about pricing plan operationId: update_pricing_plan parameters: - - required: true + - name: pricing_plan_id + in: path + required: true schema: - title: Pricing Plan Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Pricing Plan Id minimum: 0 - name: pricing_plan_id - in: path requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/UpdatePricingPlanBodyParams' - required: true responses: '200': description: Successful Response @@ -4871,22 +4872,22 @@ paths: summary: Retrieve detail information about pricing unit operationId: get_pricing_unit parameters: - - required: true + - name: pricing_plan_id + in: path + required: true schema: - title: Pricing Plan Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Pricing Plan Id minimum: 0 - name: pricing_plan_id + - name: pricing_unit_id in: path - - required: true + required: true schema: - title: Pricing Unit Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Pricing Unit Id minimum: 0 - name: pricing_unit_id - in: path responses: '200': description: Successful Response @@ -4900,28 +4901,28 @@ paths: summary: Update detail information about pricing plan operationId: update_pricing_unit parameters: - - required: true + - name: pricing_plan_id + in: path + required: true schema: - title: Pricing Plan Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Pricing Plan Id minimum: 0 - name: pricing_plan_id + - name: pricing_unit_id in: path - - required: true + required: true schema: - title: Pricing Unit Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Pricing Unit Id minimum: 0 - name: pricing_unit_id - in: path requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/UpdatePricingUnitBodyParams' - required: true responses: '200': description: Successful Response @@ -4936,20 +4937,20 @@ paths: summary: Create pricing unit operationId: create_pricing_unit parameters: - - required: true + - name: pricing_plan_id + in: path + required: true schema: - title: Pricing Plan Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Pricing Plan Id minimum: 0 - name: pricing_plan_id - in: path requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/CreatePricingUnitBodyParams' - required: true responses: '200': description: Successful Response @@ -4964,41 +4965,41 @@ paths: summary: List services that are connected to the provided pricing plan operationId: list_connected_services_to_pricing_plan parameters: - - required: true + - name: pricing_plan_id + in: path + required: true schema: - title: Pricing Plan Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Pricing Plan Id minimum: 0 - name: pricing_plan_id - in: path responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_models_library.api_schemas_webserver.resource_usage.PricingPlanToServiceAdminGet__' + $ref: '#/components/schemas/Envelope_list_PricingPlanToServiceAdminGet__' post: tags: - admin summary: Connect service with pricing plan operationId: connect_service_to_pricing_plan parameters: - - required: true + - name: pricing_plan_id + in: path + required: true schema: - title: Pricing Plan Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Pricing Plan Id minimum: 0 - name: pricing_plan_id - in: path requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/ConnectServiceToPricingPlanBodyParams' - required: true responses: '200': description: Successful Response @@ -5046,10 +5047,10 @@ paths: content: application/json: schema: - title: Response Get Storage Locations - type: array items: $ref: '#/components/schemas/DatasetMetaData' + type: array + title: Response Get Storage Locations /v0/storage/locations/{location_id}:sync: post: tags: @@ -5059,26 +5060,26 @@ paths: description: Returns an object containing added, changed and removed paths operationId: synchronise_meta_data_table parameters: - - required: true + - name: location_id + in: path + required: true schema: - title: Location Id type: integer - name: location_id - in: path - - required: false + title: Location Id + - name: dry_run + in: query + required: false schema: - title: Dry Run type: boolean default: false - name: dry_run + title: Dry Run + - name: fire_and_forget in: query - - required: false + required: false schema: - title: Fire And Forget type: boolean default: false - name: fire_and_forget - in: query + title: Fire And Forget responses: '200': description: Successful Response @@ -5094,19 +5095,19 @@ paths: description: returns all the top level datasets a user has access to operationId: get_datasets_metadata parameters: - - required: true + - name: location_id + in: path + required: true schema: - title: Location Id type: integer - name: location_id - in: path + title: Location Id responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_simcore_service_webserver.storage.schemas.DatasetMetaData__' + $ref: '#/components/schemas/Envelope_list_DatasetMetaData__' /v0/storage/locations/{location_id}/files/metadata: get: tags: @@ -5116,37 +5117,37 @@ paths: may be used) operationId: get_files_metadata parameters: - - required: true + - name: location_id + in: path + required: true schema: - title: Location Id type: integer - name: location_id - in: path - - required: false + title: Location Id + - name: uuid_filter + in: query + required: false schema: - title: Uuid Filter type: string default: '' - name: uuid_filter + title: Uuid Filter + - name: expand_dirs in: query - - description: Automatic directory expansion. This will be replaced by pagination - the future required: false schema: - title: Expand Dirs type: boolean description: Automatic directory expansion. This will be replaced by pagination the future default: true - name: expand_dirs - in: query + title: Expand Dirs + description: Automatic directory expansion. This will be replaced by pagination + the future responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_simcore_service_webserver.storage.schemas.DatasetMetaData__' + $ref: '#/components/schemas/Envelope_list_DatasetMetaData__' /v0/storage/locations/{location_id}/datasets/{dataset_id}/metadata: get: tags: @@ -5155,36 +5156,36 @@ paths: description: returns all the file meta data inside dataset with dataset_id operationId: get_files_metadata_dataset parameters: - - required: true + - name: location_id + in: path + required: true schema: - title: Location Id type: integer - name: location_id + title: Location Id + - name: dataset_id in: path - - required: true + required: true schema: - title: Dataset Id type: string - name: dataset_id - in: path - - description: Automatic directory expansion. This will be replaced by pagination - the future + title: Dataset Id + - name: expand_dirs + in: query required: false schema: - title: Expand Dirs type: boolean description: Automatic directory expansion. This will be replaced by pagination the future default: true - name: expand_dirs - in: query + title: Expand Dirs + description: Automatic directory expansion. This will be replaced by pagination + the future responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_models_library.api_schemas_storage.FileMetaDataGet__' + $ref: '#/components/schemas/Envelope_list_FileMetaDataGet__' /v0/storage/locations/{location_id}/files/{file_id}/metadata: get: tags: @@ -5194,28 +5195,28 @@ paths: to operationId: get_file_metadata parameters: - - required: true + - name: location_id + in: path + required: true schema: - title: Location Id type: integer - name: location_id + title: Location Id + - name: file_id in: path - - required: true + required: true schema: - title: File Id type: string - name: file_id - in: path + title: File Id responses: '200': description: Successful Response content: application/json: schema: - title: Response Get File Metadata anyOf: - $ref: '#/components/schemas/FileMetaData' - $ref: '#/components/schemas/Envelope_FileMetaDataGet_' + title: Response Get File Metadata /v0/storage/locations/{location_id}/files/{file_id}: get: tags: @@ -5224,25 +5225,24 @@ paths: description: creates a download file link if user has the rights to operationId: download_file parameters: - - required: true + - name: location_id + in: path + required: true schema: - title: Location Id type: integer - name: location_id + title: Location Id + - name: file_id in: path - - required: true + required: true schema: - title: File Id type: string - name: file_id - in: path - - required: false + title: File Id + - name: link_type + in: query + required: false schema: - allOf: - - $ref: '#/components/schemas/LinkType' + $ref: '#/components/schemas/LinkType' default: PRESIGNED - name: link_type - in: query responses: '200': description: Successful Response @@ -5258,48 +5258,52 @@ paths: expects the client to complete/abort upload operationId: upload_file parameters: - - required: true + - name: location_id + in: path + required: true schema: - title: Location Id type: integer - name: location_id + title: Location Id + - name: file_id in: path - - required: true + required: true schema: - title: File Id type: string - name: file_id - in: path - - required: true + title: File Id + - name: file_size + in: query + required: true schema: + anyOf: + - type: string + pattern: ^\s*(\d*\.?\d+)\s*(\w+)? + - type: integer + minimum: 0 + - type: 'null' title: File Size - type: integer - name: file_size + - name: link_type in: query - - required: false + required: false schema: - allOf: - - $ref: '#/components/schemas/LinkType' + $ref: '#/components/schemas/LinkType' default: PRESIGNED - name: link_type + - name: is_directory in: query - - required: false + required: false schema: - title: Is Directory type: boolean default: false - name: is_directory - in: query + title: Is Directory responses: '200': description: Successful Response content: application/json: schema: - title: Response Upload File anyOf: - $ref: '#/components/schemas/Envelope_FileUploadSchema_' - - $ref: '#/components/schemas/Envelope_AnyUrl_' + - $ref: '#/components/schemas/Envelope_Url_' + title: Response Upload File delete: tags: - storage @@ -5307,18 +5311,18 @@ paths: description: deletes file if user has the rights to operationId: delete_file parameters: - - required: true + - name: location_id + in: path + required: true schema: - title: Location Id type: integer - name: location_id + title: Location Id + - name: file_id in: path - - required: true + required: true schema: - title: File Id type: string - name: file_id - in: path + title: File Id responses: '204': description: Successful Response @@ -5332,18 +5336,18 @@ paths: to the latest version if available, else will delete the file' operationId: abort_upload_file parameters: - - required: true + - name: location_id + in: path + required: true schema: - title: Location Id type: integer - name: location_id + title: Location Id + - name: file_id in: path - - required: true + required: true schema: - title: File Id type: string - name: file_id - in: path + title: File Id responses: '204': description: Successful Response @@ -5355,24 +5359,24 @@ paths: description: completes an upload if the user has the rights to operationId: complete_upload_file parameters: - - required: true + - name: location_id + in: path + required: true schema: - title: Location Id type: integer - name: location_id + title: Location Id + - name: file_id in: path - - required: true + required: true schema: - title: File Id type: string - name: file_id - in: path + title: File Id requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/Envelope_FileUploadCompletionBody_' - required: true responses: '202': description: Successful Response @@ -5388,24 +5392,24 @@ paths: description: Returns state of upload completion operationId: is_completed_upload_file parameters: - - required: true + - name: location_id + in: path + required: true schema: - title: Location Id type: integer - name: location_id + title: Location Id + - name: file_id in: path - - required: true + required: true schema: - title: File Id type: string - name: file_id + title: File Id + - name: future_id in: path - - required: true + required: true schema: - title: Future Id type: string - name: future_id - in: path + title: Future Id responses: '200': description: Successful Response @@ -5430,20 +5434,20 @@ paths: summary: Trash Project operationId: trash_project parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id - in: path - - required: false + title: Project Id + - name: force + in: query + required: false schema: - title: Force type: boolean default: false - name: force - in: query + title: Force responses: '204': description: Successful Response @@ -5461,13 +5465,13 @@ paths: summary: Untrash Project operationId: untrash_project parameters: - - required: true + - name: project_id + in: path + required: true schema: - title: Project Id type: string format: uuid - name: project_id - in: path + title: Project Id responses: '204': description: Successful Response @@ -5479,28 +5483,29 @@ paths: summary: Trash Folder operationId: trash_folder parameters: - - required: true + - name: folder_id + in: path + required: true schema: - title: Folder Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Folder Id minimum: 0 - name: folder_id - in: path - - required: false + - name: force + in: query + required: false schema: - title: Force type: boolean default: false - name: force - in: query + title: Force responses: '204': description: Successful Response '404': description: Not such a folder '409': - 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 '503': description: Trash service error /v0/folders/{folder_id}:untrash: @@ -5511,14 +5516,66 @@ paths: summary: Untrash Folder operationId: untrash_folder parameters: - - required: true + - name: folder_id + in: path + required: true schema: - title: Folder Id + type: integer exclusiveMinimum: true + title: Folder Id + minimum: 0 + responses: + '204': + description: Successful Response + /v0/workspaces/{workspace_id}:trash: + post: + tags: + - trash + - workspaces + summary: Trash Workspace + operationId: trash_workspace + parameters: + - name: workspace_id + in: path + required: true + schema: type: integer + exclusiveMinimum: true + title: Workspace Id minimum: 0 - name: folder_id + - name: force + in: query + required: false + schema: + type: boolean + default: false + title: Force + responses: + '204': + description: Successful Response + '404': + description: Not such a workspace + '409': + description: One or more projects in the workspace are in use and cannot + be trashed + '503': + description: Trash service error + /v0/workspaces/{workspace_id}:untrash: + post: + tags: + - trash + - workspaces + summary: Untrash Workspace + operationId: untrash_workspace + parameters: + - name: workspace_id in: path + required: true + schema: + type: integer + exclusiveMinimum: true + title: Workspace Id + minimum: 0 responses: '204': description: Successful Response @@ -5529,24 +5586,24 @@ paths: summary: List Repos operationId: list_repos parameters: - - required: false + - name: limit + in: query + required: false schema: - title: Limit - exclusiveMaximum: true - minimum: 1 type: integer + minimum: 1 + exclusiveMaximum: true default: 20 + title: Limit maximum: 50 - name: limit + - name: offset in: query - - required: false + required: false schema: - title: Offset - minimum: 0 type: integer + minimum: 0 default: 0 - name: offset - in: query + title: Offset responses: '200': description: Successful Response @@ -5561,31 +5618,31 @@ paths: summary: List Checkpoints operationId: list_checkpoints parameters: - - required: true + - name: project_uuid + in: path + required: true schema: - title: Project Uuid type: string format: uuid - name: project_uuid - in: path - - required: false + title: Project Uuid + - name: limit + in: query + required: false schema: - title: Limit - exclusiveMaximum: true - minimum: 1 type: integer + minimum: 1 + exclusiveMaximum: true default: 20 + title: Limit maximum: 50 - name: limit + - name: offset in: query - - required: false + required: false schema: - title: Offset - minimum: 0 type: integer + minimum: 0 default: 0 - name: offset - in: query + title: Offset responses: '200': description: Successful Response @@ -5599,19 +5656,19 @@ paths: summary: Create Checkpoint operationId: create_checkpoint parameters: - - required: true + - name: project_uuid + in: path + required: true schema: - title: Project Uuid type: string format: uuid - name: project_uuid - in: path + title: Project Uuid requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/CheckpointNew' - required: true responses: '200': description: Successful Response @@ -5626,24 +5683,25 @@ paths: summary: Get Checkpoint operationId: get_checkpoint parameters: - - required: true + - name: ref_id + in: path + required: true schema: - title: Ref Id anyOf: - type: integer - type: string - enum: - HEAD + const: HEAD type: string - name: ref_id + title: Ref Id + - name: project_uuid in: path - - required: true + required: true schema: - title: Project Uuid type: string format: uuid - name: project_uuid - in: path + title: Project Uuid responses: '200': description: Successful Response @@ -5658,27 +5716,27 @@ paths: description: Update Checkpoint Annotations operationId: update_checkpoint parameters: - - required: true + - name: ref_id + in: path + required: true schema: - title: Ref Id anyOf: - type: integer - type: string - name: ref_id + title: Ref Id + - name: project_uuid in: path - - required: true + required: true schema: - title: Project Uuid type: string format: uuid - name: project_uuid - in: path + title: Project Uuid requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/CheckpointAnnotations' - required: true responses: '200': description: Successful Response @@ -5693,21 +5751,21 @@ paths: summary: View Project Workbench operationId: view_project_workbench parameters: - - required: true + - name: ref_id + in: path + required: true schema: - title: Ref Id anyOf: - type: integer - type: string - name: ref_id + title: Ref Id + - name: project_uuid in: path - - required: true + required: true schema: - title: Project Uuid type: string format: uuid - name: project_uuid - in: path + title: Project Uuid responses: '200': description: Successful Response @@ -5722,21 +5780,21 @@ paths: summary: Checkout operationId: checkout parameters: - - required: true + - name: ref_id + in: path + required: true schema: - title: Ref Id anyOf: - type: integer - type: string - name: ref_id + title: Ref Id + - name: project_uuid in: path - - required: true + required: true schema: - title: Project Uuid type: string format: uuid - name: project_uuid - in: path + title: Project Uuid responses: '200': description: Successful Response @@ -5745,29 +5803,17 @@ paths: schema: $ref: '#/components/schemas/Envelope_CheckpointApiModel_' /v0/workspaces: - get: - tags: - - workspaces - summary: List Workspaces - operationId: list_workspaces - responses: - '200': - description: Successful Response - content: - application/json: - schema: - $ref: '#/components/schemas/Envelope_list_models_library.api_schemas_webserver.workspaces.WorkspaceGet__' post: tags: - workspaces summary: Create Workspace operationId: create_workspace requestBody: + required: true content: application/json: schema: - $ref: '#/components/schemas/CreateWorkspaceBodyParams' - required: true + $ref: '#/components/schemas/WorkspaceCreateBodyParams' responses: '201': description: Successful Response @@ -5775,6 +5821,52 @@ paths: application/json: schema: $ref: '#/components/schemas/Envelope_WorkspaceGet_' + get: + tags: + - workspaces + summary: List Workspaces + operationId: list_workspaces + parameters: + - name: order_by + in: query + required: false + schema: + type: string + contentMediaType: application/json + contentSchema: {} + default: '{"field":"modified","direction":"desc"}' + title: Order By + - name: filters + in: query + required: false + schema: + anyOf: + - type: string + contentMediaType: application/json + contentSchema: {} + - type: 'null' + title: Filters + - name: limit + in: query + required: false + schema: + type: integer + default: 20 + title: Limit + - name: offset + in: query + required: false + schema: + type: integer + default: 0 + title: Offset + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/Envelope_list_WorkspaceGet__' /v0/workspaces/{workspace_id}: get: tags: @@ -5782,14 +5874,14 @@ paths: summary: Get Workspace operationId: get_workspace parameters: - - required: true + - name: workspace_id + in: path + required: true schema: - title: Workspace Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Workspace Id minimum: 0 - name: workspace_id - in: path responses: '200': description: Successful Response @@ -5803,20 +5895,20 @@ paths: summary: Replace Workspace operationId: replace_workspace parameters: - - required: true + - name: workspace_id + in: path + required: true schema: - title: Workspace Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Workspace Id minimum: 0 - name: workspace_id - in: path requestBody: + required: true content: application/json: schema: - $ref: '#/components/schemas/PutWorkspaceBodyParams' - required: true + $ref: '#/components/schemas/WorkspaceReplaceBodyParams' responses: '200': description: Successful Response @@ -5830,85 +5922,85 @@ paths: summary: Delete Workspace operationId: delete_workspace parameters: - - required: true + - name: workspace_id + in: path + required: true schema: - title: Workspace Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Workspace Id minimum: 0 - name: workspace_id - in: path responses: '204': description: Successful Response /v0/workspaces/{workspace_id}/groups/{group_id}: - put: + post: tags: - workspaces - groups - summary: Replace Workspace Group - operationId: replace_workspace_group + summary: Create Workspace Group + operationId: create_workspace_group parameters: - - required: true + - name: workspace_id + in: path + required: true schema: - title: Workspace Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Workspace Id minimum: 0 - name: workspace_id + - name: group_id in: path - - required: true + required: true schema: - title: Group Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Group Id minimum: 0 - name: group_id - in: path requestBody: + required: true content: application/json: schema: - $ref: '#/components/schemas/_WorkspacesGroupsBodyParams' - required: true + $ref: '#/components/schemas/WorkspacesGroupsBodyParams' responses: - '200': + '201': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/Envelope_WorkspaceGroupGet_' - post: + put: tags: - workspaces - groups - summary: Create Workspace Group - operationId: create_workspace_group + summary: Replace Workspace Group + operationId: replace_workspace_group parameters: - - required: true + - name: workspace_id + in: path + required: true schema: - title: Workspace Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Workspace Id minimum: 0 - name: workspace_id + - name: group_id in: path - - required: true + required: true schema: - title: Group Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Group Id minimum: 0 - name: group_id - in: path requestBody: + required: true content: application/json: schema: - $ref: '#/components/schemas/_WorkspacesGroupsBodyParams' - required: true + $ref: '#/components/schemas/WorkspacesGroupsBodyParams' responses: - '201': + '200': description: Successful Response content: application/json: @@ -5921,22 +6013,22 @@ paths: summary: Delete Workspace Group operationId: delete_workspace_group parameters: - - required: true + - name: workspace_id + in: path + required: true schema: - title: Workspace Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Workspace Id minimum: 0 - name: workspace_id + - name: group_id in: path - - required: true + required: true schema: - title: Group Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Group Id minimum: 0 - name: group_id - in: path responses: '204': description: Successful Response @@ -5948,21 +6040,21 @@ paths: summary: List Workspace Groups operationId: list_workspace_groups parameters: - - required: true + - name: workspace_id + in: path + required: true schema: - title: Workspace Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Workspace Id minimum: 0 - name: workspace_id - in: path responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Envelope_list_simcore_service_webserver.workspaces._groups_api.WorkspaceGroupGet__' + $ref: '#/components/schemas/Envelope_list_WorkspaceGroupGet__' /v0/email:test: post: tags: @@ -5970,18 +6062,20 @@ paths: summary: Test Email operationId: test_email parameters: - - required: false + - name: x-simcore-products-name + in: header + required: false schema: + anyOf: + - type: string + - type: 'null' title: X-Simcore-Products-Name - type: string - name: x-simcore-products-name - in: header requestBody: + required: true content: application/json: schema: $ref: '#/components/schemas/TestEmail' - required: true responses: '200': description: Successful Response @@ -6064,12 +6158,14 @@ paths: summary: Get App Diagnostics operationId: get_app_diagnostics parameters: - - required: false + - name: top_tracemalloc + in: query + required: false schema: + anyOf: + - type: integer + - type: 'null' title: Top Tracemalloc - type: integer - name: top_tracemalloc - in: query responses: '200': description: Returns app diagnostics report @@ -6084,12 +6180,12 @@ paths: summary: Get Service Status operationId: get_service_status parameters: - - required: true + - name: service_name + in: path + required: true schema: - title: Service Name type: string - name: service_name - in: path + title: Service Name responses: '200': description: Returns app status check @@ -6100,2185 +6196,2790 @@ paths: components: schemas: AccessEnum: - title: AccessEnum + type: string enum: - ReadAndWrite - Invisible - ReadOnly - type: string - description: An enumeration. - AccountRequestInfo: - title: AccountRequestInfo - required: - - form - - captcha + title: AccessEnum + AccessRights: + properties: + read: + type: boolean + title: Read + description: has read access + write: + type: boolean + title: Write + description: has write access + delete: + type: boolean + title: Delete + description: has deletion rights + additionalProperties: false type: object + required: + - read + - write + - delete + title: AccessRights + AccountRequestInfo: properties: form: - title: Form type: object + title: Form captcha: - title: Captcha type: string + title: Captcha + type: object + required: + - form + - captcha + title: AccountRequestInfo example: + captcha: A12B34 form: - firstName: James - lastName: Maxwel - email: maxwel@email.com - phone: +1 123456789 - company: EM Com address: Infinite Loop + application: Antenna_Design city: Washington - postalCode: '98001' + company: EM Com country: USA - application: Antenna_Design description: Description of something + email: maxwel@email.com + eula: true + firstName: James hear: Search_Engine + lastName: Maxwel + phone: +1 123456789 + postalCode: '98001' privacyPolicy: true - eula: true - captcha: A12B34 Activity: - title: Activity - required: - - stats - - limits - type: object properties: stats: $ref: '#/components/schemas/Stats' limits: $ref: '#/components/schemas/Limits' queued: - title: Queued type: boolean - Annotation: - title: Annotation - required: - - type - - color - - attributes + title: Queued type: object + required: + - stats + - limits + title: Activity + Annotation: properties: type: - title: Type + type: string enum: - note - rect - text - type: string + title: Type color: - title: Color type: string format: color + title: Color attributes: - title: Attributes type: object + title: Attributes description: svg attributes additionalProperties: false - Announcement: - title: Announcement - required: - - id - - products - - start - - end - - title - - description - - link - - widgets type: object + required: + - type + - color + - attributes + title: Annotation + Announcement: properties: id: - title: Id type: string + title: Id products: - title: Products - type: array items: type: string + type: array + title: Products start: - title: Start type: string format: date-time + title: Start end: - title: End type: string format: date-time + title: End title: - title: Title type: string + title: Title description: - title: Description type: string + title: Description link: - title: Link type: string + title: Link widgets: - title: Widgets - type: array items: + type: string enum: - login - ribbon - user-menu - type: string - ApiKeyCreate: - title: ApiKeyCreate - required: - - display_name + type: array + title: Widgets type: object + required: + - id + - products + - start + - end + - title + - description + - link + - widgets + title: Announcement + ApiKeyCreate: properties: display_name: - title: Display Name - minLength: 3 type: string + minLength: 3 + title: Display Name expiration: + anyOf: + - type: string + format: duration + - type: 'null' title: Expiration - type: number description: Time delta from creation time to expiration. If None, then it does not expire. - format: time-delta - ApiKeyGet: - title: ApiKeyGet + type: object required: - display_name - - api_key - - api_secret - type: object + title: ApiKeyCreate + ApiKeyGet: properties: display_name: - title: Display Name - minLength: 3 type: string + minLength: 3 + title: Display Name api_key: - title: Api Key type: string + title: Api Key api_secret: - title: Api Secret type: string - AppStatusCheck: - title: AppStatusCheck - required: - - app_name - - version + title: Api Secret type: object + required: + - display_name + - api_key + - api_secret + title: ApiKeyGet + AppStatusCheck: properties: app_name: - title: App Name type: string + title: App Name description: Application name version: - title: Version type: string + title: Version description: Application's version services: - title: Services type: object + title: Services description: Other backend services connected from this service default: {} sessions: + anyOf: + - type: object + - type: 'null' title: Sessions - type: object description: Client sessions info. If single session per app, then is denoted as main default: {} url: + anyOf: + - type: string + minLength: 1 + format: uri + - type: 'null' title: Url - maxLength: 65536 - minLength: 1 - type: string description: Link to current resource - format: uri diagnostics_url: + anyOf: + - type: string + minLength: 1 + format: uri + - type: 'null' title: Diagnostics Url - maxLength: 65536 - minLength: 1 - type: string description: Link to diagnostics report sub-resource. This MIGHT take some time to compute - format: uri - Author: - title: Author - required: - - name - - email type: object + required: + - app_name + - version + title: AppStatusCheck + Author: properties: name: - title: Name type: string + title: Name description: Name of the author email: - title: Email type: string - description: Email address format: email + title: Email + description: Email address affiliation: + anyOf: + - type: string + - type: 'null' title: Affiliation - type: string - Body_service_submission: - title: Body_service_submission - required: - - _file type: object + required: + - name + - email + title: Author + Body_service_submission: properties: - _file: - title: ' File' + file: type: string - description: metadata.json submission file format: binary - BootChoice: - title: BootChoice + title: File + description: metadata.json submission file + type: object required: - - label - - description - type: object + - file + title: Body_service_submission + BootChoice: properties: label: - title: Label type: string + title: Label description: - title: Description type: string + title: Description + type: object + required: + - label + - description + title: BootChoice BootMode: - title: BootMode + type: string enum: - CPU - GPU - MPI - type: string - description: An enumeration. + title: BootMode BootOption: - title: BootOption - required: - - label - - description - - default - - items - type: object properties: label: - title: Label type: string + title: Label description: - title: Description type: string + title: Description default: - title: Default type: string + title: Default items: - title: Items - type: object additionalProperties: $ref: '#/components/schemas/BootChoice' - CatalogServiceGet: - title: CatalogServiceGet + type: object + title: Items + type: object required: - - key - - version - - name + - label - description - - type - - authors - - inputs - - outputs - type: object + - default + - items + title: BootOption + CatalogServiceGet: properties: key: - title: Key - pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ type: string + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + title: Key version: - title: Version - pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ type: string + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + title: Version name: - title: Name type: string + title: Name thumbnail: + anyOf: + - type: string + maxLength: 2083 + minLength: 1 + format: uri + - type: 'null' title: Thumbnail - maxLength: 2083 - minLength: 1 - type: string - format: uri description: - title: Description type: string + title: Description descriptionUi: - title: Descriptionui type: boolean + title: Descriptionui default: false versionDisplay: + anyOf: + - type: string + - type: 'null' title: Versiondisplay - type: string type: $ref: '#/components/schemas/ServiceType' contact: + anyOf: + - type: string + format: email + - type: 'null' title: Contact - type: string - format: email authors: - title: Authors - minItems: 1 - type: array items: $ref: '#/components/schemas/Author' + type: array + minItems: 1 + title: Authors owner: + anyOf: + - type: string + format: email + - type: 'null' title: Owner - type: string - format: email + description: None when the owner email cannot be found in the database inputs: - title: Inputs type: object - additionalProperties: - $ref: '#/components/schemas/ServiceInputGet' + title: Inputs description: inputs with extended information outputs: - title: Outputs type: object - additionalProperties: - $ref: '#/components/schemas/ServiceOutputGet' + title: Outputs description: outputs with extended information bootOptions: + anyOf: + - type: object + - type: 'null' title: Bootoptions - type: object - additionalProperties: - $ref: '#/components/schemas/BootOption' minVisibleInputs: + anyOf: + - type: integer + minimum: 0 + - type: 'null' title: Minvisibleinputs - minimum: 0 - type: integer accessRights: + anyOf: + - additionalProperties: + $ref: '#/components/schemas/ServiceGroupAccessRightsV2' + type: object + - type: 'null' title: Accessrights - type: object - additionalProperties: - $ref: '#/components/schemas/ServiceGroupAccessRightsV2' classifiers: + anyOf: + - items: + type: string + type: array + - type: 'null' title: Classifiers - type: array - items: - type: string default: [] quality: - title: Quality type: object + title: Quality default: {} history: - title: History - type: array items: $ref: '#/components/schemas/ServiceRelease' + type: array + title: History description: history of releases for this service at this point in time, starting from the newest to the oldest. It includes current release. default: [] + type: object + required: + - key + - version + - name + - description + - type + - contact + - authors + - owner + - inputs + - outputs + - accessRights + title: CatalogServiceGet example: - name: sleeper - description: A service which awaits for time to pass, two times. - description_ui: true - classifiers: [] - quality: {} accessRights: '1': execute: true write: false - key: simcore/services/comp/itis/sleeper - version: 2.2.1 - version_display: 2 Xtreme - type: computational authors: - - name: Author Bar + - affiliation: ACME email: author@acme.com - affiliation: ACME + name: Author Bar + classifiers: [] contact: contact@acme.com + description: A service which awaits for time to pass, two times. + description_ui: true + history: + - released: '2024-07-20T15:00:00' + version: 2.2.1 + version_display: Summer Release + - compatibility: + canUpdateTo: + version: 2.2.1 + version: 2.0.0 + - version: 0.9.11 + - version: 0.9.10 + - compatibility: + canUpdateTo: + version: 0.9.11 + version: 0.9.8 + - compatibility: + can_update_to: + version: 0.9.11 + released: '2024-01-20T18:49:17' + version: 0.9.1 + versionDisplay: Matterhorn + - retired: '2024-07-20T15:00:00' + version: 0.9.0 + - version: 0.8.0 + - version: 0.1.0 inputs: input0: - label: Acceleration - description: acceleration with units - type: ref_contentSchema contentSchema: title: Acceleration type: number x_unit: m/s**2 + description: acceleration with units keyId: input_1 + label: Acceleration + type: ref_contentSchema unitLong: meter/second3 unitShort: m/s3 + key: simcore/services/comp/itis/sleeper + name: sleeper outputs: outFile: + description: Time the service waited before completion displayOrder: 2 + keyId: output_2 label: Time Slept - description: Time the service waited before completion type: number unit: second unitLong: seconds unitShort: sec - keyId: output_2 owner: owner@acme.com - history: - - version: 2.2.1 - version_display: Summer Release - released: '2024-07-20T15:00:00' - - version: 2.0.0 - compatibility: - canUpdateTo: - version: 2.2.1 - - version: 0.9.11 - - version: 0.9.10 - - version: 0.9.8 - compatibility: - canUpdateTo: - version: 0.9.11 - - version: 0.9.1 - versionDisplay: Matterhorn - released: '2024-01-20T18:49:17' - compatibility: - can_update_to: - version: 0.9.11 - - version: 0.9.0 - retired: '2024-07-20T15:00:00' - - version: 0.8.0 - - version: 0.1.0 + quality: {} + type: computational + version: 2.2.1 + version_display: 2 Xtreme CatalogServiceUpdate: - title: CatalogServiceUpdate - type: object properties: name: + anyOf: + - type: string + - type: 'null' title: Name - type: string thumbnail: + anyOf: + - type: string + maxLength: 2083 + minLength: 1 + format: uri + - type: 'null' title: Thumbnail - maxLength: 2083 - minLength: 1 - type: string - format: uri description: + anyOf: + - type: string + - type: 'null' title: Description - type: string descriptionUi: - title: Descriptionui type: boolean + title: Descriptionui default: false versionDisplay: + anyOf: + - type: string + - type: 'null' title: Versiondisplay - type: string deprecated: + anyOf: + - type: string + format: date-time + - type: 'null' title: Deprecated - type: string - format: date-time classifiers: + anyOf: + - items: + type: string + type: array + - type: 'null' title: Classifiers - type: array - items: - type: string quality: - title: Quality type: object + title: Quality default: {} accessRights: + anyOf: + - additionalProperties: + $ref: '#/components/schemas/ServiceGroupAccessRightsV2' + type: object + - type: 'null' title: Accessrights - type: object - additionalProperties: - $ref: '#/components/schemas/ServiceGroupAccessRightsV2' - ChangePasswordBody: - title: ChangePasswordBody - required: - - current - - new - - confirm type: object + title: CatalogServiceUpdate + ChangePasswordBody: properties: current: - title: Current type: string format: password + title: Current writeOnly: true new: - title: New type: string format: password + title: New writeOnly: true confirm: - title: Confirm type: string format: password + title: Confirm writeOnly: true additionalProperties: false - CheckpointAnnotations: - title: CheckpointAnnotations type: object + required: + - current + - new + - confirm + title: ChangePasswordBody + CheckpointAnnotations: properties: tag: + anyOf: + - type: string + - type: 'null' title: Tag - type: string message: + anyOf: + - type: string + - type: 'null' title: Message - type: string + type: object + title: CheckpointAnnotations CheckpointApiModel: - title: CheckpointApiModel - required: - - id - - checksum - - created_at - - tags - - url - type: object properties: id: - title: Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Id minimum: 0 checksum: - title: Checksum - pattern: ^[a-fA-F0-9]{40}$ type: string + pattern: ^[a-fA-F0-9]{40}$ + title: Checksum created_at: - title: Created At type: string format: date-time + title: Created At tags: - title: Tags - type: array items: type: string + type: array + title: Tags message: + anyOf: + - type: string + - type: 'null' title: Message - type: string parents_ids: + anyOf: + - items: + type: integer + exclusiveMinimum: true + minimum: 0 + type: array + - type: 'null' title: Parents Ids - type: array - items: - exclusiveMinimum: true - type: integer - minimum: 0 url: - title: Url + type: string maxLength: 2083 minLength: 1 - type: string format: uri - CheckpointNew: - title: CheckpointNew - required: - - tag + title: Url type: object + required: + - id + - checksum + - created_at + - tags + - url + title: CheckpointApiModel + CheckpointNew: properties: tag: - title: Tag type: string + title: Tag message: + anyOf: + - type: string + - type: 'null' title: Message - type: string - ClusterAccessRights: - title: ClusterAccessRights - required: - - read - - write - - delete type: object + required: + - tag + title: CheckpointNew + ClusterAccessRights: properties: read: - title: Read type: boolean + title: Read description: allows to run pipelines on that cluster write: - title: Write type: boolean + title: Write description: allows to modify the cluster delete: - title: Delete type: boolean + title: Delete description: allows to delete a cluster additionalProperties: false - ClusterCreate: - title: ClusterCreate - required: - - name - - type - - endpoint - - authentication type: object + required: + - read + - write + - delete + title: ClusterAccessRights + ClusterCreate: properties: name: - title: Name type: string + title: Name description: The human readable name of the cluster description: + anyOf: + - type: string + - type: 'null' title: Description - type: string type: $ref: '#/components/schemas/ClusterTypeInModel' owner: + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' title: Owner - exclusiveMinimum: true - type: integer - minimum: 0 thumbnail: + anyOf: + - type: string + maxLength: 2083 + minLength: 1 + format: uri + - type: 'null' title: Thumbnail - maxLength: 2083 - minLength: 1 - type: string description: url to the image describing this cluster - format: uri endpoint: - title: Endpoint - maxLength: 65536 - minLength: 1 type: string + minLength: 1 format: uri + title: Endpoint authentication: - title: Authentication - anyOf: + oneOf: - $ref: '#/components/schemas/SimpleAuthentication' - $ref: '#/components/schemas/KerberosAuthentication' - $ref: '#/components/schemas/JupyterHubTokenAuthentication' + title: Authentication + discriminator: + propertyName: type + mapping: + jupyterhub: '#/components/schemas/JupyterHubTokenAuthentication' + kerberos: '#/components/schemas/KerberosAuthentication' + simple: '#/components/schemas/SimpleAuthentication' accessRights: - title: Accessrights - type: object additionalProperties: $ref: '#/components/schemas/ClusterAccessRights' - ClusterDetails: - title: ClusterDetails - required: - - scheduler - - dashboardLink + type: object + title: Accessrights type: object + required: + - name + - type + - endpoint + - authentication + title: ClusterCreate + ClusterDetails: properties: scheduler: - title: Scheduler - allOf: - - $ref: '#/components/schemas/Scheduler' + $ref: '#/components/schemas/Scheduler' description: This contains dask scheduler information given by the underlying dask library dashboardLink: - title: Dashboardlink - maxLength: 65536 - minLength: 1 type: string - description: Link to this scheduler's dashboard + minLength: 1 format: uri - ClusterGet: - title: ClusterGet - required: - - name - - type - - owner - - endpoint - - authentication - - id + title: Dashboardlink + description: Link to this scheduler's dashboard type: object + required: + - scheduler + - dashboardLink + title: ClusterDetails + ClusterGet: properties: name: - title: Name type: string + title: Name description: The human readable name of the cluster description: + anyOf: + - type: string + - type: 'null' title: Description - type: string type: $ref: '#/components/schemas/ClusterTypeInModel' owner: - title: Owner - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Owner minimum: 0 thumbnail: + anyOf: + - type: string + maxLength: 2083 + minLength: 1 + format: uri + - type: 'null' title: Thumbnail - maxLength: 2083 - minLength: 1 - type: string description: url to the image describing this cluster - format: uri endpoint: - title: Endpoint - maxLength: 65536 - minLength: 1 type: string + minLength: 1 format: uri + title: Endpoint authentication: - title: Authentication - anyOf: + oneOf: - $ref: '#/components/schemas/SimpleAuthentication' - $ref: '#/components/schemas/KerberosAuthentication' - $ref: '#/components/schemas/JupyterHubTokenAuthentication' - $ref: '#/components/schemas/NoAuthentication' - $ref: '#/components/schemas/TLSAuthentication' + title: Authentication description: Dask gateway authentication + discriminator: + propertyName: type + mapping: + jupyterhub: '#/components/schemas/JupyterHubTokenAuthentication' + kerberos: '#/components/schemas/KerberosAuthentication' + none: '#/components/schemas/NoAuthentication' + simple: '#/components/schemas/SimpleAuthentication' + tls: '#/components/schemas/TLSAuthentication' accessRights: - title: Accessrights - type: object additionalProperties: $ref: '#/components/schemas/ClusterAccessRights' + type: object + title: Accessrights + default: {} id: - title: Id - minimum: 0 type: integer + minimum: 0 + title: Id description: The cluster ID - ClusterPatch: - title: ClusterPatch type: object + required: + - name + - type + - owner + - endpoint + - authentication + - id + title: ClusterGet + ClusterPatch: properties: name: + anyOf: + - type: string + - type: 'null' title: Name - type: string description: + anyOf: + - type: string + - type: 'null' title: Description - type: string type: - $ref: '#/components/schemas/ClusterTypeInModel' + anyOf: + - $ref: '#/components/schemas/ClusterTypeInModel' + - type: 'null' owner: + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' title: Owner - exclusiveMinimum: true - type: integer - minimum: 0 thumbnail: + anyOf: + - type: string + maxLength: 2083 + minLength: 1 + format: uri + - type: 'null' title: Thumbnail - maxLength: 2083 - minLength: 1 - type: string - format: uri endpoint: + anyOf: + - type: string + minLength: 1 + format: uri + - type: 'null' title: Endpoint - maxLength: 65536 - minLength: 1 - type: string - format: uri authentication: - title: Authentication anyOf: - - $ref: '#/components/schemas/SimpleAuthentication' - - $ref: '#/components/schemas/KerberosAuthentication' - - $ref: '#/components/schemas/JupyterHubTokenAuthentication' + - oneOf: + - $ref: '#/components/schemas/SimpleAuthentication' + - $ref: '#/components/schemas/KerberosAuthentication' + - $ref: '#/components/schemas/JupyterHubTokenAuthentication' + discriminator: + propertyName: type + mapping: + jupyterhub: '#/components/schemas/JupyterHubTokenAuthentication' + kerberos: '#/components/schemas/KerberosAuthentication' + simple: '#/components/schemas/SimpleAuthentication' + - type: 'null' + title: Authentication accessRights: + anyOf: + - additionalProperties: + $ref: '#/components/schemas/ClusterAccessRights' + type: object + - type: 'null' title: Accessrights - type: object - additionalProperties: - $ref: '#/components/schemas/ClusterAccessRights' - ClusterPing: - title: ClusterPing - required: - - endpoint - - authentication type: object + title: ClusterPatch + ClusterPing: properties: endpoint: - title: Endpoint - maxLength: 65536 - minLength: 1 type: string + minLength: 1 format: uri + title: Endpoint authentication: - title: Authentication - anyOf: + oneOf: - $ref: '#/components/schemas/SimpleAuthentication' - $ref: '#/components/schemas/KerberosAuthentication' - $ref: '#/components/schemas/JupyterHubTokenAuthentication' - $ref: '#/components/schemas/NoAuthentication' - $ref: '#/components/schemas/TLSAuthentication' + title: Authentication description: Dask gateway authentication + discriminator: + propertyName: type + mapping: + jupyterhub: '#/components/schemas/JupyterHubTokenAuthentication' + kerberos: '#/components/schemas/KerberosAuthentication' + none: '#/components/schemas/NoAuthentication' + simple: '#/components/schemas/SimpleAuthentication' + tls: '#/components/schemas/TLSAuthentication' + type: object + required: + - endpoint + - authentication + title: ClusterPing ClusterTypeInModel: - title: ClusterTypeInModel + type: string enum: - AWS - ON_PREMISE - ON_DEMAND - type: string - description: An enumeration. + title: ClusterTypeInModel CodePageParams: - title: CodePageParams - required: - - message - type: object properties: message: - title: Message type: string + title: Message expiration_2fa: - title: Expiration 2Fa - exclusiveMinimum: true - type: integer - minimum: 0 + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' + title: Expiration 2Fa next_url: + anyOf: + - type: string + - type: 'null' title: Next Url - type: string - Compatibility: - title: Compatibility - required: - - canUpdateTo type: object + required: + - message + title: CodePageParams + Compatibility: properties: canUpdateTo: - title: Canupdateto - allOf: - - $ref: '#/components/schemas/CompatibleService' + $ref: '#/components/schemas/CompatibleService' description: Latest compatible service at this moment - CompatibleService: - title: CompatibleService - required: - - version type: object + required: + - canUpdateTo + title: Compatibility + CompatibleService: properties: key: + anyOf: + - type: string + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + - type: 'null' title: Key - pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ - type: string description: If None, it refer to current service. Used only for inter-service compatibility version: - title: Version - pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ type: string - ComputationStart: - title: ComputationStart + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + title: Version type: object + required: + - version + title: CompatibleService + ComputationStart: properties: force_restart: - title: Force Restart type: boolean + title: Force Restart default: false cluster_id: - title: Cluster Id - minimum: 0 type: integer + minimum: 0 + title: Cluster Id default: 0 subgraph: - title: Subgraph - uniqueItems: true - type: array items: type: string + type: array + uniqueItems: true + title: Subgraph default: [] - ComputationTaskGet: - title: ComputationTaskGet type: object + title: ComputationStart + ComputationTaskGet: properties: cluster_id: + anyOf: + - type: integer + minimum: 0 + - type: 'null' title: Cluster Id - minimum: 0 - type: integer - ConnectServiceToPricingPlanBodyParams: - title: ConnectServiceToPricingPlanBodyParams - required: - - serviceKey - - serviceVersion type: object + required: + - cluster_id + title: ComputationTaskGet + ConnectServiceToPricingPlanBodyParams: properties: serviceKey: - title: Servicekey - pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ type: string + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + title: Servicekey serviceVersion: - title: Serviceversion - pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ type: string - CountryInfoDict: - title: CountryInfoDict - required: - - name - - alpha2 + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + title: Serviceversion type: object + required: + - serviceKey + - serviceVersion + title: ConnectServiceToPricingPlanBodyParams + CountryInfoDict: properties: name: - title: Name type: string + title: Name alpha2: - title: Alpha2 type: string - CreateFolderBodyParams: - title: CreateFolderBodyParams + title: Alpha2 + type: object required: - name - type: object - properties: - name: - title: Name - maxLength: 100 - minLength: 1 - type: string - parentFolderId: - title: Parentfolderid - exclusiveMinimum: true - type: integer - minimum: 0 - workspaceId: - title: Workspaceid - exclusiveMinimum: true - type: integer - minimum: 0 - additionalProperties: false + - alpha2 + title: CountryInfoDict CreatePricingPlanBodyParams: - title: CreatePricingPlanBodyParams - required: - - displayName - - description - - classification - - pricingPlanKey - type: object properties: displayName: - title: Displayname type: string + title: Displayname description: - title: Description type: string + title: Description classification: $ref: '#/components/schemas/PricingPlanClassification' pricingPlanKey: - title: Pricingplankey type: string - CreatePricingUnitBodyParams: - title: CreatePricingUnitBodyParams - required: - - unitName - - unitExtraInfo - - default - - specificInfo - - costPerUnit - - comment + title: Pricingplankey type: object + required: + - displayName + - description + - classification + - pricingPlanKey + title: CreatePricingPlanBodyParams + CreatePricingUnitBodyParams: properties: unitName: - title: Unitname type: string + title: Unitname unitExtraInfo: - $ref: '#/components/schemas/UnitExtraInfo' + $ref: '#/components/schemas/UnitExtraInfo-Input' default: - title: Default type: boolean + title: Default specificInfo: $ref: '#/components/schemas/SpecificInfo' costPerUnit: + anyOf: + - type: number + - type: string title: Costperunit - type: number comment: - title: Comment type: string - CreateWalletBodyParams: - title: CreateWalletBodyParams - required: - - name + title: Comment type: object + required: + - unitName + - unitExtraInfo + - default + - specificInfo + - costPerUnit + - comment + title: CreatePricingUnitBodyParams + CreateWalletBodyParams: properties: name: - title: Name type: string + title: Name description: + anyOf: + - type: string + - type: 'null' title: Description - type: string thumbnail: + anyOf: + - type: string + - type: 'null' title: Thumbnail - type: string - CreateWalletPayment: - title: CreateWalletPayment - required: - - priceDollars type: object + required: + - name + title: CreateWalletBodyParams + CreateWalletPayment: properties: priceDollars: + anyOf: + - type: number + exclusiveMaximum: true + exclusiveMinimum: true + maximum: 1000000.0 + minimum: 0.0 + - type: string title: Pricedollars - exclusiveMaximum: true - exclusiveMinimum: true - type: number - maximum: 1000000.0 - minimum: 0.0 comment: + anyOf: + - type: string + maxLength: 100 + - type: 'null' title: Comment - maxLength: 100 - type: string - CreateWorkspaceBodyParams: - title: CreateWorkspaceBodyParams - required: - - name type: object - properties: - name: - title: Name - type: string - description: - title: Description - type: string - thumbnail: - title: Thumbnail - type: string - additionalProperties: false - DatCoreFileLink: - title: DatCoreFileLink required: - - store - - path - - label - - dataset - type: object + - priceDollars + title: CreateWalletPayment + DatCoreFileLink: properties: store: - title: Store type: integer + title: Store description: 'The store identifier: 0 for simcore S3, 1 for datcore' path: - title: Path anyOf: - - pattern: ^(api|([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}))\/([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12})\/(.+)$ - type: string - - pattern: ^N:package:[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}$ - type: string + - type: string + pattern: ^(api|([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}))\/([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12})\/(.+)$ + - type: string + pattern: ^N:package:[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}$ + title: Path description: The path to the file in the storage provider domain label: - title: Label type: string + title: Label description: The real file name eTag: + anyOf: + - type: string + - type: 'null' title: Etag - type: string description: Entity tag that uniquely represents the file. The method to generate the tag is not specified (black box). dataset: - title: Dataset type: string + title: Dataset description: Unique identifier to access the dataset on datcore (REQUIRED for datcore) additionalProperties: false + type: object + required: + - store + - path + - label + - dataset + title: DatCoreFileLink description: I/O port type to hold a link to a file in DATCORE storage DatasetMetaData: - title: DatasetMetaData - type: object properties: dataset_id: + anyOf: + - type: string + - type: 'null' title: Dataset Id - type: string display_name: + anyOf: + - type: string + - type: 'null' title: Display Name - type: string + type: object + title: DatasetMetaData example: dataset_id: N:id-aaaa display_name: simcore-testing - DictModel_str__PositiveFloat_: - title: DictModel[str, PositiveFloat] - type: object + DictModel_str_Annotated_float__Gt__: additionalProperties: - exclusiveMinimum: true type: number + exclusiveMinimum: true minimum: 0.0 - DownloadLink: - title: DownloadLink - required: - - downloadLink type: object + title: DictModel[str, Annotated[float, Gt]] + DownloadLink: properties: downloadLink: - title: Downloadlink - maxLength: 65536 - minLength: 1 type: string - format: uri + title: Downloadlink label: + anyOf: + - type: string + - type: 'null' title: Label - type: string description: Display name additionalProperties: false + type: object + required: + - downloadLink + title: DownloadLink description: I/O port type to hold a generic download link to a file (e.g. S3 pre-signed link, etc) EmailTestFailed: - title: EmailTestFailed - required: - - test_name - - error_type - - error_message - - traceback - type: object properties: test_name: - title: Test Name type: string + title: Test Name error_type: - title: Error Type type: string + title: Error Type error_message: - title: Error Message type: string + title: Error Message traceback: - title: Traceback type: string - EmailTestPassed: - title: EmailTestPassed - required: - - fixtures - - info + title: Traceback type: object + required: + - test_name + - error_type + - error_message + - traceback + title: EmailTestFailed + EmailTestPassed: properties: fixtures: - title: Fixtures type: object + title: Fixtures info: - title: Info type: object - EmptyModel: - title: EmptyModel + title: Info type: object + required: + - fixtures + - info + title: EmailTestPassed + EmptyModel: properties: {} additionalProperties: false - Envelope_AnyUrl_: - title: Envelope[AnyUrl] type: object + title: EmptyModel + Envelope_AppStatusCheck_: properties: data: - title: Data - maxLength: 65536 - minLength: 1 - type: string - format: uri + anyOf: + - $ref: '#/components/schemas/AppStatusCheck' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_AppStatusCheck_: - title: Envelope[AppStatusCheck] type: object + title: Envelope[AppStatusCheck] + Envelope_CatalogServiceGet_: properties: data: - $ref: '#/components/schemas/AppStatusCheck' + anyOf: + - $ref: '#/components/schemas/CatalogServiceGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_CatalogServiceGet_: - title: Envelope[CatalogServiceGet] type: object + title: Envelope[CatalogServiceGet] + Envelope_CheckpointApiModel_: properties: data: - $ref: '#/components/schemas/CatalogServiceGet' + anyOf: + - $ref: '#/components/schemas/CheckpointApiModel' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_CheckpointApiModel_: - title: Envelope[CheckpointApiModel] type: object + title: Envelope[CheckpointApiModel] + Envelope_ClusterDetails_: properties: data: - $ref: '#/components/schemas/CheckpointApiModel' + anyOf: + - $ref: '#/components/schemas/ClusterDetails' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_ClusterDetails_: - title: Envelope[ClusterDetails] type: object + title: Envelope[ClusterDetails] + Envelope_ClusterGet_: properties: data: - $ref: '#/components/schemas/ClusterDetails' + anyOf: + - $ref: '#/components/schemas/ClusterGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_ClusterGet_: - title: Envelope[ClusterGet] type: object + title: Envelope[ClusterGet] + Envelope_ComputationTaskGet_: properties: data: - $ref: '#/components/schemas/ClusterGet' + anyOf: + - $ref: '#/components/schemas/ComputationTaskGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_ComputationTaskGet_: - title: Envelope[ComputationTaskGet] type: object + title: Envelope[ComputationTaskGet] + Envelope_Error_: properties: data: - $ref: '#/components/schemas/ComputationTaskGet' + anyOf: + - $ref: '#/components/schemas/Error' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_Error_: - title: Envelope[Error] type: object + title: Envelope[Error] + Envelope_FileMetaDataGet_: properties: data: - $ref: '#/components/schemas/Error' + anyOf: + - $ref: '#/components/schemas/FileMetaDataGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_FileMetaDataGet_: - title: Envelope[FileMetaDataGet] type: object + title: Envelope[FileMetaDataGet] + Envelope_FileUploadCompleteFutureResponse_: properties: data: - $ref: '#/components/schemas/FileMetaDataGet' + anyOf: + - $ref: '#/components/schemas/FileUploadCompleteFutureResponse' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_FileUploadCompleteFutureResponse_: - title: Envelope[FileUploadCompleteFutureResponse] type: object + title: Envelope[FileUploadCompleteFutureResponse] + Envelope_FileUploadCompleteResponse_: properties: data: - $ref: '#/components/schemas/FileUploadCompleteFutureResponse' + anyOf: + - $ref: '#/components/schemas/FileUploadCompleteResponse' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_FileUploadCompleteResponse_: - title: Envelope[FileUploadCompleteResponse] type: object + title: Envelope[FileUploadCompleteResponse] + Envelope_FileUploadCompletionBody_: properties: data: - $ref: '#/components/schemas/FileUploadCompleteResponse' + anyOf: + - $ref: '#/components/schemas/FileUploadCompletionBody' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_FileUploadCompletionBody_: - title: Envelope[FileUploadCompletionBody] type: object + title: Envelope[FileUploadCompletionBody] + Envelope_FileUploadSchema_: properties: data: - $ref: '#/components/schemas/FileUploadCompletionBody' + anyOf: + - $ref: '#/components/schemas/FileUploadSchema' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_FileUploadSchema_: - title: Envelope[FileUploadSchema] type: object + title: Envelope[FileUploadSchema] + Envelope_FolderGet_: properties: data: - $ref: '#/components/schemas/FileUploadSchema' + anyOf: + - $ref: '#/components/schemas/FolderGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_FolderGet_: - title: Envelope[FolderGet] type: object + title: Envelope[FolderGet] + Envelope_GetCreditPrice_: properties: data: - $ref: '#/components/schemas/FolderGet' + anyOf: + - $ref: '#/components/schemas/GetCreditPrice' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_GetCreditPrice_: - title: Envelope[GetCreditPrice] type: object + title: Envelope[GetCreditPrice] + Envelope_GetProduct_: properties: data: - $ref: '#/components/schemas/GetCreditPrice' + anyOf: + - $ref: '#/components/schemas/GetProduct' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_GetProduct_: - title: Envelope[GetProduct] type: object + title: Envelope[GetProduct] + Envelope_GetProjectInactivityResponse_: properties: data: - $ref: '#/components/schemas/GetProduct' + anyOf: + - $ref: '#/components/schemas/GetProjectInactivityResponse' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_GetProjectInactivityResponse_: - title: Envelope[GetProjectInactivityResponse] type: object + title: Envelope[GetProjectInactivityResponse] + Envelope_GetWalletAutoRecharge_: properties: data: - $ref: '#/components/schemas/GetProjectInactivityResponse' + anyOf: + - $ref: '#/components/schemas/GetWalletAutoRecharge' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_GetWalletAutoRecharge_: - title: Envelope[GetWalletAutoRecharge] type: object + title: Envelope[GetWalletAutoRecharge] + Envelope_GroupGet_: properties: data: - $ref: '#/components/schemas/GetWalletAutoRecharge' + anyOf: + - $ref: '#/components/schemas/GroupGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_GroupGet_: - title: Envelope[GroupGet] type: object + title: Envelope[GroupGet] + Envelope_GroupUserGet_: properties: data: - $ref: '#/components/schemas/GroupGet' + anyOf: + - $ref: '#/components/schemas/GroupUserGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_GroupUserGet_: - title: Envelope[GroupUserGet] type: object + title: Envelope[GroupUserGet] + Envelope_HealthInfoDict_: properties: data: - $ref: '#/components/schemas/GroupUserGet' + anyOf: + - $ref: '#/components/schemas/HealthInfoDict' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_HealthInfoDict_: - title: Envelope[HealthInfoDict] type: object + title: Envelope[HealthInfoDict] + Envelope_InvitationGenerated_: properties: data: - $ref: '#/components/schemas/HealthInfoDict' + anyOf: + - $ref: '#/components/schemas/InvitationGenerated' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_InvitationGenerated_: - title: Envelope[InvitationGenerated] type: object + title: Envelope[InvitationGenerated] + Envelope_InvitationInfo_: properties: data: - $ref: '#/components/schemas/InvitationGenerated' + anyOf: + - $ref: '#/components/schemas/InvitationInfo' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_InvitationInfo_: - title: Envelope[InvitationInfo] type: object + title: Envelope[InvitationInfo] + Envelope_Log_: properties: data: - $ref: '#/components/schemas/InvitationInfo' + anyOf: + - $ref: '#/components/schemas/Log' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_Log_: - title: Envelope[Log] type: object + title: Envelope[Log] + Envelope_LoginNextPage_: properties: data: - $ref: '#/components/schemas/Log' + anyOf: + - $ref: '#/components/schemas/LoginNextPage' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_LoginNextPage_: - title: Envelope[LoginNextPage] type: object + title: Envelope[LoginNextPage] + Envelope_MyGroupsGet_: properties: data: - $ref: '#/components/schemas/LoginNextPage' + anyOf: + - $ref: '#/components/schemas/MyGroupsGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_MyGroupsGet_: - title: Envelope[MyGroupsGet] type: object + title: Envelope[MyGroupsGet] + Envelope_NodeCreated_: properties: data: - $ref: '#/components/schemas/MyGroupsGet' + anyOf: + - $ref: '#/components/schemas/NodeCreated' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_NodeCreated_: - title: Envelope[NodeCreated] type: object + title: Envelope[NodeCreated] + Envelope_NodeRetrieved_: properties: data: - $ref: '#/components/schemas/NodeCreated' + anyOf: + - $ref: '#/components/schemas/NodeRetrieved' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_NodeRetrieved_: - title: Envelope[NodeRetrieved] type: object + title: Envelope[NodeRetrieved] + Envelope_PaymentMethodGet_: properties: data: - $ref: '#/components/schemas/NodeRetrieved' + anyOf: + - $ref: '#/components/schemas/PaymentMethodGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_PaymentMethodGet_: - title: Envelope[PaymentMethodGet] type: object + title: Envelope[PaymentMethodGet] + Envelope_PaymentMethodInitiated_: properties: data: - $ref: '#/components/schemas/PaymentMethodGet' + anyOf: + - $ref: '#/components/schemas/PaymentMethodInitiated' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_PaymentMethodInitiated_: - title: Envelope[PaymentMethodInitiated] type: object + title: Envelope[PaymentMethodInitiated] + Envelope_PresignedLink_: properties: data: - $ref: '#/components/schemas/PaymentMethodInitiated' + anyOf: + - $ref: '#/components/schemas/PresignedLink' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_PresignedLink_: - title: Envelope[PresignedLink] type: object + title: Envelope[PresignedLink] + Envelope_PricingPlanAdminGet_: properties: data: - $ref: '#/components/schemas/PresignedLink' + anyOf: + - $ref: '#/components/schemas/PricingPlanAdminGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_PricingPlanAdminGet_: - title: Envelope[PricingPlanAdminGet] type: object + title: Envelope[PricingPlanAdminGet] + Envelope_PricingPlanToServiceAdminGet_: properties: data: - $ref: '#/components/schemas/PricingPlanAdminGet' + anyOf: + - $ref: '#/components/schemas/PricingPlanToServiceAdminGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_PricingPlanToServiceAdminGet_: - title: Envelope[PricingPlanToServiceAdminGet] type: object + title: Envelope[PricingPlanToServiceAdminGet] + Envelope_PricingUnitAdminGet_: properties: data: - $ref: '#/components/schemas/PricingPlanToServiceAdminGet' + anyOf: + - $ref: '#/components/schemas/PricingUnitAdminGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_PricingUnitAdminGet_: - title: Envelope[PricingUnitAdminGet] type: object + title: Envelope[PricingUnitAdminGet] + Envelope_PricingUnitGet_: properties: data: - $ref: '#/components/schemas/PricingUnitAdminGet' + anyOf: + - $ref: '#/components/schemas/PricingUnitGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_PricingUnitGet_: - title: Envelope[PricingUnitGet] type: object - properties: - data: - $ref: '#/components/schemas/PricingUnitGet' - error: - title: Error + title: Envelope[PricingUnitGet] Envelope_ProfileGet_: - title: Envelope[ProfileGet] - type: object properties: data: - $ref: '#/components/schemas/ProfileGet' + anyOf: + - $ref: '#/components/schemas/ProfileGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_ProjectGet_: - title: Envelope[ProjectGet] type: object + title: Envelope[ProfileGet] + Envelope_ProjectGet_: properties: data: - $ref: '#/components/schemas/ProjectGet' + anyOf: + - $ref: '#/components/schemas/ProjectGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_ProjectGroupGet_: - title: Envelope[ProjectGroupGet] type: object + title: Envelope[ProjectGet] + Envelope_ProjectGroupGet_: properties: data: - $ref: '#/components/schemas/ProjectGroupGet' + anyOf: + - $ref: '#/components/schemas/ProjectGroupGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_ProjectMetadataGet_: - title: Envelope[ProjectMetadataGet] type: object + title: Envelope[ProjectGroupGet] + Envelope_ProjectMetadataGet_: properties: data: - $ref: '#/components/schemas/ProjectMetadataGet' + anyOf: + - $ref: '#/components/schemas/ProjectMetadataGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_ProjectState_: - title: Envelope[ProjectState] type: object + title: Envelope[ProjectMetadataGet] + Envelope_ProjectState_: properties: data: - $ref: '#/components/schemas/ProjectState' + anyOf: + - $ref: '#/components/schemas/ProjectState' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_ProjectsCommentsAPI_: - title: Envelope[ProjectsCommentsAPI] type: object + title: Envelope[ProjectState] + Envelope_ProjectsCommentsAPI_: properties: data: - $ref: '#/components/schemas/ProjectsCommentsAPI' + anyOf: + - $ref: '#/components/schemas/ProjectsCommentsAPI' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_RegisterPhoneNextPage_: - title: Envelope[RegisterPhoneNextPage] type: object + title: Envelope[ProjectsCommentsAPI] + Envelope_RegisterPhoneNextPage_: properties: data: - $ref: '#/components/schemas/RegisterPhoneNextPage' + anyOf: + - $ref: '#/components/schemas/RegisterPhoneNextPage' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_ResearchResource_: - title: Envelope[ResearchResource] type: object + title: Envelope[RegisterPhoneNextPage] + Envelope_ResearchResource_: properties: data: - $ref: '#/components/schemas/ResearchResource' + anyOf: + - $ref: '#/components/schemas/ResearchResource' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_ServiceInputGet_: - title: Envelope[ServiceInputGet] type: object + title: Envelope[ResearchResource] + Envelope_ServiceInputGet_: properties: data: - $ref: '#/components/schemas/ServiceInputGet' + anyOf: + - $ref: '#/components/schemas/ServiceInputGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_ServicePricingPlanGet_: - title: Envelope[ServicePricingPlanGet] type: object + title: Envelope[ServiceInputGet] + Envelope_ServicePricingPlanGet_: properties: data: - $ref: '#/components/schemas/ServicePricingPlanGet' + anyOf: + - $ref: '#/components/schemas/ServicePricingPlanGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_StatusDiagnosticsGet_: - title: Envelope[StatusDiagnosticsGet] type: object + title: Envelope[ServicePricingPlanGet] + Envelope_StatusDiagnosticsGet_: properties: data: - $ref: '#/components/schemas/StatusDiagnosticsGet' + anyOf: + - $ref: '#/components/schemas/StatusDiagnosticsGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_TableSynchronisation_: - title: Envelope[TableSynchronisation] type: object + title: Envelope[StatusDiagnosticsGet] + Envelope_TableSynchronisation_: properties: data: - $ref: '#/components/schemas/TableSynchronisation' + anyOf: + - $ref: '#/components/schemas/TableSynchronisation' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_TagGet_: - title: Envelope[TagGet] type: object + title: Envelope[TableSynchronisation] + Envelope_TagGet_: properties: data: - $ref: '#/components/schemas/TagGet' + anyOf: + - $ref: '#/components/schemas/TagGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_TaskGet_: - title: Envelope[TaskGet] type: object + title: Envelope[TagGet] + Envelope_TaskGet_: properties: data: - $ref: '#/components/schemas/TaskGet' + anyOf: + - $ref: '#/components/schemas/TaskGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_TaskStatus_: - title: Envelope[TaskStatus] type: object + title: Envelope[TaskGet] + Envelope_TaskStatus_: properties: data: - $ref: '#/components/schemas/TaskStatus' + anyOf: + - $ref: '#/components/schemas/TaskStatus' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_ThirdPartyToken_: - title: Envelope[ThirdPartyToken] type: object + title: Envelope[TaskStatus] + Envelope_ThirdPartyToken_: properties: data: - $ref: '#/components/schemas/ThirdPartyToken' + anyOf: + - $ref: '#/components/schemas/ThirdPartyToken' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_Union_EmailTestFailed__EmailTestPassed__: - title: Envelope[Union[EmailTestFailed, EmailTestPassed]] type: object + title: Envelope[ThirdPartyToken] + Envelope_Union_EmailTestFailed__EmailTestPassed__: properties: data: - title: Data anyOf: - $ref: '#/components/schemas/EmailTestFailed' - $ref: '#/components/schemas/EmailTestPassed' + - type: 'null' + title: Data error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_Union_NodeGetIdle__NodeGetUnknown__RunningDynamicServiceDetails__NodeGet__: - title: Envelope[Union[NodeGetIdle, NodeGetUnknown, RunningDynamicServiceDetails, - NodeGet]] type: object + title: Envelope[Union[EmailTestFailed, EmailTestPassed]] + Envelope_Union_NodeGetIdle__NodeGetUnknown__RunningDynamicServiceDetails__NodeGet__: properties: data: - title: Data anyOf: - $ref: '#/components/schemas/NodeGetIdle' - $ref: '#/components/schemas/NodeGetUnknown' - $ref: '#/components/schemas/RunningDynamicServiceDetails' - $ref: '#/components/schemas/NodeGet' + - type: 'null' + title: Data error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_Union_PricingUnitGet__NoneType__: - title: Envelope[Union[PricingUnitGet, NoneType]] type: object + title: Envelope[Union[NodeGetIdle, NodeGetUnknown, RunningDynamicServiceDetails, + NodeGet]] + Envelope_Union_PricingUnitGet__NoneType__: properties: data: - $ref: '#/components/schemas/PricingUnitGet' + anyOf: + - $ref: '#/components/schemas/PricingUnitGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_Union_WalletGet__NoneType__: - title: Envelope[Union[WalletGet, NoneType]] type: object + title: Envelope[Union[PricingUnitGet, NoneType]] + Envelope_Union_WalletGet__NoneType__: properties: data: - $ref: '#/components/schemas/WalletGet' + anyOf: + - $ref: '#/components/schemas/WalletGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_UserProfile_: - title: Envelope[UserProfile] type: object + title: Envelope[Union[WalletGet, NoneType]] + Envelope_Url_: properties: data: - $ref: '#/components/schemas/UserProfile' + anyOf: + - type: string + minLength: 1 + format: uri + - type: 'null' + title: Data error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_WalletGetWithAvailableCredits_: - title: Envelope[WalletGetWithAvailableCredits] type: object + title: Envelope[Url] + Envelope_UserProfile_: properties: data: - $ref: '#/components/schemas/WalletGetWithAvailableCredits' + anyOf: + - $ref: '#/components/schemas/UserProfile' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_WalletGet_: - title: Envelope[WalletGet] type: object + title: Envelope[UserProfile] + Envelope_WalletGetWithAvailableCredits_: properties: data: - $ref: '#/components/schemas/WalletGet' + anyOf: + - $ref: '#/components/schemas/WalletGetWithAvailableCredits' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_WalletGroupGet_: - title: Envelope[WalletGroupGet] type: object + title: Envelope[WalletGetWithAvailableCredits] + Envelope_WalletGet_: properties: data: - $ref: '#/components/schemas/WalletGroupGet' + anyOf: + - $ref: '#/components/schemas/WalletGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_WalletPaymentInitiated_: - title: Envelope[WalletPaymentInitiated] type: object + title: Envelope[WalletGet] + Envelope_WalletGroupGet_: properties: data: - $ref: '#/components/schemas/WalletPaymentInitiated' + anyOf: + - $ref: '#/components/schemas/WalletGroupGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_WorkbenchViewApiModel_: - title: Envelope[WorkbenchViewApiModel] type: object + title: Envelope[WalletGroupGet] + Envelope_WalletPaymentInitiated_: properties: data: - $ref: '#/components/schemas/WorkbenchViewApiModel' + anyOf: + - $ref: '#/components/schemas/WalletPaymentInitiated' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_WorkspaceGet_: - title: Envelope[WorkspaceGet] type: object + title: Envelope[WalletPaymentInitiated] + Envelope_WorkbenchViewApiModel_: properties: data: - $ref: '#/components/schemas/WorkspaceGet' + anyOf: + - $ref: '#/components/schemas/WorkbenchViewApiModel' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_WorkspaceGroupGet_: - title: Envelope[WorkspaceGroupGet] type: object + title: Envelope[WorkbenchViewApiModel] + Envelope_WorkspaceGet_: properties: data: - $ref: '#/components/schemas/WorkspaceGroupGet' + anyOf: + - $ref: '#/components/schemas/WorkspaceGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope__ComputationStarted_: - title: Envelope[_ComputationStarted] type: object + title: Envelope[WorkspaceGet] + Envelope_WorkspaceGroupGet_: properties: data: - $ref: '#/components/schemas/_ComputationStarted' + anyOf: + - $ref: '#/components/schemas/WorkspaceGroupGet' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope__ProjectGroupAccess_: - title: Envelope[_ProjectGroupAccess] type: object + title: Envelope[WorkspaceGroupGet] + Envelope__ComputationStarted_: properties: data: - $ref: '#/components/schemas/_ProjectGroupAccess' + anyOf: + - $ref: '#/components/schemas/_ComputationStarted' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope__ProjectNodePreview_: - title: Envelope[_ProjectNodePreview] type: object + title: Envelope[_ComputationStarted] + Envelope__ProjectGroupAccess_: properties: data: - $ref: '#/components/schemas/_ProjectNodePreview' + anyOf: + - $ref: '#/components/schemas/_ProjectGroupAccess' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_dict_Literal__comment_id____pydantic.types.PositiveInt__: - title: Envelope[dict[Literal['comment_id'], pydantic.types.PositiveInt]] type: object + title: Envelope[_ProjectGroupAccess] + Envelope__ProjectNodePreview_: properties: data: - title: Data - type: object - additionalProperties: - exclusiveMinimum: true - type: integer - minimum: 0 + anyOf: + - $ref: '#/components/schemas/_ProjectNodePreview' + - type: 'null' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_dict_models_library.docker.DockerGenericTag__models_library.services_resources.ImageResources__: - title: Envelope[dict[models_library.docker.DockerGenericTag, models_library.services_resources.ImageResources]] type: object + title: Envelope[_ProjectNodePreview] + Envelope_dict_Annotated_str__StringConstraints___ImageResources__: properties: data: + anyOf: + - type: object + - type: 'null' title: Data - type: object - additionalProperties: - $ref: '#/components/schemas/ImageResources' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_dict_str__Any__: - title: Envelope[dict[str, Any]] type: object + title: Envelope[dict[Annotated[str, StringConstraints], ImageResources]] + Envelope_dict_Literal__comment_id____Annotated_int__Gt___: properties: data: + anyOf: + - additionalProperties: + type: integer + exclusiveMinimum: true + minimum: 0 + type: object + - type: 'null' title: Data - type: object error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_dict_uuid.UUID__models_library.api_schemas_webserver.activity.Activity__: - title: Envelope[dict[uuid.UUID, models_library.api_schemas_webserver.activity.Activity]] type: object + title: Envelope[dict[Literal['comment_id'], Annotated[int, Gt]]] + Envelope_dict_UUID__Activity__: properties: data: + anyOf: + - additionalProperties: + $ref: '#/components/schemas/Activity' + type: object + - type: 'null' title: Data - type: object - additionalProperties: - $ref: '#/components/schemas/Activity' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_dict_uuid.UUID__models_library.api_schemas_webserver.projects_ports.ProjectInputGet__: - title: Envelope[dict[uuid.UUID, models_library.api_schemas_webserver.projects_ports.ProjectInputGet]] type: object + title: Envelope[dict[UUID, Activity]] + Envelope_dict_UUID__ProjectInputGet__: properties: data: + anyOf: + - additionalProperties: + $ref: '#/components/schemas/ProjectInputGet' + type: object + - type: 'null' title: Data - type: object - additionalProperties: - $ref: '#/components/schemas/ProjectInputGet' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_dict_uuid.UUID__models_library.api_schemas_webserver.projects_ports.ProjectOutputGet__: - title: Envelope[dict[uuid.UUID, models_library.api_schemas_webserver.projects_ports.ProjectOutputGet]] type: object + title: Envelope[dict[UUID, ProjectInputGet]] + Envelope_dict_UUID__ProjectOutputGet__: properties: data: + anyOf: + - additionalProperties: + $ref: '#/components/schemas/ProjectOutputGet' + type: object + - type: 'null' title: Data - type: object - additionalProperties: - $ref: '#/components/schemas/ProjectOutputGet' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_models_library.api_schemas_long_running_tasks.tasks.TaskGet__: - title: Envelope[list[models_library.api_schemas_long_running_tasks.tasks.TaskGet]] type: object + title: Envelope[dict[UUID, ProjectOutputGet]] + Envelope_dict_str__Any__: properties: data: + anyOf: + - type: object + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/TaskGet' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_models_library.api_schemas_resource_usage_tracker.service_runs.OsparcCreditsAggregatedByServiceGet__: - title: Envelope[list[models_library.api_schemas_resource_usage_tracker.service_runs.OsparcCreditsAggregatedByServiceGet]] type: object + title: Envelope[dict[str, Any]] + Envelope_list_Annotated_str__StringConstraints___: properties: data: + anyOf: + - items: + type: string + pattern: ^[-_a-zA-Z0-9]+$ + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/OsparcCreditsAggregatedByServiceGet' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_models_library.api_schemas_storage.FileMetaDataGet__: - title: Envelope[list[models_library.api_schemas_storage.FileMetaDataGet]] type: object + title: Envelope[list[Annotated[str, StringConstraints]]] + Envelope_list_Announcement__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/Announcement' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/FileMetaDataGet' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_models_library.api_schemas_webserver.catalog.ServiceInputGet__: - title: Envelope[list[models_library.api_schemas_webserver.catalog.ServiceInputGet]] type: object + title: Envelope[list[Announcement]] + Envelope_list_ClusterGet__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/ClusterGet' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/ServiceInputGet' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_models_library.api_schemas_webserver.catalog.ServiceOutputGet__: - title: Envelope[list[models_library.api_schemas_webserver.catalog.ServiceOutputGet]] type: object + title: Envelope[list[ClusterGet]] + Envelope_list_DatasetMetaData__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/DatasetMetaData' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/ServiceOutputGet' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_models_library.api_schemas_webserver.clusters.ClusterGet__: - title: Envelope[list[models_library.api_schemas_webserver.clusters.ClusterGet]] type: object + title: Envelope[list[DatasetMetaData]] + Envelope_list_FileMetaDataGet__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/FileMetaDataGet' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/ClusterGet' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_models_library.api_schemas_webserver.folders_v2.FolderGet__: - title: Envelope[list[models_library.api_schemas_webserver.folders_v2.FolderGet]] type: object + title: Envelope[list[FileMetaDataGet]] + Envelope_list_FolderGet__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/FolderGet' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/FolderGet' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_models_library.api_schemas_webserver.groups.GroupUserGet__: - title: Envelope[list[models_library.api_schemas_webserver.groups.GroupUserGet]] type: object + title: Envelope[list[FolderGet]] + Envelope_list_GroupUserGet__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/GroupUserGet' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/GroupUserGet' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_models_library.api_schemas_webserver.resource_usage.PricingPlanAdminGet__: - title: Envelope[list[models_library.api_schemas_webserver.resource_usage.PricingPlanAdminGet]] type: object + title: Envelope[list[GroupUserGet]] + Envelope_list_OsparcCreditsAggregatedByServiceGet__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/OsparcCreditsAggregatedByServiceGet' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/PricingPlanAdminGet' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_models_library.api_schemas_webserver.resource_usage.PricingPlanToServiceAdminGet__: - title: Envelope[list[models_library.api_schemas_webserver.resource_usage.PricingPlanToServiceAdminGet]] type: object + title: Envelope[list[OsparcCreditsAggregatedByServiceGet]] + Envelope_list_PaymentMethodGet__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/PaymentMethodGet' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/PricingPlanToServiceAdminGet' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_models_library.api_schemas_webserver.resource_usage.ServiceRunGet__: - title: Envelope[list[models_library.api_schemas_webserver.resource_usage.ServiceRunGet]] type: object + title: Envelope[list[PaymentMethodGet]] + Envelope_list_PermissionGet__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/PermissionGet' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/ServiceRunGet' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_models_library.api_schemas_webserver.wallets.PaymentMethodGet__: - title: Envelope[list[models_library.api_schemas_webserver.wallets.PaymentMethodGet]] type: object + title: Envelope[list[PermissionGet]] + Envelope_list_PricingPlanAdminGet__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/PricingPlanAdminGet' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/PaymentMethodGet' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_models_library.api_schemas_webserver.wallets.WalletGetWithAvailableCredits__: - title: Envelope[list[models_library.api_schemas_webserver.wallets.WalletGetWithAvailableCredits]] type: object + title: Envelope[list[PricingPlanAdminGet]] + Envelope_list_PricingPlanToServiceAdminGet__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/PricingPlanToServiceAdminGet' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/WalletGetWithAvailableCredits' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_models_library.api_schemas_webserver.workspaces.WorkspaceGet__: - title: Envelope[list[models_library.api_schemas_webserver.workspaces.WorkspaceGet]] type: object + title: Envelope[list[PricingPlanToServiceAdminGet]] + Envelope_list_ProjectGroupGet__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/ProjectGroupGet' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/WorkspaceGet' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_models_library.projects_comments.ProjectsCommentsAPI__: - title: Envelope[list[models_library.projects_comments.ProjectsCommentsAPI]] type: object + title: Envelope[list[ProjectGroupGet]] + Envelope_list_ProjectMetadataPortGet__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/ProjectMetadataPortGet' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/ProjectsCommentsAPI' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_models_library.services_types.ServicePortKey__: - title: Envelope[list[models_library.services_types.ServicePortKey]] type: object + title: Envelope[list[ProjectMetadataPortGet]] + Envelope_list_ProjectsCommentsAPI__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/ProjectsCommentsAPI' + type: array + - type: 'null' title: Data - type: array - items: - pattern: ^[-_a-zA-Z0-9]+$ - type: string error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_simcore_service_webserver.announcements._models.Announcement__: - title: Envelope[list[simcore_service_webserver.announcements._models.Announcement]] type: object + title: Envelope[list[ProjectsCommentsAPI]] + Envelope_list_ResourceHit__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/ResourceHit' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/Announcement' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_simcore_service_webserver.projects._groups_api.ProjectGroupGet__: - title: Envelope[list[simcore_service_webserver.projects._groups_api.ProjectGroupGet]] type: object + title: Envelope[list[ResourceHit]] + Envelope_list_ServiceGet__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/ServiceGet' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/ProjectGroupGet' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_simcore_service_webserver.projects._nodes_handlers._ProjectNodePreview__: - title: Envelope[list[simcore_service_webserver.projects._nodes_handlers._ProjectNodePreview]] type: object + title: Envelope[list[ServiceGet]] + Envelope_list_ServiceInputGet__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/ServiceInputGet' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/_ProjectNodePreview' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_simcore_service_webserver.projects._ports_handlers.ProjectMetadataPortGet__: - title: Envelope[list[simcore_service_webserver.projects._ports_handlers.ProjectMetadataPortGet]] type: object + title: Envelope[list[ServiceInputGet]] + Envelope_list_ServiceOutputGet__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/ServiceOutputGet' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/ProjectMetadataPortGet' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_simcore_service_webserver.scicrunch.models.ResourceHit__: - title: Envelope[list[simcore_service_webserver.scicrunch.models.ResourceHit]] type: object + title: Envelope[list[ServiceOutputGet]] + Envelope_list_ServiceRunGet__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/ServiceRunGet' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/ResourceHit' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_simcore_service_webserver.storage.schemas.DatasetMetaData__: - title: Envelope[list[simcore_service_webserver.storage.schemas.DatasetMetaData]] type: object + title: Envelope[list[ServiceRunGet]] + Envelope_list_TagGet__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/TagGet' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/DatasetMetaData' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_simcore_service_webserver.studies_dispatcher._rest_handlers.ServiceGet__: - title: Envelope[list[simcore_service_webserver.studies_dispatcher._rest_handlers.ServiceGet]] type: object + title: Envelope[list[TagGet]] + Envelope_list_TagGroupGet__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/TagGroupGet' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/ServiceGet' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_simcore_service_webserver.studies_dispatcher._rest_handlers.Viewer__: - title: Envelope[list[simcore_service_webserver.studies_dispatcher._rest_handlers.Viewer]] type: object + title: Envelope[list[TagGroupGet]] + Envelope_list_TaskGet__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/TaskGet' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/Viewer' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_simcore_service_webserver.tags.schemas.TagGet__: - title: Envelope[list[simcore_service_webserver.tags.schemas.TagGet]] type: object + title: Envelope[list[TaskGet]] + Envelope_list_ThirdPartyToken__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/ThirdPartyToken' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/TagGet' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_simcore_service_webserver.tags.schemas.TagGroupGet__: - title: Envelope[list[simcore_service_webserver.tags.schemas.TagGroupGet]] type: object + title: Envelope[list[ThirdPartyToken]] + Envelope_list_UserNotification__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/UserNotification' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/TagGroupGet' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_simcore_service_webserver.users._notifications.UserNotification__: - title: Envelope[list[simcore_service_webserver.users._notifications.UserNotification]] type: object + title: Envelope[list[UserNotification]] + Envelope_list_UserProfile__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/UserProfile' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/UserNotification' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_simcore_service_webserver.users._schemas.UserProfile__: - title: Envelope[list[simcore_service_webserver.users._schemas.UserProfile]] type: object + title: Envelope[list[UserProfile]] + Envelope_list_Viewer__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/Viewer' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/UserProfile' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_simcore_service_webserver.users.schemas.PermissionGet__: - title: Envelope[list[simcore_service_webserver.users.schemas.PermissionGet]] type: object + title: Envelope[list[Viewer]] + Envelope_list_WalletGetWithAvailableCredits__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/WalletGetWithAvailableCredits' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/PermissionGet' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_simcore_service_webserver.users.schemas.ThirdPartyToken__: - title: Envelope[list[simcore_service_webserver.users.schemas.ThirdPartyToken]] type: object + title: Envelope[list[WalletGetWithAvailableCredits]] + Envelope_list_WalletGroupGet__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/WalletGroupGet' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/ThirdPartyToken' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_simcore_service_webserver.wallets._groups_api.WalletGroupGet__: - title: Envelope[list[simcore_service_webserver.wallets._groups_api.WalletGroupGet]] type: object + title: Envelope[list[WalletGroupGet]] + Envelope_list_WorkspaceGet__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/WorkspaceGet' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/WalletGroupGet' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_list_simcore_service_webserver.workspaces._groups_api.WorkspaceGroupGet__: - title: Envelope[list[simcore_service_webserver.workspaces._groups_api.WorkspaceGroupGet]] type: object + title: Envelope[list[WorkspaceGet]] + Envelope_list_WorkspaceGroupGet__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/WorkspaceGroupGet' + type: array + - type: 'null' title: Data - type: array - items: - $ref: '#/components/schemas/WorkspaceGroupGet' error: + anyOf: + - {} + - type: 'null' title: Error - Envelope_str_: - title: Envelope[str] type: object + title: Envelope[list[WorkspaceGroupGet]] + Envelope_list__ProjectNodePreview__: properties: data: + anyOf: + - items: + $ref: '#/components/schemas/_ProjectNodePreview' + type: array + - type: 'null' title: Data - type: string error: + anyOf: + - {} + - type: 'null' + title: Error + type: object + title: Envelope[list[_ProjectNodePreview]] + Envelope_str_: + properties: + data: + anyOf: + - type: string + - type: 'null' + title: Data + error: + anyOf: + - {} + - type: 'null' title: Error - Error: - title: Error type: object + title: Envelope[str] + Error: properties: logs: + anyOf: + - items: + $ref: '#/components/schemas/Log' + type: array + - type: 'null' title: Logs - type: array - items: - $ref: '#/components/schemas/Log' description: log messages errors: + anyOf: + - items: + $ref: '#/components/schemas/ErrorItem' + type: array + - type: 'null' title: Errors - type: array - items: - $ref: '#/components/schemas/ErrorItem' description: errors metadata status: + anyOf: + - type: integer + - type: 'null' title: Status - type: integer description: HTTP error code - ErrorItem: - title: ErrorItem - required: - - code - - message type: object + title: Error + ErrorItem: properties: code: - title: Code type: string + title: Code description: Typically the name of the exception that produced it otherwise some known error code message: - title: Message type: string + title: Message description: Error message specific to this item resource: + anyOf: + - type: string + - type: 'null' title: Resource - type: string description: API resource affected by this error field: + anyOf: + - type: string + - type: 'null' title: Field - type: string description: Specific field within the resource - ExtractedResults: - title: ExtractedResults - required: - - progress - - labels - - values type: object + required: + - code + - message + title: ErrorItem + ExtractedResults: properties: progress: - title: Progress type: object - additionalProperties: - maximum: 100 - minimum: 0 - type: integer + title: Progress description: Progress in each computational node labels: - title: Labels type: object - additionalProperties: - type: string + title: Labels description: Maps captured node with a label values: - title: Values type: object - additionalProperties: - type: object - additionalProperties: - anyOf: - - type: boolean - - type: integer - - type: number - - type: string - format: json-string - - type: string - - $ref: '#/components/schemas/SimCoreFileLink' - - $ref: '#/components/schemas/DatCoreFileLink' - - $ref: '#/components/schemas/DownloadLink' - - type: array - items: {} - - type: object + title: Values description: Captured outputs per node + type: object + required: + - progress + - labels + - values + title: ExtractedResults example: - progress: - 4c08265a-427b-4ac3-9eab-1d11c822ada4: 0 - e33c6880-1b1d-4419-82d7-270197738aa9: 100 labels: 0f1e38c9-dcb7-443c-a745-91b97ac28ccc: Integer iterator 2d0ce8b9-c9c3-43ce-ad2f-ad493898de37: Probe Sensor - Integer 445b44d1-59b3-425c-ac48-7c13e0f2ea5b: Probe Sensor - Integer_2 d76fca06-f050-4790-88a8-0aac10c87b39: Boolean Parameter + progress: + 4c08265a-427b-4ac3-9eab-1d11c822ada4: 0 + e33c6880-1b1d-4419-82d7-270197738aa9: 100 values: 0f1e38c9-dcb7-443c-a745-91b97ac28ccc: out_1: 1 @@ -8292,656 +8993,795 @@ components: d76fca06-f050-4790-88a8-0aac10c87b39: out_1: true FileMetaData: - title: FileMetaData - type: object properties: file_uuid: + anyOf: + - type: string + - type: 'null' title: File Uuid - type: string location_id: + anyOf: + - type: string + - type: 'null' title: Location Id - type: string project_name: + anyOf: + - type: string + - type: 'null' title: Project Name - type: string node_name: + anyOf: + - type: string + - type: 'null' title: Node Name - type: string file_name: + anyOf: + - type: string + - type: 'null' title: File Name - type: string file_id: + anyOf: + - type: string + - type: 'null' title: File Id - type: string created_at: + anyOf: + - type: string + - type: 'null' title: Created At - type: string last_modified: + anyOf: + - type: string + - type: 'null' title: Last Modified - type: string file_size: + anyOf: + - type: integer + - type: 'null' title: File Size - type: integer entity_tag: + anyOf: + - type: string + - type: 'null' title: Entity Tag - type: string is_directory: + anyOf: + - type: boolean + - type: 'null' title: Is Directory - type: boolean + type: object + title: FileMetaData example: - file_uuid: simcore-testing/105/1000/3 - location_id: '0' - project_name: futurology - node_name: alpha - file_name: example.txt - file_id: N:package:e263da07-2d89-45a6-8b0f-61061b913873 created_at: '2019-06-19T12:29:03.308611Z' - last_modified: '2019-06-19T12:29:03.78852Z' - file_size: 73 entity_tag: a87ff679a2f3e71d9181a67b7542122c + file_id: N:package:e263da07-2d89-45a6-8b0f-61061b913873 + file_name: example.txt + file_size: 73 + file_uuid: simcore-testing/105/1000/3 is_directory: false + last_modified: '2019-06-19T12:29:03.78852Z' + location_id: '0' + node_name: alpha + project_name: futurology FileMetaDataGet: - title: FileMetaDataGet - required: - - file_uuid - - location_id - - file_name - - file_id - - created_at - - last_modified - type: object properties: file_uuid: - title: File Uuid type: string + title: File Uuid description: NOT a unique ID, like (api|uuid)/uuid/file_name or DATCORE folder structure location_id: - title: Location Id type: integer + title: Location Id description: Storage location project_name: + anyOf: + - type: string + - type: 'null' title: Project Name - type: string description: optional project name, used by frontend to display path node_name: + anyOf: + - type: string + - type: 'null' title: Node Name - type: string description: optional node name, used by frontend to display path file_name: - title: File Name type: string + title: File Name description: Display name for a file file_id: - title: File Id anyOf: - - pattern: ^(api|([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}))\/([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12})\/(.+)$ - type: string - - pattern: ^N:package:[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}$ - type: string + - type: string + pattern: ^(api|([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}))\/([0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12})\/(.+)$ + - type: string + pattern: ^N:package:[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}$ + title: File Id description: THIS IS the unique ID for the file. either (api|project_id)/node_id/file_name.ext for S3 and N:package:UUID for datcore created_at: - title: Created At type: string format: date-time + title: Created At last_modified: - title: Last Modified type: string format: date-time + title: Last Modified file_size: - title: File Size anyOf: - type: integer + enum: + - -1 + const: -1 - type: integer + minimum: 0 + title: File Size description: File size in bytes (-1 means invalid) default: -1 entity_tag: + anyOf: + - type: string + - type: 'null' title: Entity Tag - type: string description: Entity tag (or ETag), represents a specific version of the file, None if invalid upload or datcore is_soft_link: - title: Is Soft Link type: boolean + title: Is Soft Link description: If true, this file is a soft link.i.e. is another entry with the same object_name default: false is_directory: - title: Is Directory type: boolean + title: Is Directory description: if True this is a directory default: false sha256_checksum: + anyOf: + - type: string + pattern: ^[a-fA-F0-9]{64}$ + - type: 'null' title: Sha256 Checksum - pattern: ^[a-fA-F0-9]{64}$ - type: string description: 'SHA256 message digest of the file content. Main purpose: cheap lookup.' - additionalProperties: false - FileUploadCompleteFutureResponse: - title: FileUploadCompleteFutureResponse - required: - - state type: object + required: + - file_uuid + - location_id + - file_name + - file_id + - created_at + - last_modified + title: FileMetaDataGet + FileUploadCompleteFutureResponse: properties: state: $ref: '#/components/schemas/FileUploadCompleteState' e_tag: + anyOf: + - type: string + - type: 'null' title: E Tag - type: string - FileUploadCompleteLinks: - title: FileUploadCompleteLinks + type: object required: - state - type: object + title: FileUploadCompleteFutureResponse + FileUploadCompleteLinks: properties: state: - title: State - maxLength: 65536 - minLength: 1 type: string + minLength: 1 format: uri - FileUploadCompleteResponse: - title: FileUploadCompleteResponse - required: - - links + title: State type: object + required: + - state + title: FileUploadCompleteLinks + FileUploadCompleteResponse: properties: links: $ref: '#/components/schemas/FileUploadCompleteLinks' + type: object + required: + - links + title: FileUploadCompleteResponse FileUploadCompleteState: - title: FileUploadCompleteState + type: string enum: - ok - nok - description: An enumeration. + title: FileUploadCompleteState FileUploadCompletionBody: - title: FileUploadCompletionBody - required: - - parts - type: object properties: parts: - title: Parts - type: array items: $ref: '#/components/schemas/UploadedPart' - FileUploadLinks: - title: FileUploadLinks - required: - - abort_upload - - complete_upload + type: array + title: Parts type: object + required: + - parts + title: FileUploadCompletionBody + FileUploadLinks: properties: abort_upload: - title: Abort Upload - maxLength: 65536 - minLength: 1 type: string + minLength: 1 format: uri + title: Abort Upload complete_upload: - title: Complete Upload - maxLength: 65536 - minLength: 1 type: string + minLength: 1 format: uri - FileUploadSchema: - title: FileUploadSchema - required: - - chunk_size - - urls - - links + title: Complete Upload type: object + required: + - abort_upload + - complete_upload + title: FileUploadLinks + FileUploadSchema: properties: chunk_size: - title: Chunk Size type: integer + minimum: 0 + title: Chunk Size urls: - title: Urls - type: array items: - maxLength: 65536 - minLength: 1 type: string + minLength: 1 format: uri + type: array + title: Urls links: $ref: '#/components/schemas/FileUploadLinks' - FolderGet: - title: FolderGet + type: object required: - - folderId - - name - - createdAt - - modifiedAt - - owner - - myAccessRights + - chunk_size + - urls + - links + title: FileUploadSchema + FolderCreateBodyParams: + properties: + name: + type: string + maxLength: 100 + minLength: 1 + title: Name + parentFolderId: + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' + title: Parentfolderid + workspaceId: + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' + title: Workspaceid + additionalProperties: false type: object + required: + - name + title: FolderCreateBodyParams + FolderGet: properties: folderId: - title: Folderid - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Folderid minimum: 0 parentFolderId: + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' title: Parentfolderid - exclusiveMinimum: true - type: integer - minimum: 0 name: - title: Name type: string + title: Name createdAt: - title: Createdat type: string format: date-time + title: Createdat modifiedAt: - title: Modifiedat type: string format: date-time + title: Modifiedat trashedAt: + anyOf: + - type: string + format: date-time + - type: 'null' title: Trashedat - type: string - format: date-time owner: - title: Owner - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Owner minimum: 0 workspaceId: + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' title: Workspaceid - exclusiveMinimum: true - type: integer - minimum: 0 myAccessRights: - $ref: '#/components/schemas/models_library__access_rights__AccessRights' - GenerateInvitation: - title: GenerateInvitation + $ref: '#/components/schemas/AccessRights' + type: object required: - - guest + - folderId + - name + - createdAt + - modifiedAt + - trashedAt + - owner + - workspaceId + - myAccessRights + title: FolderGet + FolderReplaceBodyParams: + properties: + name: + type: string + maxLength: 100 + minLength: 1 + title: Name + parentFolderId: + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' + title: Parentfolderid + additionalProperties: false type: object + required: + - name + title: FolderReplaceBodyParams + GenerateInvitation: properties: guest: - title: Guest type: string format: email + title: Guest trialAccountDays: + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' title: Trialaccountdays - exclusiveMinimum: true - type: integer - minimum: 0 extraCreditsInUsd: + anyOf: + - type: integer + exclusiveMaximum: true + minimum: 0 + maximum: 500 + - type: 'null' title: Extracreditsinusd - exclusiveMaximum: true - minimum: 0 - type: integer - maximum: 500 - GetCreditPrice: - title: GetCreditPrice - required: - - productName - - usdPerCredit - - minPaymentAmountUsd type: object + required: + - guest + title: GenerateInvitation + GetCreditPrice: properties: productName: - title: Productname type: string + title: Productname usdPerCredit: + anyOf: + - type: number + minimum: 0.0 + - type: 'null' title: Usdpercredit - minimum: 0.0 - type: number description: Price of a credit in USD. If None, then this product's price is UNDEFINED minPaymentAmountUsd: + anyOf: + - type: integer + minimum: 0 + - type: 'null' title: Minpaymentamountusd - minimum: 0 - type: integer description: Minimum amount (included) in USD that can be paid for this productCan be None if this product's price is UNDEFINED - GetProduct: - title: GetProduct + type: object required: - - name - - displayName - - loginSettings - - isPaymentEnabled - type: object + - productName + - usdPerCredit + - minPaymentAmountUsd + title: GetCreditPrice + GetProduct: properties: name: - title: Name type: string + title: Name displayName: - title: Displayname type: string + title: Displayname shortName: + anyOf: + - type: string + - type: 'null' title: Shortname - type: string description: Short display name for SMS vendor: + anyOf: + - type: object + - type: 'null' title: Vendor - type: object description: vendor attributes issues: + anyOf: + - items: + type: object + type: array + - type: 'null' title: Issues - type: array - items: - type: object description: Reference to issues tracker manuals: + anyOf: + - items: + type: object + type: array + - type: 'null' title: Manuals - type: array - items: - type: object description: List of manuals support: + anyOf: + - items: + type: object + type: array + - type: 'null' title: Support - type: array - items: - type: object description: List of support resources loginSettings: - title: Loginsettings type: object + title: Loginsettings maxOpenStudiesPerUser: + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' title: Maxopenstudiesperuser - exclusiveMinimum: true - type: integer - minimum: 0 isPaymentEnabled: - title: Ispaymentenabled type: boolean + title: Ispaymentenabled creditsPerUsd: + anyOf: + - type: string + - type: 'null' title: Creditsperusd - minimum: 0.0 - type: number templates: - title: Templates - type: array items: $ref: '#/components/schemas/GetProductTemplate' + type: array + title: Templates description: List of templates available to this product for communications (e.g. emails, sms, etc) - GetProductTemplate: - title: GetProductTemplate - required: - - id - - content type: object + required: + - name + - displayName + - loginSettings + - maxOpenStudiesPerUser + - isPaymentEnabled + - creditsPerUsd + title: GetProduct + GetProductTemplate: properties: id: - title: Id + type: string maxLength: 100 minLength: 1 - type: string + title: Id content: - title: Content type: string - GetProjectInactivityResponse: - title: GetProjectInactivityResponse - required: - - is_inactive + title: Content type: object + required: + - id + - content + title: GetProductTemplate + GetProjectInactivityResponse: properties: is_inactive: - title: Is Inactive type: boolean - GetWalletAutoRecharge: - title: GetWalletAutoRecharge - required: - - paymentMethodId - - minBalanceInCredits - - topUpAmountInUsd - - monthlyLimitInUsd + title: Is Inactive type: object + required: + - is_inactive + title: GetProjectInactivityResponse + GetWalletAutoRecharge: properties: enabled: - title: Enabled type: boolean + title: Enabled description: Enables/disables auto-recharge trigger in this wallet default: false paymentMethodId: + anyOf: + - type: string + maxLength: 100 + minLength: 1 + - type: 'null' title: Paymentmethodid - maxLength: 100 - minLength: 1 - type: string description: Payment method in the wallet used to perform the auto-recharge payments or None if still undefined minBalanceInCredits: + type: string title: Minbalanceincredits - minimum: 0.0 - type: number description: Minimum balance in credits that triggers an auto-recharge [Read only] topUpAmountInUsd: + type: string title: Topupamountinusd - minimum: 0.0 - type: number description: Amount in USD payed when auto-recharge condition is satisfied monthlyLimitInUsd: + anyOf: + - type: string + - type: 'null' title: Monthlylimitinusd - minimum: 0.0 - type: number description: Maximum amount in USD charged within a natural month.None indicates no limit. - GroupAccessRights: - title: GroupAccessRights - required: - - read - - write - - delete type: object + required: + - paymentMethodId + - minBalanceInCredits + - topUpAmountInUsd + - monthlyLimitInUsd + title: GetWalletAutoRecharge + GroupAccessRights: properties: read: - title: Read type: boolean + title: Read write: - title: Write type: boolean + title: Write delete: - title: Delete type: boolean + title: Delete + type: object + required: + - read + - write + - delete + title: GroupAccessRights description: defines acesss rights for the user GroupCreate: - title: GroupCreate - required: - - label - - description - type: object properties: label: - title: Label type: string + title: Label description: - title: Description type: string + title: Description thumbnail: + anyOf: + - type: string + minLength: 1 + format: uri + - type: 'null' title: Thumbnail - maxLength: 65536 - minLength: 1 - type: string - format: uri - GroupGet: - title: GroupGet + type: object required: - - gid - label - description - - accessRights - type: object + title: GroupCreate + GroupGet: properties: gid: - title: Gid type: integer + title: Gid description: the group ID label: - title: Label type: string + title: Label description: the group name description: - title: Description type: string + title: Description description: the group description thumbnail: + anyOf: + - type: string + minLength: 1 + format: uri + - type: 'null' title: Thumbnail - maxLength: 65536 - minLength: 1 - type: string description: url to the group thumbnail - format: uri accessRights: $ref: '#/components/schemas/GroupAccessRights' inclusionRules: - title: Inclusionrules - type: object additionalProperties: type: string + type: object + title: Inclusionrules description: Maps user's column and regular expression - GroupUpdate: - title: GroupUpdate type: object + required: + - gid + - label + - description + - accessRights + title: GroupGet + GroupUpdate: properties: label: + anyOf: + - type: string + - type: 'null' title: Label - type: string description: + anyOf: + - type: string + - type: 'null' title: Description - type: string thumbnail: + anyOf: + - type: string + minLength: 1 + format: uri + - type: 'null' title: Thumbnail - maxLength: 65536 - minLength: 1 - type: string - format: uri - GroupUserAdd: - title: GroupUserAdd type: object + title: GroupUpdate + GroupUserAdd: properties: uid: + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' title: Uid - exclusiveMinimum: true - type: integer - minimum: 0 email: + anyOf: + - type: string + format: email + - type: 'null' title: Email - type: string - format: email + type: object + title: GroupUserAdd description: "Identify the user with either `email` or `uid` \u2014 only one." GroupUserGet: - title: GroupUserGet - required: - - accessRights - type: object properties: id: + anyOf: + - type: string + - type: 'null' title: Id - type: string description: the user id login: + anyOf: + - type: string + format: email + - type: 'null' title: Login - type: string description: the user login email - format: email first_name: + anyOf: + - type: string + - type: 'null' title: First Name - type: string description: the user first name last_name: + anyOf: + - type: string + - type: 'null' title: Last Name - type: string description: the user last name gravatar_id: + anyOf: + - type: string + - type: 'null' title: Gravatar Id - type: string description: the user gravatar id hash gid: + anyOf: + - type: string + - type: 'null' title: Gid - type: string description: the user primary gid accessRights: $ref: '#/components/schemas/GroupAccessRights' + type: object + required: + - accessRights + title: GroupUserGet example: - id: '1' - login: mr.smith@matrix.com - first_name: Mr - last_name: Smith - gravatar_id: a1af5c6ecc38e81f29695f01d6ceb540 - gid: '3' accessRights: + delete: false read: true write: false - delete: false + first_name: Mr + gid: '3' + gravatar_id: a1af5c6ecc38e81f29695f01d6ceb540 + id: '1' + last_name: Smith + login: mr.smith@matrix.com GroupUserUpdate: - title: GroupUserUpdate - required: - - accessRights - type: object properties: accessRights: $ref: '#/components/schemas/GroupAccessRights' + type: object + required: + - accessRights + title: GroupUserUpdate example: accessRights: + delete: false read: true write: false - delete: false HardwareInfo: - title: HardwareInfo - required: - - aws_ec2_instances - type: object properties: aws_ec2_instances: - title: Aws Ec2 Instances - type: array items: type: string - HealthInfoDict: - title: HealthInfoDict - required: - - name - - version - - api_version + type: array + title: Aws Ec2 Instances type: object + required: + - aws_ec2_instances + title: HardwareInfo + HealthInfoDict: properties: name: - title: Name type: string + title: Name version: - title: Version type: string + title: Version api_version: - title: Api Version type: string - ImageResources: - title: ImageResources - required: - - image - - resources + title: Api Version type: object + required: + - name + - version + - api_version + title: HealthInfoDict + ImageResources: properties: image: - title: Image - pattern: ^(?:([a-z0-9-]+(?:\.[a-z0-9-]+)+(?::\d+)?|[a-z0-9-]+:\d+)/)?((?:[a-z0-9][a-z0-9_.-]*/)*[a-z0-9-_]+[a-z0-9])(?::([\w][\w.-]{0,127}))?(\@sha256:[a-fA-F0-9]{32,64})?$ type: string + pattern: ^(?:([a-z0-9-]+(?:\.[a-z0-9-]+)+(?::\d+)?|[a-z0-9-]+:\d+)/)?((?:[a-z0-9][a-z0-9_.-]*/)*[a-z0-9-_]+[a-z0-9])(?::([\w][\w.-]{0,127}))?(\@sha256:[a-fA-F0-9]{32,64})?$ + title: Image description: Used by the frontend to provide a context for the users.Services with a docker-compose spec will have multiple entries.Using the `image:version` instead of the docker-compose spec is more helpful for the end user. resources: - title: Resources - type: object additionalProperties: $ref: '#/components/schemas/ResourceValue' + type: object + title: Resources boot_modes: - type: array items: $ref: '#/components/schemas/BootMode' + type: array + title: Boot Modes description: describe how a service shall be booted, using CPU, MPI, openMP or GPU default: - CPU + type: object + required: + - image + - resources + title: ImageResources example: image: simcore/service/dynamic/pretty-intense:1.0.0 resources: + AIRAM: + limit: 1 + reservation: 1 + ANY_resource: + limit: some_value + reservation: some_value CPU: limit: 4 reservation: 0.1 @@ -8951,533 +9791,643 @@ components: VRAM: limit: 1 reservation: 1 - AIRAM: - limit: 1 - reservation: 1 - ANY_resource: - limit: some_value - reservation: some_value InvitationCheck: - title: InvitationCheck - required: - - invitation - type: object properties: invitation: - title: Invitation type: string + title: Invitation description: Invitation code additionalProperties: false - InvitationGenerated: - title: InvitationGenerated - required: - - productName - - issuer - - guest - - created - - invitationLink type: object + required: + - invitation + title: InvitationCheck + InvitationGenerated: properties: productName: - title: Productname type: string + title: Productname issuer: - title: Issuer type: string + title: Issuer guest: - title: Guest type: string format: email + title: Guest trialAccountDays: + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' title: Trialaccountdays - exclusiveMinimum: true - type: integer - minimum: 0 extraCreditsInUsd: + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' title: Extracreditsinusd - exclusiveMinimum: true - type: integer - minimum: 0 created: - title: Created type: string format: date-time + title: Created invitationLink: - title: Invitationlink + type: string maxLength: 2083 minLength: 1 - type: string format: uri - InvitationInfo: - title: InvitationInfo + title: Invitationlink type: object + required: + - productName + - issuer + - guest + - created + - invitationLink + title: InvitationGenerated + InvitationInfo: properties: email: + anyOf: + - type: string + format: email + - type: 'null' title: Email - type: string description: Email associated to invitation or None - format: email additionalProperties: false - JupyterHubTokenAuthentication: - title: JupyterHubTokenAuthentication - required: - - api_token type: object + title: InvitationInfo + JupyterHubTokenAuthentication: properties: type: - title: Type + type: string enum: - jupyterhub - type: string + const: jupyterhub + title: Type default: jupyterhub api_token: - title: Api Token type: string + title: Api Token additionalProperties: false - KerberosAuthentication: - title: KerberosAuthentication type: object + required: + - api_token + title: JupyterHubTokenAuthentication + KerberosAuthentication: properties: type: - title: Type + type: string enum: - kerberos - type: string + const: kerberos + title: Type default: kerberos additionalProperties: false - Limits: - title: Limits - required: - - cpus - - mem type: object + title: KerberosAuthentication + Limits: properties: cpus: - title: Cpus - exclusiveMinimum: true type: number + exclusiveMinimum: true + title: Cpus minimum: 0.0 mem: - title: Mem - exclusiveMinimum: true type: number + exclusiveMinimum: true + title: Mem minimum: 0.0 + type: object + required: + - cpus + - mem + title: Limits LinkType: - title: LinkType + type: string enum: - PRESIGNED - S3 - type: string - description: An enumeration. + title: LinkType Log: - title: Log - required: - - message - type: object properties: level: - allOf: + anyOf: - $ref: '#/components/schemas/LogLevel' + - type: 'null' description: log level default: INFO message: - title: Message type: string + title: Message description: log message. If logger is USER, then it MUST be human readable logger: + anyOf: + - type: string + - type: 'null' title: Logger - type: string description: name of the logger receiving this message + type: object + required: + - message + title: Log example: - message: Hi there, Mr user level: INFO logger: user-logger + message: Hi there, Mr user LogLevel: - title: LogLevel + type: string enum: - DEBUG - INFO - WARNING - ERROR - type: string - description: An enumeration. + title: LogLevel LoginBody: - title: LoginBody - required: - - email - - password - type: object properties: email: - title: Email type: string format: email + title: Email password: - title: Password type: string format: password + title: Password writeOnly: true additionalProperties: false - LoginNextPage: - title: LoginNextPage - required: - - name type: object + required: + - email + - password + title: LoginBody + LoginNextPage: properties: name: - title: Name type: string + title: Name description: Code name to the front-end page. Ideally a PageStr parameters: - $ref: '#/components/schemas/CodePageParams' - description: 'This is the body of a 2XX response to pass the front-end - - what kind of page shall be display next and some information about it - - - An analogous structure is used in the redirects (see create_redirect_response) - but - - using a path+query in the fragment of the URL' - LoginTwoFactorAuthBody: - title: LoginTwoFactorAuthBody - required: - - email - - code + anyOf: + - $ref: '#/components/schemas/CodePageParams' + - type: 'null' type: object + required: + - name + title: LoginNextPage + LoginTwoFactorAuthBody: properties: email: - title: Email type: string format: email + title: Email code: - title: Code type: string format: password + title: Code writeOnly: true additionalProperties: false - LogoutBody: - title: LogoutBody type: object + required: + - email + - code + title: LoginTwoFactorAuthBody + LogoutBody: properties: client_session_id: + anyOf: + - type: string + - type: 'null' title: Client Session Id - type: string - example: 5ac57685-c40f-448f-8711-70be1936fd63 additionalProperties: false - Marker: - title: Marker - required: - - color type: object + title: LogoutBody + Marker: properties: color: - title: Color type: string format: color + title: Color additionalProperties: false - MyGroupsGet: - title: MyGroupsGet + type: object required: - - me - - all - type: object + - color + title: Marker + MyGroupsGet: properties: me: $ref: '#/components/schemas/GroupGet' organizations: + anyOf: + - items: + $ref: '#/components/schemas/GroupGet' + type: array + - type: 'null' title: Organizations - type: array - items: - $ref: '#/components/schemas/GroupGet' all: $ref: '#/components/schemas/GroupGet' product: - $ref: '#/components/schemas/GroupGet' + anyOf: + - $ref: '#/components/schemas/GroupGet' + - type: 'null' + type: object + required: + - me + - all + title: MyGroupsGet example: + all: + accessRights: + delete: false + read: true + write: false + description: Open to all users + gid: '0' + label: All me: - gid: '27' - label: A user - description: A very special user accessRights: + delete: true read: true write: true - delete: true + description: A very special user + gid: '27' + label: A user organizations: - - gid: '15' - label: ITIS Foundation - description: The Foundation for Research on Information Technologies in - Society - accessRights: - read: true - write: false + - accessRights: delete: false - - gid: '16' - label: Blue Fundation - description: Some foundation - accessRights: read: true write: false + description: The Foundation for Research on Information Technologies in + Society + gid: '15' + label: ITIS Foundation + - accessRights: delete: false - all: - gid: '0' - label: All - description: Open to all users - accessRights: read: true write: false - delete: false + description: Some foundation + gid: '16' + label: Blue Fundation NoAuthentication: - title: NoAuthentication - type: object properties: type: - title: Type + type: string enum: - none - type: string + const: none + title: Type default: none additionalProperties: false - Node: - title: Node + type: object + title: NoAuthentication + Node-Input: + properties: + key: + type: string + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + title: Key + description: distinctive name for the node based on the docker registry + path + version: + type: string + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + title: Version + description: semantic version number of the node + label: + type: string + title: Label + description: The short name of the node + progress: + anyOf: + - type: number + maximum: 100.0 + minimum: 0.0 + - type: 'null' + title: Progress + description: the node progress value (deprecated in DB, still used for API + only) + deprecated: true + thumbnail: + anyOf: + - type: string + - type: 'null' + title: Thumbnail + description: url of the latest screenshot of the node + runHash: + anyOf: + - type: string + - type: 'null' + title: Runhash + description: the hex digest of the resolved inputs +outputs hash at the + time when the last outputs were generated + nullable: true + inputs: + anyOf: + - type: object + - type: 'null' + title: Inputs + description: values of input properties + inputsRequired: + items: + type: string + pattern: ^[-_a-zA-Z0-9]+$ + type: array + title: Inputsrequired + description: Defines inputs that are required in order to run the service + inputsUnits: + anyOf: + - type: object + - type: 'null' + title: Inputsunits + description: Overrides default unit (if any) defined in the service for + each port + inputAccess: + anyOf: + - type: object + - type: 'null' + title: Inputaccess + description: map with key - access level pairs + inputNodes: + anyOf: + - items: + type: string + format: uuid + type: array + - type: 'null' + title: Inputnodes + description: node IDs of where the node is connected to + outputs: + anyOf: + - type: object + - type: 'null' + title: Outputs + description: values of output properties + outputNode: + anyOf: + - type: boolean + - type: 'null' + title: Outputnode + deprecated: true + outputNodes: + anyOf: + - items: + type: string + format: uuid + type: array + - type: 'null' + title: Outputnodes + description: Used in group-nodes. Node IDs of those connected to the output + parent: + anyOf: + - type: string + format: uuid + - type: 'null' + title: Parent + description: Parent's (group-nodes') node ID s. Used to group + nullable: true + position: + anyOf: + - $ref: '#/components/schemas/Position' + - type: 'null' + description: Use projects_ui.WorkbenchUI.position instead + deprecated: true + state: + anyOf: + - $ref: '#/components/schemas/NodeState' + - type: 'null' + description: The node's state object + bootOptions: + anyOf: + - type: object + - type: 'null' + title: Bootoptions + description: Some services provide alternative parameters to be injected + at boot time. The user selection should be stored here, and it will overwrite + the services's defaults. + additionalProperties: false + type: object required: - key - version - label - type: object + title: Node + Node-Output: properties: key: - title: Key - pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ type: string + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + title: Key description: distinctive name for the node based on the docker registry path version: - title: Version - pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ type: string + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + title: Version description: semantic version number of the node label: - title: Label type: string + title: Label description: The short name of the node progress: + anyOf: + - type: number + maximum: 100.0 + minimum: 0.0 + - type: 'null' title: Progress - maximum: 100.0 - minimum: 0.0 - type: number description: the node progress value (deprecated in DB, still used for API only) deprecated: true thumbnail: + anyOf: + - type: string + - type: 'null' title: Thumbnail - maxLength: 2083 - minLength: 0 - type: string description: url of the latest screenshot of the node - format: uri runHash: + anyOf: + - type: string + - type: 'null' title: Runhash - type: string description: the hex digest of the resolved inputs +outputs hash at the time when the last outputs were generated nullable: true inputs: + anyOf: + - type: object + - type: 'null' title: Inputs - type: object - additionalProperties: - anyOf: - - type: boolean - - type: integer - - type: number - - type: string - format: json-string - - type: string - - $ref: '#/components/schemas/PortLink' - - $ref: '#/components/schemas/SimCoreFileLink' - - $ref: '#/components/schemas/DatCoreFileLink' - - $ref: '#/components/schemas/DownloadLink' - - type: array - items: {} - - type: object description: values of input properties inputsRequired: - title: Inputsrequired - type: array items: - pattern: ^[-_a-zA-Z0-9]+$ type: string + pattern: ^[-_a-zA-Z0-9]+$ + type: array + title: Inputsrequired description: Defines inputs that are required in order to run the service inputsUnits: + anyOf: + - type: object + - type: 'null' title: Inputsunits - type: object - additionalProperties: - type: string description: Overrides default unit (if any) defined in the service for each port inputAccess: - type: object - additionalProperties: - $ref: '#/components/schemas/AccessEnum' + anyOf: + - type: object + - type: 'null' + title: Inputaccess description: map with key - access level pairs inputNodes: + anyOf: + - items: + type: string + format: uuid + type: array + - type: 'null' title: Inputnodes - type: array - items: - type: string - format: uuid description: node IDs of where the node is connected to outputs: + anyOf: + - type: object + - type: 'null' title: Outputs - type: object - additionalProperties: - anyOf: - - type: boolean - - type: integer - - type: number - - type: string - format: json-string - - type: string - - $ref: '#/components/schemas/SimCoreFileLink' - - $ref: '#/components/schemas/DatCoreFileLink' - - $ref: '#/components/schemas/DownloadLink' - - type: array - items: {} - - type: object description: values of output properties outputNode: + anyOf: + - type: boolean + - type: 'null' title: Outputnode - type: boolean deprecated: true outputNodes: + anyOf: + - items: + type: string + format: uuid + type: array + - type: 'null' title: Outputnodes - type: array - items: - type: string - format: uuid description: Used in group-nodes. Node IDs of those connected to the output parent: + anyOf: + - type: string + format: uuid + - type: 'null' title: Parent - type: string description: Parent's (group-nodes') node ID s. Used to group - format: uuid nullable: true position: - title: Position - allOf: + anyOf: - $ref: '#/components/schemas/Position' + - type: 'null' description: Use projects_ui.WorkbenchUI.position instead deprecated: true state: - title: State - allOf: + anyOf: - $ref: '#/components/schemas/NodeState' + - type: 'null' description: The node's state object bootOptions: + anyOf: + - type: object + - type: 'null' title: Bootoptions - type: object - additionalProperties: - type: string description: Some services provide alternative parameters to be injected at boot time. The user selection should be stored here, and it will overwrite the services's defaults. additionalProperties: false - NodeCreate: - title: NodeCreate - required: - - service_key - - service_version type: object + required: + - key + - version + - label + title: Node + NodeCreate: properties: service_key: - title: Service Key - pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ type: string + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + title: Service Key service_version: - title: Service Version - pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ type: string + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + title: Service Version service_id: + anyOf: + - type: string + - type: 'null' title: Service Id - type: string - NodeCreated: - title: NodeCreated - required: - - nodeId type: object + required: + - service_key + - service_version + title: NodeCreate + NodeCreated: properties: nodeId: - title: Nodeid type: string format: uuid - NodeGet: - title: NodeGet - required: - - publishedPort - - serviceUuid - - serviceKey - - serviceVersion - - serviceHost - - servicePort - - serviceState - - userId + title: Nodeid type: object + required: + - nodeId + title: NodeCreated + NodeGet: properties: publishedPort: + anyOf: + - type: integer + exclusiveMaximum: true + exclusiveMinimum: true + maximum: 65535 + minimum: 0 + - type: 'null' title: Publishedport - exclusiveMaximum: true - exclusiveMinimum: true - type: integer description: The ports where the service provides its interface - maximum: 65535 - minimum: 0 entryPoint: + anyOf: + - type: string + - type: 'null' title: Entrypoint - type: string description: The entry point where the service provides its interface if specified serviceUuid: - title: Serviceuuid type: string + title: Serviceuuid description: The UUID attached to this service serviceKey: - title: Servicekey - pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ type: string + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + title: Servicekey description: distinctive name for the node based on the docker registry path - example: - - simcore/services/comp/itis/sleeper - - simcore/services/dynamic/3dviewer serviceVersion: - title: Serviceversion - pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ type: string + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + title: Serviceversion description: semantic version number - example: - - 1.0.0 - - 0.0.1 serviceHost: - title: Servicehost type: string + title: Servicehost description: service host name within the network servicePort: - title: Serviceport + type: integer exclusiveMaximum: true exclusiveMinimum: true - type: integer + title: Serviceport description: port to access the service within the network maximum: 65535 minimum: 0 serviceBasepath: + anyOf: + - type: string + - type: 'null' title: Servicebasepath - type: string description: different base path where current service is mounted otherwise defaults to root default: '' serviceState: - allOf: - - $ref: '#/components/schemas/ServiceState' + $ref: '#/components/schemas/ServiceState' description: 'the service state * ''pending'' - The service is waiting for resources to start * ''pulling'' - The service is being pulled from the registry * ''starting'' - The service is starting * ''running'' - The @@ -9486,693 +10436,744 @@ components: ' serviceMessage: + anyOf: + - type: string + - type: 'null' title: Servicemessage - type: string description: the service message userId: - title: Userid type: string + title: Userid description: the user that started the service - NodeGetIdle: - title: NodeGetIdle + type: object required: - - serviceState + - publishedPort - serviceUuid - type: object + - serviceKey + - serviceVersion + - serviceHost + - servicePort + - serviceState + - userId + title: NodeGet + NodeGetIdle: properties: serviceState: - title: Servicestate + type: string enum: - idle - type: string + const: idle + title: Servicestate serviceUuid: - title: Serviceuuid type: string format: uuid - example: - service_uuid: 3fa85f64-5717-4562-b3fc-2c963f66afa6 - service_state: idle - NodeGetUnknown: - title: NodeGetUnknown + title: Serviceuuid + type: object required: - serviceState - serviceUuid - type: object + title: NodeGetIdle + example: + service_state: idle + service_uuid: 3fa85f64-5717-4562-b3fc-2c963f66afa6 + NodeGetUnknown: properties: serviceState: - title: Servicestate + type: string enum: - unknown - type: string + const: unknown + title: Servicestate serviceUuid: - title: Serviceuuid type: string format: uuid + title: Serviceuuid + type: object + required: + - serviceState + - serviceUuid + title: NodeGetUnknown example: - service_uuid: 3fa85f64-5717-4562-b3fc-2c963f66afa6 service_state: unknown + service_uuid: 3fa85f64-5717-4562-b3fc-2c963f66afa6 NodeOutputs: - title: NodeOutputs - required: - - outputs - type: object properties: outputs: - title: Outputs type: object - NodePatch: - title: NodePatch + title: Outputs type: object + required: + - outputs + title: NodeOutputs + NodePatch: properties: key: + anyOf: + - type: string + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + - type: 'null' title: Key - pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ - type: string version: + anyOf: + - type: string + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + - type: 'null' title: Version - pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ - type: string label: + anyOf: + - type: string + - type: 'null' title: Label - type: string inputs: - title: Inputs type: object - additionalProperties: - anyOf: - - type: boolean - - type: integer - - type: number - - type: string - format: json-string - - type: string - - $ref: '#/components/schemas/PortLink' - - $ref: '#/components/schemas/SimCoreFileLink' - - $ref: '#/components/schemas/DatCoreFileLink' - - $ref: '#/components/schemas/DownloadLink' - - type: array - items: {} - - type: object + title: Inputs inputsRequired: + anyOf: + - items: + type: string + pattern: ^[-_a-zA-Z0-9]+$ + type: array + - type: 'null' title: Inputsrequired - type: array - items: - pattern: ^[-_a-zA-Z0-9]+$ - type: string inputNodes: + anyOf: + - items: + type: string + format: uuid + type: array + - type: 'null' title: Inputnodes - type: array - items: - type: string - format: uuid progress: + anyOf: + - type: number + maximum: 100.0 + minimum: 0.0 + - type: 'null' title: Progress - maximum: 100.0 - minimum: 0.0 - type: number bootOptions: + anyOf: + - type: object + - type: 'null' title: Bootoptions - type: object outputs: + anyOf: + - type: object + - type: 'null' title: Outputs - type: object - NodeRetrieve: - title: NodeRetrieve type: object + title: NodePatch + NodeRetrieve: properties: port_keys: - title: Port Keys - type: array items: - pattern: ^[-_a-zA-Z0-9]+$ type: string + pattern: ^[-_a-zA-Z0-9]+$ + type: array + title: Port Keys default: [] - NodeRetrieved: - title: NodeRetrieved - required: - - sizeBytes type: object + title: NodeRetrieve + NodeRetrieved: properties: sizeBytes: - title: Sizebytes type: integer + minimum: 0 + title: Sizebytes description: The amount of data transferred by the retrieve call - NodeScreenshot: - title: NodeScreenshot - required: - - thumbnail_url - - file_url type: object + required: + - sizeBytes + title: NodeRetrieved + NodeScreenshot: properties: thumbnail_url: - title: Thumbnail Url + type: string maxLength: 2083 minLength: 1 - type: string format: uri + title: Thumbnail Url file_url: - title: File Url + type: string maxLength: 2083 minLength: 1 - type: string format: uri + title: File Url mimetype: + anyOf: + - type: string + - type: 'null' title: Mimetype - type: string description: File's media type or None if unknown. SEE https://www.iana.org/assignments/media-types/media-types.xhtml - example: image/jpeg - NodeState: - title: NodeState type: object + required: + - thumbnail_url + - file_url + title: NodeScreenshot + NodeState: properties: modified: - title: Modified type: boolean + title: Modified description: true if the node's outputs need to be re-computed default: true dependencies: - title: Dependencies - uniqueItems: true - type: array items: type: string format: uuid + type: array + uniqueItems: true + title: Dependencies description: contains the node inputs dependencies if they need to be computed first currentStatus: - allOf: - - $ref: '#/components/schemas/RunningState' + $ref: '#/components/schemas/RunningState' description: the node's current state default: NOT_STARTED progress: + anyOf: + - type: number + maximum: 1.0 + minimum: 0.0 + - type: 'null' title: Progress - maximum: 1.0 - minimum: 0.0 - type: number description: current progress of the task if available (None if not started or not a computational task) default: 0 additionalProperties: false + type: object + title: NodeState NotificationCategory: - title: NotificationCategory + type: string enum: - NEW_ORGANIZATION - STUDY_SHARED - TEMPLATE_SHARED - ANNOTATION_NOTE - WALLET_SHARED - type: string - description: An enumeration. + title: NotificationCategory OsparcCreditsAggregatedByServiceGet: - title: OsparcCreditsAggregatedByServiceGet - required: - - osparc_credits - - service_key - - running_time_in_hours - type: object properties: osparc_credits: + type: string title: Osparc Credits - type: number service_key: - title: Service Key - pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ type: string + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + title: Service Key running_time_in_hours: + type: string title: Running Time In Hours - type: number - Owner: - title: Owner - required: - - user_id - - first_name - - last_name type: object + required: + - osparc_credits + - service_key + - running_time_in_hours + title: OsparcCreditsAggregatedByServiceGet + Owner: properties: user_id: - title: User Id type: integer + exclusiveMinimum: true + title: User Id description: Owner's user id + minimum: 0 first_name: + anyOf: + - type: string + maxLength: 255 + - type: 'null' title: First Name - maxLength: 255 - type: string description: Owner's first name last_name: + anyOf: + - type: string + maxLength: 255 + - type: 'null' title: Last Name - maxLength: 255 - type: string description: Owner's last name additionalProperties: false - PageLinks: - title: PageLinks type: object + required: + - user_id + - first_name + - last_name + title: Owner + PageLinks: properties: self: + type: string title: Self first: + type: string title: First prev: + anyOf: + - type: string + - type: 'null' title: Prev next: + anyOf: + - type: string + - type: 'null' title: Next last: + type: string title: Last additionalProperties: false - PageMetaInfoLimitOffset: - title: PageMetaInfoLimitOffset - required: - - total - - count type: object + required: + - self + - first + - prev + - next + - last + title: PageLinks + PageMetaInfoLimitOffset: properties: limit: - title: Limit - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Limit default: 20 minimum: 0 total: - title: Total - minimum: 0 type: integer - offset: - title: Offset minimum: 0 + title: Total + offset: type: integer + minimum: 0 + title: Offset default: 0 count: - title: Count - minimum: 0 type: integer + minimum: 0 + title: Count additionalProperties: false - Page_CatalogServiceGet_: - title: Page[CatalogServiceGet] - required: - - _meta - - _links - - data type: object + required: + - total + - count + title: PageMetaInfoLimitOffset + Page_CatalogServiceGet_: properties: _meta: $ref: '#/components/schemas/PageMetaInfoLimitOffset' _links: $ref: '#/components/schemas/PageLinks' data: - title: Data - type: array items: $ref: '#/components/schemas/CatalogServiceGet' + type: array + title: Data additionalProperties: false - description: Paginated response model of ItemTs - Page_CheckpointApiModel_: - title: Page[CheckpointApiModel] + type: object required: - _meta - _links - data - type: object + title: Page[CatalogServiceGet] + Page_CheckpointApiModel_: properties: _meta: $ref: '#/components/schemas/PageMetaInfoLimitOffset' _links: $ref: '#/components/schemas/PageLinks' data: - title: Data - type: array items: $ref: '#/components/schemas/CheckpointApiModel' + type: array + title: Data additionalProperties: false - description: Paginated response model of ItemTs - Page_PaymentTransaction_: - title: Page[PaymentTransaction] + type: object required: - _meta - _links - data - type: object + title: Page[CheckpointApiModel] + Page_PaymentTransaction_: properties: _meta: $ref: '#/components/schemas/PageMetaInfoLimitOffset' _links: $ref: '#/components/schemas/PageLinks' data: - title: Data - type: array items: $ref: '#/components/schemas/PaymentTransaction' + type: array + title: Data additionalProperties: false - description: Paginated response model of ItemTs - Page_ProjectIterationItem_: - title: Page[ProjectIterationItem] + type: object required: - _meta - _links - data - type: object + title: Page[PaymentTransaction] + Page_ProjectIterationItem_: properties: _meta: $ref: '#/components/schemas/PageMetaInfoLimitOffset' _links: $ref: '#/components/schemas/PageLinks' data: - title: Data - type: array items: $ref: '#/components/schemas/ProjectIterationItem' + type: array + title: Data additionalProperties: false - description: Paginated response model of ItemTs - Page_ProjectIterationResultItem_: - title: Page[ProjectIterationResultItem] + type: object required: - _meta - _links - data - type: object + title: Page[ProjectIterationItem] + Page_ProjectIterationResultItem_: properties: _meta: $ref: '#/components/schemas/PageMetaInfoLimitOffset' _links: $ref: '#/components/schemas/PageLinks' data: - title: Data - type: array items: $ref: '#/components/schemas/ProjectIterationResultItem' + type: array + title: Data additionalProperties: false - description: Paginated response model of ItemTs - Page_ProjectListItem_: - title: Page[ProjectListItem] + type: object required: - _meta - _links - data - type: object + title: Page[ProjectIterationResultItem] + Page_ProjectListItem_: properties: _meta: $ref: '#/components/schemas/PageMetaInfoLimitOffset' _links: $ref: '#/components/schemas/PageLinks' data: - title: Data - type: array items: $ref: '#/components/schemas/ProjectListItem' + type: array + title: Data additionalProperties: false - description: Paginated response model of ItemTs - Page_RepoApiModel_: - title: Page[RepoApiModel] + type: object required: - _meta - _links - data - type: object + title: Page[ProjectListItem] + Page_RepoApiModel_: properties: _meta: $ref: '#/components/schemas/PageMetaInfoLimitOffset' _links: $ref: '#/components/schemas/PageLinks' data: - title: Data - type: array items: $ref: '#/components/schemas/RepoApiModel' + type: array + title: Data additionalProperties: false - description: Paginated response model of ItemTs - ParentMetaProjectRef: - title: ParentMetaProjectRef - required: - - project_id - - ref_id type: object + required: + - _meta + - _links + - data + title: Page[RepoApiModel] + ParentMetaProjectRef: properties: project_id: - title: Project Id type: string format: uuid + title: Project Id ref_id: - title: Ref Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Ref Id minimum: 0 - PatchRequestBody: - title: PatchRequestBody type: object - properties: - value: - title: Value - PaymentMethodGet: - title: PaymentMethodGet required: - - idr - - walletId - - created + - project_id + - ref_id + title: ParentMetaProjectRef + PatchRequestBody: + properties: + value: + title: Value type: object + required: + - value + title: PatchRequestBody + PaymentMethodGet: properties: idr: - title: Idr + type: string maxLength: 100 minLength: 1 - type: string + title: Idr walletId: - title: Walletid - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Walletid minimum: 0 cardHolderName: + anyOf: + - type: string + - type: 'null' title: Cardholdername - type: string cardNumberMasked: + anyOf: + - type: string + - type: 'null' title: Cardnumbermasked - type: string cardType: + anyOf: + - type: string + - type: 'null' title: Cardtype - type: string expirationMonth: + anyOf: + - type: integer + - type: 'null' title: Expirationmonth - type: integer expirationYear: + anyOf: + - type: integer + - type: 'null' title: Expirationyear - type: integer created: - title: Created type: string format: date-time + title: Created autoRecharge: - title: Autorecharge type: boolean + title: Autorecharge description: If true, this payment-method is used for auto-recharge default: false - PaymentMethodInitiated: - title: PaymentMethodInitiated + type: object required: + - idr - walletId - - paymentMethodId - - paymentMethodFormUrl - type: object + - created + title: PaymentMethodGet + PaymentMethodInitiated: properties: walletId: - title: Walletid - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Walletid minimum: 0 paymentMethodId: - title: Paymentmethodid + type: string maxLength: 100 minLength: 1 - type: string + title: Paymentmethodid paymentMethodFormUrl: - title: Paymentmethodformurl + type: string maxLength: 2083 minLength: 1 - type: string - description: Link to external site that holds the payment submission form format: uri - PaymentTransaction: - title: PaymentTransaction + title: Paymentmethodformurl + description: Link to external site that holds the payment submission form + type: object required: - - paymentId - - priceDollars - walletId - - osparcCredits - - createdAt - - completedStatus - type: object + - paymentMethodId + - paymentMethodFormUrl + title: PaymentMethodInitiated + PaymentTransaction: properties: paymentId: - title: Paymentid + type: string maxLength: 100 minLength: 1 - type: string + title: Paymentid priceDollars: + type: string title: Pricedollars - type: number walletId: - title: Walletid - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Walletid minimum: 0 osparcCredits: + type: string title: Osparccredits - type: number comment: + anyOf: + - type: string + - type: 'null' title: Comment - type: string createdAt: - title: Createdat type: string format: date-time + title: Createdat completedAt: + anyOf: + - type: string + format: date-time + - type: 'null' title: Completedat - type: string - format: date-time completedStatus: - title: Completedstatus + type: string enum: - PENDING - SUCCESS - FAILED - CANCELED - type: string + title: Completedstatus stateMessage: + anyOf: + - type: string + - type: 'null' title: Statemessage - type: string invoiceUrl: + anyOf: + - type: string + maxLength: 2083 + minLength: 1 + format: uri + - type: 'null' title: Invoiceurl - maxLength: 2083 - minLength: 1 - type: string - format: uri - PermissionGet: - title: PermissionGet - required: - - name - - allowed type: object + required: + - paymentId + - priceDollars + - walletId + - osparcCredits + - createdAt + - completedAt + - completedStatus + title: PaymentTransaction + PermissionGet: properties: name: - title: Name type: string + title: Name allowed: - title: Allowed type: boolean - PhoneConfirmationBody: - title: PhoneConfirmationBody - required: - - email - - phone - - code + title: Allowed type: object + required: + - name + - allowed + title: PermissionGet + PhoneConfirmationBody: properties: email: - title: Email type: string format: email + title: Email phone: - title: Phone type: string + title: Phone description: Phone number E.164, needed on the deployments with 2FA code: - title: Code type: string format: password + title: Code writeOnly: true additionalProperties: false - PortLink: - title: PortLink - required: - - nodeUuid - - output type: object + required: + - email + - phone + - code + title: PhoneConfirmationBody + PortLink: properties: nodeUuid: - title: Nodeuuid type: string - description: The node to get the port output from format: uuid + title: Nodeuuid + description: The node to get the port output from output: - title: Output - pattern: ^[-_a-zA-Z0-9]+$ type: string + pattern: ^[-_a-zA-Z0-9]+$ + title: Output description: The port key in the node given by nodeUuid additionalProperties: false + type: object + required: + - nodeUuid + - output + title: PortLink description: I/O port type to reference to an output port of another node in the same project Position: - title: Position - required: - - x - - y - type: object properties: x: - title: X type: integer + title: X description: The x position - example: - - '12' y: - title: Y type: integer + title: Y description: The y position - example: - - '15' additionalProperties: false - PreUserProfile: - title: PreUserProfile - required: - - firstName - - lastName - - email - - address - - city - - postalCode - - country type: object + required: + - x + - y + title: Position + PreUserProfile: properties: firstName: - title: Firstname type: string + title: Firstname lastName: - title: Lastname type: string + title: Lastname email: - title: Email type: string format: email + title: Email institution: + anyOf: + - type: string + - type: 'null' title: Institution - type: string description: company, university, ... phone: + anyOf: + - type: string + - type: 'null' title: Phone - type: string address: - title: Address type: string + title: Address city: - title: City type: string + title: City state: + anyOf: + - type: string + - type: 'null' title: State - type: string postalCode: - title: Postalcode type: string + title: Postalcode country: - title: Country type: string + title: Country extras: - title: Extras type: object + title: Extras description: Keeps extra information provided in the request form. At most MAX_NUM_EXTRAS fields - Preference: - title: Preference - required: - - defaultValue - - value type: object + required: + - firstName + - lastName + - email + - phone + - address + - city + - postalCode + - country + title: PreUserProfile + Preference: properties: defaultValue: title: Defaultvalue @@ -10180,188 +11181,192 @@ components: value: title: Value description: preference value - PresignedLink: - title: PresignedLink - required: - - link type: object - properties: - link: - title: Link - maxLength: 65536 - minLength: 1 - type: string - format: uri - PricingPlanAdminGet: - title: PricingPlanAdminGet required: - - pricingPlanId - - displayName - - description - - classification - - createdAt - - pricingPlanKey - - isActive + - defaultValue + - value + title: Preference + PresignedLink: + properties: + link: + type: string + minLength: 1 + format: uri + title: Link type: object + required: + - link + title: PresignedLink + PricingPlanAdminGet: properties: pricingPlanId: - title: Pricingplanid - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Pricingplanid minimum: 0 displayName: - title: Displayname type: string + title: Displayname description: - title: Description type: string + title: Description classification: $ref: '#/components/schemas/PricingPlanClassification' createdAt: - title: Createdat type: string format: date-time + title: Createdat pricingPlanKey: - title: Pricingplankey type: string + title: Pricingplankey pricingUnits: + anyOf: + - items: + $ref: '#/components/schemas/PricingUnitGet' + type: array + - type: 'null' title: Pricingunits - type: array - items: - $ref: '#/components/schemas/PricingUnitGet' isActive: - title: Isactive type: boolean + title: Isactive + type: object + required: + - pricingPlanId + - displayName + - description + - classification + - createdAt + - pricingPlanKey + - pricingUnits + - isActive + title: PricingPlanAdminGet PricingPlanClassification: - title: PricingPlanClassification + type: string enum: - TIER - type: string - description: An enumeration. + const: TIER + title: PricingPlanClassification PricingPlanToServiceAdminGet: - title: PricingPlanToServiceAdminGet - required: - - pricingPlanId - - serviceKey - - serviceVersion - - created - type: object properties: pricingPlanId: - title: Pricingplanid - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Pricingplanid minimum: 0 serviceKey: - title: Servicekey - pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ type: string + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + title: Servicekey serviceVersion: - title: Serviceversion - pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ type: string + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + title: Serviceversion created: - title: Created type: string format: date-time - PricingUnitAdminGet: - title: PricingUnitAdminGet - required: - - pricingUnitId - - unitName - - unitExtraInfo - - currentCostPerUnit - - default - - specificInfo + title: Created type: object + required: + - pricingPlanId + - serviceKey + - serviceVersion + - created + title: PricingPlanToServiceAdminGet + PricingUnitAdminGet: properties: pricingUnitId: - title: Pricingunitid - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Pricingunitid minimum: 0 unitName: - title: Unitname type: string + title: Unitname unitExtraInfo: - title: Unitextrainfo - type: object + $ref: '#/components/schemas/UnitExtraInfo-Output' currentCostPerUnit: - title: Currentcostperunit type: number + title: Currentcostperunit default: - title: Default type: boolean + title: Default specificInfo: $ref: '#/components/schemas/HardwareInfo' - PricingUnitCostUpdate: - title: PricingUnitCostUpdate - required: - - cost_per_unit - - comment type: object - properties: - cost_per_unit: - title: Cost Per Unit - type: number - comment: - title: Comment - type: string - PricingUnitGet: - title: PricingUnitGet required: - pricingUnitId - unitName - unitExtraInfo - currentCostPerUnit - default + - specificInfo + title: PricingUnitAdminGet + PricingUnitCostUpdate: + properties: + cost_per_unit: + anyOf: + - type: number + - type: string + title: Cost Per Unit + comment: + type: string + title: Comment type: object + required: + - cost_per_unit + - comment + title: PricingUnitCostUpdate + PricingUnitGet: properties: pricingUnitId: - title: Pricingunitid - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Pricingunitid minimum: 0 unitName: - title: Unitname type: string + title: Unitname unitExtraInfo: - title: Unitextrainfo - type: object + $ref: '#/components/schemas/UnitExtraInfo-Output' currentCostPerUnit: - title: Currentcostperunit type: number + title: Currentcostperunit default: - title: Default type: boolean - ProfileGet: - title: ProfileGet - required: - - id - - login - - role - - preferences + title: Default type: object + required: + - pricingUnitId + - unitName + - unitExtraInfo + - currentCostPerUnit + - default + title: PricingUnitGet + ProfileGet: properties: id: - title: Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Id minimum: 0 first_name: + anyOf: + - type: string + maxLength: 255 + - type: 'null' title: First Name - maxLength: 255 - type: string last_name: + anyOf: + - type: string + maxLength: 255 + - type: 'null' title: Last Name - maxLength: 255 - type: string login: - title: Login type: string format: email + title: Login role: - title: Role + type: string enum: - ANONYMOUS - GUEST @@ -10369,639 +11374,710 @@ components: - TESTER - PRODUCT_OWNER - ADMIN - type: string + title: Role groups: - $ref: '#/components/schemas/MyGroupsGet' + anyOf: + - $ref: '#/components/schemas/MyGroupsGet' + - type: 'null' gravatar_id: + anyOf: + - type: string + - type: 'null' title: Gravatar Id - type: string expirationDate: + anyOf: + - type: string + format: date + - type: 'null' title: Expirationdate - type: string description: If user has a trial account, it sets the expiration date, otherwise None - format: date preferences: - title: Preferences - type: object additionalProperties: $ref: '#/components/schemas/Preference' - ProfileUpdate: - title: ProfileUpdate + type: object + title: Preferences type: object + required: + - id + - login + - role + - preferences + title: ProfileGet + ProfileUpdate: properties: first_name: + anyOf: + - type: string + maxLength: 255 + - type: 'null' title: First Name - maxLength: 255 - type: string last_name: + anyOf: + - type: string + maxLength: 255 + - type: 'null' title: Last Name - maxLength: 255 - type: string + type: object + title: ProfileUpdate example: first_name: Pedro last_name: Crespo ProjectCopyOverride: - title: ProjectCopyOverride - required: - - name - - prjOwner - type: object properties: name: - title: Name type: string + title: Name description: + anyOf: + - type: string + - type: 'null' title: Description - type: string thumbnail: + anyOf: + - type: string + maxLength: 2083 + minLength: 1 + format: uri + - type: 'null' title: Thumbnail - maxLength: 2083 - minLength: 0 - type: string - format: uri prjOwner: - title: Prjowner type: string format: email - ProjectCreateNew: - title: ProjectCreateNew + title: Prjowner + type: object required: - name - - workbench - - accessRights - type: object + - prjOwner + title: ProjectCopyOverride + ProjectCreateNew: properties: uuid: + anyOf: + - type: string + format: uuid + - type: 'null' title: Uuid - type: string - format: uuid name: - title: Name type: string + title: Name description: + anyOf: + - type: string + - type: 'null' title: Description - type: string thumbnail: + anyOf: + - type: string + maxLength: 2083 + minLength: 1 + format: uri + - type: 'null' title: Thumbnail - maxLength: 2083 - minLength: 0 - type: string - format: uri workbench: - title: Workbench type: object - additionalProperties: - $ref: '#/components/schemas/Node' + title: Workbench accessRights: - title: Accessrights - type: object additionalProperties: - $ref: '#/components/schemas/models_library__projects_access__AccessRights' + $ref: '#/components/schemas/AccessRights' + type: object + title: Accessrights tags: - title: Tags - type: array items: type: integer - classifiers: - title: Classifiers type: array + title: Tags + classifiers: items: type: string + type: array + title: Classifiers ui: - $ref: '#/components/schemas/StudyUI' + anyOf: + - $ref: '#/components/schemas/StudyUI-Input' + - type: 'null' workspaceId: + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' title: Workspaceid - exclusiveMinimum: true - type: integer - minimum: 0 folderId: + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' title: Folderid - exclusiveMinimum: true - type: integer - minimum: 0 - ProjectGet: - title: ProjectGet + type: object required: - - uuid - name - - description - - thumbnail - - creationDate - - lastChangeDate - workbench - - prjOwner - accessRights - - tags - type: object + title: ProjectCreateNew + ProjectGet: properties: uuid: - title: Uuid type: string format: uuid + title: Uuid name: - title: Name type: string + title: Name description: - title: Description type: string + title: Description thumbnail: - title: Thumbnail anyOf: - - maxLength: 2083 - minLength: 0 - type: string + - type: string + maxLength: 2083 + minLength: 1 format: uri - - enum: + - type: string + enum: - '' - type: string + const: '' + title: Thumbnail creationDate: - title: Creationdate - pattern: \d{4}-(12|11|10|0?[1-9])-(31|30|[0-2]?\d)T(2[0-3]|1\d|0?[0-9])(:(\d|[0-5]\d)){2}(\.\d{3})?Z type: string - lastChangeDate: - title: Lastchangedate pattern: \d{4}-(12|11|10|0?[1-9])-(31|30|[0-2]?\d)T(2[0-3]|1\d|0?[0-9])(:(\d|[0-5]\d)){2}(\.\d{3})?Z + title: Creationdate + lastChangeDate: type: string + pattern: \d{4}-(12|11|10|0?[1-9])-(31|30|[0-2]?\d)T(2[0-3]|1\d|0?[0-9])(:(\d|[0-5]\d)){2}(\.\d{3})?Z + title: Lastchangedate workbench: - title: Workbench type: object - additionalProperties: - $ref: '#/components/schemas/Node' + title: Workbench prjOwner: - title: Prjowner type: string format: email + title: Prjowner accessRights: - title: Accessrights - type: object additionalProperties: - $ref: '#/components/schemas/models_library__projects_access__AccessRights' + $ref: '#/components/schemas/AccessRights' + type: object + title: Accessrights tags: - title: Tags - type: array items: type: integer - classifiers: - title: Classifiers type: array + title: Tags + classifiers: items: type: string + type: array + title: Classifiers default: [] state: - $ref: '#/components/schemas/ProjectState' + anyOf: + - $ref: '#/components/schemas/ProjectState' + - type: 'null' ui: - title: Ui anyOf: - $ref: '#/components/schemas/EmptyModel' - - $ref: '#/components/schemas/StudyUI' + - $ref: '#/components/schemas/StudyUI-Output' + - type: 'null' + title: Ui quality: - title: Quality type: object + title: Quality default: {} dev: + anyOf: + - type: object + - type: 'null' title: Dev - type: object permalink: - $ref: '#/components/schemas/ProjectPermalink' + anyOf: + - $ref: '#/components/schemas/ProjectPermalink' + - type: 'null' workspaceId: + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' title: Workspaceid - exclusiveMinimum: true - type: integer - minimum: 0 folderId: + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' title: Folderid - exclusiveMinimum: true - type: integer - minimum: 0 trashedAt: + anyOf: + - type: string + format: date-time + - type: 'null' title: Trashedat - type: string - format: date-time - ProjectGroupGet: - title: ProjectGroupGet - required: - - gid - - read - - write - - delete - - created - - modified type: object + required: + - uuid + - name + - description + - thumbnail + - creationDate + - lastChangeDate + - workbench + - prjOwner + - accessRights + - tags + - dev + - workspaceId + - folderId + - trashedAt + title: ProjectGet + ProjectGroupGet: properties: gid: - title: Gid - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Gid minimum: 0 read: - title: Read type: boolean + title: Read write: - title: Write type: boolean + title: Write delete: - title: Delete type: boolean + title: Delete created: - title: Created type: string format: date-time + title: Created modified: - title: Modified type: string format: date-time - ProjectInputGet: - title: ProjectInputGet - required: - - key - - value - - label + title: Modified type: object + required: + - gid + - read + - write + - delete + - created + - modified + title: ProjectGroupGet + ProjectInputGet: properties: key: - title: Key type: string + format: uuid + title: Key description: Project port's unique identifer. Same as the UUID of the associated port node - format: uuid value: title: Value description: Value assigned to this i/o port label: - title: Label type: string - ProjectInputUpdate: - title: ProjectInputUpdate + title: Label + type: object required: - key - value - type: object + - label + title: ProjectInputGet + ProjectInputUpdate: properties: key: - title: Key type: string + format: uuid + title: Key description: Project port's unique identifer. Same as the UUID of the associated port node - format: uuid value: title: Value description: Value assigned to this i/o port - ProjectIterationItem: - title: ProjectIterationItem - required: - - name - - parent - - iteration_index - - workcopy_project_id - - workcopy_project_url type: object + required: + - key + - value + title: ProjectInputUpdate + ProjectIterationItem: properties: name: - title: Name type: string + title: Name description: Iteration's resource API name parent: - title: Parent - allOf: - - $ref: '#/components/schemas/ParentMetaProjectRef' + $ref: '#/components/schemas/ParentMetaProjectRef' description: Reference to the the meta-project that created this iteration iteration_index: - title: Iteration Index - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Iteration Index minimum: 0 workcopy_project_id: - title: Workcopy Project Id type: string + format: uuid + title: Workcopy Project Id description: ID to this iteration's working copy.A working copy is a real project where this iteration is run - format: uuid workcopy_project_url: - title: Workcopy Project Url + type: string maxLength: 2083 minLength: 1 - type: string - description: reference to a working copy project format: uri - ProjectIterationResultItem: - title: ProjectIterationResultItem + title: Workcopy Project Url + description: reference to a working copy project + type: object required: - name - parent - iteration_index - workcopy_project_id - workcopy_project_url - - results - type: object + title: ProjectIterationItem + ProjectIterationResultItem: properties: name: - title: Name type: string + title: Name description: Iteration's resource API name parent: - title: Parent - allOf: - - $ref: '#/components/schemas/ParentMetaProjectRef' + $ref: '#/components/schemas/ParentMetaProjectRef' description: Reference to the the meta-project that created this iteration iteration_index: - title: Iteration Index - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Iteration Index minimum: 0 workcopy_project_id: - title: Workcopy Project Id type: string + format: uuid + title: Workcopy Project Id description: ID to this iteration's working copy.A working copy is a real project where this iteration is run - format: uuid workcopy_project_url: - title: Workcopy Project Url + type: string maxLength: 2083 minLength: 1 - type: string - description: reference to a working copy project format: uri + title: Workcopy Project Url + description: reference to a working copy project results: $ref: '#/components/schemas/ExtractedResults' - ProjectListItem: - title: ProjectListItem + type: object required: - - uuid - name - - description - - thumbnail - - creationDate - - lastChangeDate - - workbench - - prjOwner - - accessRights - - tags - type: object + - parent + - iteration_index + - workcopy_project_id + - workcopy_project_url + - results + title: ProjectIterationResultItem + ProjectListItem: properties: uuid: - title: Uuid type: string format: uuid + title: Uuid name: - title: Name type: string + title: Name description: - title: Description type: string + title: Description thumbnail: - title: Thumbnail anyOf: - - maxLength: 2083 - minLength: 0 - type: string + - type: string + maxLength: 2083 + minLength: 1 format: uri - - enum: + - type: string + enum: - '' - type: string + const: '' + title: Thumbnail creationDate: - title: Creationdate - pattern: \d{4}-(12|11|10|0?[1-9])-(31|30|[0-2]?\d)T(2[0-3]|1\d|0?[0-9])(:(\d|[0-5]\d)){2}(\.\d{3})?Z type: string - lastChangeDate: - title: Lastchangedate pattern: \d{4}-(12|11|10|0?[1-9])-(31|30|[0-2]?\d)T(2[0-3]|1\d|0?[0-9])(:(\d|[0-5]\d)){2}(\.\d{3})?Z + title: Creationdate + lastChangeDate: type: string + pattern: \d{4}-(12|11|10|0?[1-9])-(31|30|[0-2]?\d)T(2[0-3]|1\d|0?[0-9])(:(\d|[0-5]\d)){2}(\.\d{3})?Z + title: Lastchangedate workbench: - title: Workbench type: object - additionalProperties: - $ref: '#/components/schemas/Node' + title: Workbench prjOwner: - title: Prjowner type: string format: email + title: Prjowner accessRights: - title: Accessrights - type: object additionalProperties: - $ref: '#/components/schemas/models_library__projects_access__AccessRights' + $ref: '#/components/schemas/AccessRights' + type: object + title: Accessrights tags: - title: Tags - type: array items: type: integer - classifiers: - title: Classifiers type: array + title: Tags + classifiers: items: type: string + type: array + title: Classifiers default: [] state: - $ref: '#/components/schemas/ProjectState' + anyOf: + - $ref: '#/components/schemas/ProjectState' + - type: 'null' ui: - title: Ui anyOf: - $ref: '#/components/schemas/EmptyModel' - - $ref: '#/components/schemas/StudyUI' + - $ref: '#/components/schemas/StudyUI-Output' + - type: 'null' + title: Ui quality: - title: Quality type: object + title: Quality default: {} dev: + anyOf: + - type: object + - type: 'null' title: Dev - type: object permalink: - $ref: '#/components/schemas/ProjectPermalink' + anyOf: + - $ref: '#/components/schemas/ProjectPermalink' + - type: 'null' workspaceId: + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' title: Workspaceid - exclusiveMinimum: true - type: integer - minimum: 0 folderId: + anyOf: + - type: integer + exclusiveMinimum: true + minimum: 0 + - type: 'null' title: Folderid - exclusiveMinimum: true - type: integer - minimum: 0 trashedAt: + anyOf: + - type: string + format: date-time + - type: 'null' title: Trashedat - type: string - format: date-time - ProjectLocked: - title: ProjectLocked - required: - - value - - status type: object + required: + - uuid + - name + - description + - thumbnail + - creationDate + - lastChangeDate + - workbench + - prjOwner + - accessRights + - tags + - dev + - workspaceId + - folderId + - trashedAt + title: ProjectListItem + ProjectLocked: properties: value: - title: Value type: boolean + title: Value description: True if the project is locked status: - allOf: - - $ref: '#/components/schemas/ProjectStatus' + $ref: '#/components/schemas/ProjectStatus' description: The status of the project owner: - title: Owner - allOf: + anyOf: - $ref: '#/components/schemas/Owner' + - type: 'null' description: If locked, the user that owns the lock additionalProperties: false - ProjectMetadataGet: - title: ProjectMetadataGet - required: - - projectUuid type: object + required: + - value + - status + title: ProjectLocked + ProjectMetadataGet: properties: projectUuid: - title: Projectuuid type: string format: uuid + title: Projectuuid custom: - title: Custom - type: object additionalProperties: anyOf: - type: boolean - type: integer - type: number - type: string + type: object + title: Custom description: Custom key-value map - ProjectMetadataPortGet: - title: ProjectMetadataPortGet - required: - - key - - kind type: object + required: + - projectUuid + title: ProjectMetadataGet + ProjectMetadataPortGet: properties: key: - title: Key type: string + format: uuid + title: Key description: Project port's unique identifer. Same as the UUID of the associated port node - format: uuid kind: - title: Kind + type: string enum: - input - output - type: string + title: Kind content_schema: + anyOf: + - type: object + - type: 'null' title: Content Schema - type: object description: jsonschema for the port's value. SEE https://json-schema.org/understanding-json-schema/ - ProjectMetadataUpdate: - title: ProjectMetadataUpdate - required: - - custom type: object + required: + - key + - kind + title: ProjectMetadataPortGet + ProjectMetadataUpdate: properties: custom: - title: Custom - type: object additionalProperties: anyOf: - type: boolean - type: integer - type: number - type: string - ProjectOutputGet: - title: ProjectOutputGet - required: - - key - - value - - label + type: object + title: Custom type: object + required: + - custom + title: ProjectMetadataUpdate + ProjectOutputGet: properties: key: - title: Key type: string + format: uuid + title: Key description: Project port's unique identifer. Same as the UUID of the associated port node - format: uuid value: title: Value description: Value assigned to this i/o port label: - title: Label type: string - ProjectPatch: - title: ProjectPatch + title: Label type: object + required: + - key + - value + - label + title: ProjectOutputGet + ProjectPatch: properties: name: + anyOf: + - type: string + - type: 'null' title: Name - type: string description: + anyOf: + - type: string + - type: 'null' title: Description - type: string thumbnail: + anyOf: + - type: string + maxLength: 2083 + minLength: 1 + format: uri + - type: 'null' title: Thumbnail - maxLength: 2083 - minLength: 0 - type: string - format: uri accessRights: + anyOf: + - additionalProperties: + $ref: '#/components/schemas/AccessRights' + type: object + - type: 'null' title: Accessrights - type: object - additionalProperties: - $ref: '#/components/schemas/models_library__projects_access__AccessRights' classifiers: + anyOf: + - items: + type: string + type: array + - type: 'null' title: Classifiers - type: array - items: - type: string dev: + anyOf: + - type: object + - type: 'null' title: Dev - type: object ui: - $ref: '#/components/schemas/StudyUI' + anyOf: + - $ref: '#/components/schemas/StudyUI-Input' + - type: 'null' quality: + anyOf: + - type: object + - type: 'null' title: Quality - type: object - ProjectPermalink: - title: ProjectPermalink - required: - - url - - is_public type: object + title: ProjectPatch + ProjectPermalink: properties: url: - title: Url + type: string maxLength: 2083 minLength: 1 - type: string format: uri + title: Url is_public: - title: Is Public type: boolean - ProjectRunningState: - title: ProjectRunningState - required: - - value + title: Is Public type: object + required: + - url + - is_public + title: ProjectPermalink + ProjectRunningState: properties: value: - allOf: - - $ref: '#/components/schemas/RunningState' + $ref: '#/components/schemas/RunningState' description: The running state of the project additionalProperties: false - ProjectState: - title: ProjectState - required: - - locked - - state type: object + required: + - value + title: ProjectRunningState + ProjectState: properties: locked: - title: Locked - allOf: - - $ref: '#/components/schemas/ProjectLocked' + $ref: '#/components/schemas/ProjectLocked' description: The project lock state state: - title: State - allOf: - - $ref: '#/components/schemas/ProjectRunningState' + $ref: '#/components/schemas/ProjectRunningState' description: The project running state additionalProperties: false + type: object + required: + - locked + - state + title: ProjectState ProjectStatus: - title: ProjectStatus + type: string enum: - CLOSED - CLOSING @@ -11010,419 +12086,397 @@ components: - OPENING - OPENED - MAINTAINING - type: string - description: An enumeration. + title: ProjectStatus ProjectTypeAPI: - title: ProjectTypeAPI + type: string enum: - all - template - user - type: string - description: An enumeration. + title: ProjectTypeAPI ProjectsCommentsAPI: - title: ProjectsCommentsAPI - required: - - comment_id - - project_uuid - - user_id - - contents - - created - - modified - type: object properties: comment_id: - title: Comment Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Comment Id description: Primary key, identifies the comment minimum: 0 project_uuid: - title: Project Uuid type: string - description: project reference for this table format: uuid + title: Project Uuid + description: project reference for this table user_id: - title: User Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: User Id description: user reference for this table minimum: 0 contents: - title: Contents type: string + title: Contents description: Contents of the comment created: - title: Created - type: string - description: Timestamp on creation - format: date-time - modified: - title: Modified type: string - description: Timestamp with last update format: date-time + title: Created + description: Timestamp on creation + modified: + type: string + format: date-time + title: Modified + description: Timestamp with last update additionalProperties: false - PutFolderBodyParams: - title: PutFolderBodyParams - required: - - name - type: object - properties: - name: - title: Name - maxLength: 100 - minLength: 1 - type: string - parentFolderId: - title: Parentfolderid - exclusiveMinimum: true - type: integer - minimum: 0 - additionalProperties: false - PutWalletBodyParams: - title: PutWalletBodyParams - required: - - name - - status type: object + required: + - comment_id + - project_uuid + - user_id + - contents + - created + - modified + title: ProjectsCommentsAPI + PutWalletBodyParams: properties: name: - title: Name type: string + title: Name description: + anyOf: + - type: string + - type: 'null' title: Description - type: string thumbnail: + anyOf: + - type: string + - type: 'null' title: Thumbnail - type: string status: $ref: '#/components/schemas/WalletStatus' - PutWorkspaceBodyParams: - title: PutWorkspaceBodyParams + type: object required: - name - type: object - properties: - name: - title: Name - maxLength: 100 - minLength: 1 - type: string - description: - title: Description - type: string - thumbnail: - title: Thumbnail - type: string - additionalProperties: false + - description + - thumbnail + - status + title: PutWalletBodyParams RegisterBody: - title: RegisterBody - required: - - email - - password - type: object properties: email: - title: Email type: string format: email + title: Email password: - title: Password type: string format: password + title: Password writeOnly: true confirm: + anyOf: + - type: string + format: password + writeOnly: true + - type: 'null' title: Confirm - type: string description: Password confirmation - format: password - writeOnly: true invitation: + anyOf: + - type: string + - type: 'null' title: Invitation - type: string description: Invitation code additionalProperties: false - RegisterPhoneBody: - title: RegisterPhoneBody + type: object required: - email - - phone - type: object + - password + title: RegisterBody + RegisterPhoneBody: properties: email: - title: Email type: string format: email + title: Email phone: - title: Phone type: string + title: Phone description: Phone number E.164, needed on the deployments with 2FA additionalProperties: false - RegisterPhoneNextPage: - title: RegisterPhoneNextPage - required: - - name - - message type: object + required: + - email + - phone + title: RegisterPhoneBody + RegisterPhoneNextPage: properties: name: - title: Name type: string + title: Name description: Code name to the front-end page. Ideally a PageStr parameters: - $ref: '#/components/schemas/_PageParams' + anyOf: + - $ref: '#/components/schemas/_PageParams' + - type: 'null' logger: - title: Logger type: string + title: Logger default: user deprecated: true level: - title: Level + type: string enum: - INFO - WARNING - ERROR - type: string + title: Level default: INFO message: - title: Message type: string - description: 'This is the body of a 2XX response to pass the front-end - - what kind of page shall be display next and some information about it - - - An analogous structure is used in the redirects (see create_redirect_response) - but - - using a path+query in the fragment of the URL' - ReplaceWalletAutoRecharge: - title: ReplaceWalletAutoRecharge - required: - - enabled - - paymentMethodId - - topUpAmountInUsd + title: Message type: object + required: + - name + - message + title: RegisterPhoneNextPage + ReplaceWalletAutoRecharge: properties: enabled: - title: Enabled type: boolean + title: Enabled paymentMethodId: - title: Paymentmethodid + type: string maxLength: 100 minLength: 1 - type: string + title: Paymentmethodid topUpAmountInUsd: + anyOf: + - type: number + minimum: 0.0 + - type: string title: Topupamountinusd - minimum: 0.0 - type: number monthlyLimitInUsd: + anyOf: + - type: number + minimum: 0.0 + - type: string + - type: 'null' title: Monthlylimitinusd - minimum: 0.0 - type: number - RepoApiModel: - title: RepoApiModel - required: - - project_uuid - - url type: object + required: + - enabled + - paymentMethodId + - topUpAmountInUsd + - monthlyLimitInUsd + title: ReplaceWalletAutoRecharge + RepoApiModel: properties: project_uuid: - title: Project Uuid type: string format: uuid + title: Project Uuid url: - title: Url + type: string maxLength: 2083 minLength: 1 - type: string format: uri - ResearchResource: - title: ResearchResource - required: - - rrid - - name - - description + title: Url type: object + required: + - project_uuid + - url + title: RepoApiModel + ResearchResource: properties: rrid: - title: Rrid - pattern: ^(RRID:)([^_\s]{1,30})_(\S{1,30})$ type: string + pattern: ^(RRID:)([^_\s]{1,30})_(\S{1,30})$ + title: Rrid description: Unique identifier used as classifier, i.e. to tag studies and services name: - title: Name type: string + title: Name description: - title: Description type: string - Resend2faBody: - title: Resend2faBody - required: - - email + title: Description type: object + required: + - rrid + - name + - description + title: ResearchResource + Resend2faBody: properties: email: - title: Email type: string - description: User email (identifier) format: email + title: Email + description: User email (identifier) via: - title: Via + type: string enum: - SMS - Email - type: string + title: Via default: SMS additionalProperties: false - ResetPasswordBody: - title: ResetPasswordBody + type: object required: - email - type: object + title: Resend2faBody + ResetPasswordBody: properties: email: - title: Email type: string + title: Email additionalProperties: false - ResetPasswordConfirmation: - title: ResetPasswordConfirmation - required: - - password - - confirm type: object + required: + - email + title: ResetPasswordBody + ResetPasswordConfirmation: properties: password: - title: Password type: string format: password + title: Password writeOnly: true confirm: - title: Confirm type: string format: password + title: Confirm writeOnly: true additionalProperties: false - ResourceHit: - title: ResourceHit - required: - - rid - - name type: object + required: + - password + - confirm + title: ResetPasswordConfirmation + ResourceHit: properties: rid: - title: Rid type: string + title: Rid name: - title: Name type: string - ResourceValue: - title: ResourceValue - required: - - limit - - reservation + title: Name type: object + required: + - rid + - name + title: ResourceHit + ResourceValue: properties: limit: - title: Limit anyOf: - type: integer - type: number - type: string + title: Limit reservation: - title: Reservation anyOf: - type: integer - type: number - type: string - RunningDynamicServiceDetails: - title: RunningDynamicServiceDetails - required: - - service_key - - service_version - - user_id - - project_id - - service_uuid - - service_host - - service_port - - service_state + title: Reservation type: object + required: + - limit + - reservation + title: ResourceValue + RunningDynamicServiceDetails: properties: service_key: - title: Service Key - pattern: ^simcore/services/dynamic/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ type: string + pattern: ^simcore/services/dynamic/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + title: Service Key description: distinctive name for the node based on the docker registry path service_version: - title: Service Version - pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ type: string + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + title: Service Version description: semantic version number of the node user_id: - title: User Id - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: User Id minimum: 0 project_id: - title: Project Id type: string format: uuid + title: Project Id service_uuid: - title: Service Uuid type: string format: uuid + title: Service Uuid service_basepath: + anyOf: + - type: string + format: path + - type: 'null' title: Service Basepath - type: string description: predefined path where the dynamic service should be served. If empty, the service shall use the root endpoint. - format: path boot_type: - allOf: - - $ref: '#/components/schemas/ServiceBootType' + $ref: '#/components/schemas/ServiceBootType' description: Describes how the dynamic services was started (legacy=V0, modern=V2).Since legacy services do not have this label it defaults to V0. default: V0 service_host: - title: Service Host type: string + title: Service Host description: the service swarm internal host name service_port: - title: Service Port + type: integer exclusiveMaximum: true exclusiveMinimum: true - type: integer + title: Service Port description: the service swarm internal port maximum: 65535 minimum: 0 published_port: + anyOf: + - type: integer + exclusiveMaximum: true + exclusiveMinimum: true + maximum: 65535 + minimum: 0 + - type: 'null' title: Published Port - exclusiveMaximum: true - exclusiveMinimum: true - type: integer description: the service swarm published port if any deprecated: true - maximum: 65535 - minimum: 0 entry_point: + anyOf: + - type: string + - type: 'null' title: Entry Point - type: string description: if empty the service entrypoint is on the root endpoint. deprecated: true service_state: - allOf: - - $ref: '#/components/schemas/ServiceState' + $ref: '#/components/schemas/ServiceState' description: service current state service_message: + anyOf: + - type: string + - type: 'null' title: Service Message - type: string description: additional information related to service state + type: object + required: + - service_key + - service_version + - user_id + - project_id + - service_uuid + - service_host + - service_port + - service_state + title: RunningDynamicServiceDetails RunningState: - title: RunningState + type: string enum: - UNKNOWN - PUBLISHED @@ -11434,452 +12488,482 @@ components: - FAILED - ABORTED - WAITING_FOR_CLUSTER - type: string + title: RunningState description: 'State of execution of a project''s computational workflow SEE StateType for task state' Scheduler: - title: Scheduler - required: - - status - type: object properties: status: - title: Status type: string + title: Status description: The running status of the scheduler workers: + anyOf: + - additionalProperties: + $ref: '#/components/schemas/Worker' + type: object + - type: 'null' title: Workers - type: object - additionalProperties: - $ref: '#/components/schemas/Worker' - SelectBox: - title: SelectBox - required: - - structure type: object + required: + - status + title: Scheduler + SelectBox: properties: structure: - title: Structure - minItems: 1 - type: array items: $ref: '#/components/schemas/Structure' + type: array + minItems: 1 + title: Structure additionalProperties: false + type: object + required: + - structure + title: SelectBox ServiceBootType: - title: ServiceBootType + type: string enum: - V0 - V2 - type: string - description: An enumeration. + title: ServiceBootType ServiceGet: - title: ServiceGet - required: - - key - - title - - description - - thumbnail - - view_url - type: object properties: key: - title: Key - pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ type: string + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + title: Key description: Service key ID title: - title: Title type: string + title: Title description: Service name for display description: - title: Description type: string + title: Description description: Long description of the service thumbnail: - title: Thumbnail + type: string maxLength: 2083 minLength: 1 - type: string - description: Url to service thumbnail format: uri + title: Thumbnail + description: Url to service thumbnail file_extensions: - title: File Extensions - type: array items: type: string + type: array + title: File Extensions description: File extensions that this service can process view_url: - title: View Url + type: string maxLength: 2083 minLength: 1 - type: string - description: Redirection to open a service in osparc (see /view) format: uri + title: View Url + description: Redirection to open a service in osparc (see /view) + type: object + required: + - key + - title + - description + - thumbnail + - view_url + title: ServiceGet example: - key: simcore/services/dynamic/sim4life - title: Sim4Life Mattermost description: It is also sim4life for the web - thumbnail: https://via.placeholder.com/170x120.png file_extensions: - smash - h5 + key: simcore/services/dynamic/sim4life + thumbnail: https://via.placeholder.com/170x120.png + title: Sim4Life Mattermost view_url: https://host.com/view?viewer_key=simcore/services/dynamic/raw-graphs&viewer_version=1.2.3 ServiceGroupAccessRightsV2: - title: ServiceGroupAccessRightsV2 - type: object properties: execute: - title: Execute type: boolean + title: Execute default: false write: - title: Write type: boolean + title: Write default: false additionalProperties: false - ServiceInputGet: - title: ServiceInputGet - required: - - label - - description - - type - - keyId type: object + title: ServiceGroupAccessRightsV2 + ServiceInputGet: properties: unitLong: + anyOf: + - type: string + - type: 'null' title: Unitlong - type: string description: Long name of the unit for display (html-compatible), if available unitShort: + anyOf: + - type: string + - type: 'null' title: Unitshort - type: string description: Short name for the unit for display (html-compatible), if available displayOrder: + anyOf: + - type: number + - type: 'null' title: Displayorder - type: number description: 'DEPRECATED: new display order is taken from the item position. This will be removed.' deprecated: true label: - title: Label type: string + title: Label description: short name for the property - example: Age description: - title: Description type: string + title: Description description: description of the property - example: Age in seconds since 1970 type: - title: Type - pattern: ^(number|integer|boolean|string|ref_contentSchema|data:([^/\s,]+/[^/\s,]+|\[[^/\s,]+/[^/\s,]+(,[^/\s]+/[^/,\s]+)*\]))$ type: string + pattern: ^(number|integer|boolean|string|ref_contentSchema|data:([^/\s,]+/[^/\s,]+|\[[^/\s,]+/[^/\s,]+(,[^/\s]+/[^/,\s]+)*\]))$ + title: Type description: data type expected on this input glob matching for data type is allowed contentSchema: + anyOf: + - type: object + - type: 'null' title: Contentschema - type: object description: jsonschema of this input/output. Required when type='ref_contentSchema' fileToKeyMap: + anyOf: + - type: object + - type: 'null' title: Filetokeymap - type: object - additionalProperties: - pattern: ^[-_a-zA-Z0-9]+$ - type: string description: Place the data associated with the named keys in files unit: + anyOf: + - type: string + - type: 'null' title: Unit - type: string description: Units, when it refers to a physical quantity deprecated: true defaultValue: - title: Defaultvalue anyOf: - type: boolean - type: integer - type: number - type: string + - type: 'null' + title: Defaultvalue deprecated: true widget: - title: Widget - allOf: + anyOf: - $ref: '#/components/schemas/Widget' + - type: 'null' description: custom widget to use instead of the default one determined from the data-type keyId: - title: Keyid - pattern: ^[-_a-zA-Z0-9]+$ type: string + pattern: ^[-_a-zA-Z0-9]+$ + title: Keyid description: Unique name identifier for this input additionalProperties: false + type: object + required: + - label + - description + - type + - keyId + title: ServiceInputGet description: Extends fields of api_schemas_catalog.services.ServiceGet.outputs[*] example: + defaultValue: 0 + description: Time to wait before completion displayOrder: 2 + keyId: input_2 label: Sleep Time - description: Time to wait before completion type: number - defaultValue: 0 unit: second + unitLong: seconds + unitShort: sec widget: - type: TextArea details: minHeight: 1 - keyId: input_2 - unitLong: seconds - unitShort: sec + type: TextArea ServiceKeyVersion: - title: ServiceKeyVersion - required: - - key - - version - type: object properties: key: - title: Key - pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ type: string + pattern: ^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$ + title: Key description: distinctive name for the node based on the docker registry path version: - title: Version - pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ type: string + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + title: Version description: service version number + type: object + required: + - key + - version + title: ServiceKeyVersion description: Service `key-version` pair uniquely identifies a service ServiceOutputGet: - title: ServiceOutputGet - required: - - label - - description - - type - - keyId - type: object properties: unitLong: + anyOf: + - type: string + - type: 'null' title: Unitlong - type: string description: Long name of the unit for display (html-compatible), if available unitShort: + anyOf: + - type: string + - type: 'null' title: Unitshort - type: string description: Short name for the unit for display (html-compatible), if available displayOrder: + anyOf: + - type: number + - type: 'null' title: Displayorder - type: number description: 'DEPRECATED: new display order is taken from the item position. This will be removed.' deprecated: true label: - title: Label type: string + title: Label description: short name for the property - example: Age description: - title: Description type: string + title: Description description: description of the property - example: Age in seconds since 1970 type: - title: Type - pattern: ^(number|integer|boolean|string|ref_contentSchema|data:([^/\s,]+/[^/\s,]+|\[[^/\s,]+/[^/\s,]+(,[^/\s]+/[^/,\s]+)*\]))$ type: string + pattern: ^(number|integer|boolean|string|ref_contentSchema|data:([^/\s,]+/[^/\s,]+|\[[^/\s,]+/[^/\s,]+(,[^/\s]+/[^/,\s]+)*\]))$ + title: Type description: data type expected on this input glob matching for data type is allowed contentSchema: + anyOf: + - type: object + - type: 'null' title: Contentschema - type: object description: jsonschema of this input/output. Required when type='ref_contentSchema' fileToKeyMap: + anyOf: + - type: object + - type: 'null' title: Filetokeymap - type: object - additionalProperties: - pattern: ^[-_a-zA-Z0-9]+$ - type: string description: Place the data associated with the named keys in files unit: + anyOf: + - type: string + - type: 'null' title: Unit - type: string description: Units, when it refers to a physical quantity deprecated: true widget: - title: Widget - allOf: + anyOf: - $ref: '#/components/schemas/Widget' + - type: 'null' description: custom widget to use instead of the default one determined from the data-type deprecated: true keyId: - title: Keyid - pattern: ^[-_a-zA-Z0-9]+$ type: string + pattern: ^[-_a-zA-Z0-9]+$ + title: Keyid description: Unique name identifier for this input additionalProperties: false + type: object + required: + - label + - description + - type + - keyId + title: ServiceOutputGet description: Extends fields of api_schemas_catalog.services.ServiceGet.outputs[*] example: + description: Time the service waited before completion displayOrder: 2 + keyId: output_2 label: Time Slept - description: Time the service waited before completion type: number unit: second unitLong: seconds unitShort: sec - keyId: output_2 ServicePricingPlanGet: - title: ServicePricingPlanGet - required: - - pricingPlanId - - displayName - - description - - classification - - createdAt - - pricingPlanKey - - pricingUnits - type: object properties: pricingPlanId: - title: Pricingplanid - exclusiveMinimum: true type: integer + exclusiveMinimum: true + title: Pricingplanid minimum: 0 displayName: - title: Displayname type: string + title: Displayname description: - title: Description type: string + title: Description classification: $ref: '#/components/schemas/PricingPlanClassification' createdAt: - title: Createdat type: string format: date-time + title: Createdat pricingPlanKey: - title: Pricingplankey type: string + title: Pricingplankey pricingUnits: - title: Pricingunits - type: array items: $ref: '#/components/schemas/PricingUnitGet' - ServiceRelease: - title: ServiceRelease - required: - - version + type: array + title: Pricingunits type: object + required: + - pricingPlanId + - displayName + - description + - classification + - createdAt + - pricingPlanKey + - pricingUnits + title: ServicePricingPlanGet + ServiceRelease: properties: version: - title: Version - pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ type: string + pattern: ^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$ + title: Version versionDisplay: + anyOf: + - type: string + - type: 'null' title: Versiondisplay - type: string description: If None, then display `version` released: + anyOf: + - type: string + format: date-time + - type: 'null' title: Released - type: string description: When provided, it indicates the release timestamp - format: date-time retired: + anyOf: + - type: string + format: date-time + - type: 'null' title: Retired - type: string description: 'whether this service is planned to be retired. If None, the service is still active. If now Path: oas_path: Path = webserver_resources.get_path(f"api/{api_version_dir}/openapi.yaml") return oas_path - - -@lru_cache # required to boost tests speed, gains 3.5s per test -def load_openapi_specs(spec_path: Path | None = None) -> OpenApiSpecs: - if spec_path is None: - spec_path = get_openapi_specs_path() - - with spec_path.open() as fh: - spec_dict = yaml.safe_load(fh) - specs: OpenApiSpecs = openapi_core.create_spec(spec_dict, spec_path.as_uri()) - - return specs diff --git a/services/web/server/src/simcore_service_webserver/workspaces/_exceptions_handlers.py b/services/web/server/src/simcore_service_webserver/workspaces/_exceptions_handlers.py new file mode 100644 index 00000000000..f6470f461f7 --- /dev/null +++ b/services/web/server/src/simcore_service_webserver/workspaces/_exceptions_handlers.py @@ -0,0 +1,53 @@ +import logging + +from servicelib.aiohttp import status + +from ..exceptions_handlers import ( + ExceptionToHttpErrorMap, + HttpErrorInfo, + create_exception_handlers_decorator, +) +from ..projects.exceptions import ( + BaseProjectError, + ProjectRunningConflictError, + ProjectStoppingError, +) +from .errors import ( + WorkspaceAccessForbiddenError, + WorkspaceGroupNotFoundError, + WorkspaceNotFoundError, + WorkspacesValueError, +) + +_logger = logging.getLogger(__name__) + + +_TO_HTTP_ERROR_MAP: ExceptionToHttpErrorMap = { + WorkspaceGroupNotFoundError: HttpErrorInfo( + status.HTTP_404_NOT_FOUND, + "Workspace {workspace_id} group {group_id} not found.", + ), + WorkspaceAccessForbiddenError: HttpErrorInfo( + status.HTTP_403_FORBIDDEN, + "Does not have access to this workspace", + ), + WorkspaceNotFoundError: HttpErrorInfo( + status.HTTP_404_NOT_FOUND, + "Workspace not found. {reason}", + ), + # Trashing + ProjectRunningConflictError: HttpErrorInfo( + status.HTTP_409_CONFLICT, + "One or more studies in this workspace are in use and cannot be trashed. Please stop all services first and try again", + ), + ProjectStoppingError: HttpErrorInfo( + status.HTTP_503_SERVICE_UNAVAILABLE, + "Something went wrong while stopping running services in studies within this workspace before trashing. Aborting trash.", + ), +} + + +handle_plugin_requests_exceptions = create_exception_handlers_decorator( + exceptions_catch=(BaseProjectError, WorkspacesValueError), + exc_to_status_map=_TO_HTTP_ERROR_MAP, +) diff --git a/services/web/server/src/simcore_service_webserver/workspaces/_groups_handlers.py b/services/web/server/src/simcore_service_webserver/workspaces/_groups_handlers.py index 292c4ed1615..599305c3f81 100644 --- a/services/web/server/src/simcore_service_webserver/workspaces/_groups_handlers.py +++ b/services/web/server/src/simcore_service_webserver/workspaces/_groups_handlers.py @@ -1,49 +1,29 @@ -""" Handlers for project comments operations - -""" - -import functools import logging from aiohttp import web -from models_library.users import GroupID -from models_library.workspaces import WorkspaceID -from pydantic import BaseModel, ConfigDict from servicelib.aiohttp import status from servicelib.aiohttp.requests_validation import ( parse_request_body_as, parse_request_path_parameters_as, ) -from servicelib.aiohttp.typing_extension import Handler from .._meta import api_version_prefix as VTAG from ..login.decorators import login_required -from ..models import RequestContext from ..security.decorators import permission_required from ..utils_aiohttp import envelope_json_response from . import _groups_api +from ._exceptions_handlers import handle_plugin_requests_exceptions from ._groups_api import WorkspaceGroupGet -from ._workspaces_handlers import WorkspacesPathParams -from .errors import WorkspaceAccessForbiddenError, WorkspaceGroupNotFoundError +from ._models import ( + WorkspacesGroupsBodyParams, + WorkspacesGroupsPathParams, + WorkspacesPathParams, + WorkspacesRequestContext, +) _logger = logging.getLogger(__name__) -def _handle_workspaces_groups_exceptions(handler: Handler): - @functools.wraps(handler) - async def wrapper(request: web.Request) -> web.StreamResponse: - try: - return await handler(request) - - except WorkspaceGroupNotFoundError as exc: - raise web.HTTPNotFound(reason=f"{exc}") from exc - - except WorkspaceAccessForbiddenError as exc: - raise web.HTTPForbidden(reason=f"{exc}") from exc - - return wrapper - - # # workspaces groups COLLECTION ------------------------- # @@ -51,30 +31,17 @@ async def wrapper(request: web.Request) -> web.StreamResponse: routes = web.RouteTableDef() -class _WorkspacesGroupsPathParams(BaseModel): - workspace_id: WorkspaceID - group_id: GroupID - model_config = ConfigDict(extra="forbid") - - -class _WorkspacesGroupsBodyParams(BaseModel): - read: bool - write: bool - delete: bool - model_config = ConfigDict(extra="forbid") - - @routes.post( f"/{VTAG}/workspaces/{{workspace_id}}/groups/{{group_id}}", name="create_workspace_group", ) @login_required @permission_required("workspaces.*") -@_handle_workspaces_groups_exceptions +@handle_plugin_requests_exceptions async def create_workspace_group(request: web.Request): - req_ctx = RequestContext.model_validate(request) - path_params = parse_request_path_parameters_as(_WorkspacesGroupsPathParams, request) - body_params = await parse_request_body_as(_WorkspacesGroupsBodyParams, request) + req_ctx = WorkspacesRequestContext.model_validate(request) + path_params = parse_request_path_parameters_as(WorkspacesGroupsPathParams, request) + body_params = await parse_request_body_as(WorkspacesGroupsBodyParams, request) workspace_groups: WorkspaceGroupGet = await _groups_api.create_workspace_group( request.app, @@ -93,12 +60,12 @@ async def create_workspace_group(request: web.Request): @routes.get(f"/{VTAG}/workspaces/{{workspace_id}}/groups", name="list_workspace_groups") @login_required @permission_required("workspaces.*") -@_handle_workspaces_groups_exceptions +@handle_plugin_requests_exceptions async def list_workspace_groups(request: web.Request): - req_ctx = RequestContext.model_validate(request) + req_ctx = WorkspacesRequestContext.model_validate(request) path_params = parse_request_path_parameters_as(WorkspacesPathParams, request) - workspaces: list[ + workspaces_groups: list[ WorkspaceGroupGet ] = await _groups_api.list_workspace_groups_by_user_and_workspace( request.app, @@ -107,7 +74,7 @@ async def list_workspace_groups(request: web.Request): product_name=req_ctx.product_name, ) - return envelope_json_response(workspaces, web.HTTPOk) + return envelope_json_response(workspaces_groups) @routes.put( @@ -116,13 +83,13 @@ async def list_workspace_groups(request: web.Request): ) @login_required @permission_required("workspaces.*") -@_handle_workspaces_groups_exceptions +@handle_plugin_requests_exceptions async def replace_workspace_group(request: web.Request): - req_ctx = RequestContext.model_validate(request) - path_params = parse_request_path_parameters_as(_WorkspacesGroupsPathParams, request) - body_params = await parse_request_body_as(_WorkspacesGroupsBodyParams, request) + req_ctx = WorkspacesRequestContext.model_validate(request) + path_params = parse_request_path_parameters_as(WorkspacesGroupsPathParams, request) + body_params = await parse_request_body_as(WorkspacesGroupsBodyParams, request) - return await _groups_api.update_workspace_group( + workspace_group = await _groups_api.update_workspace_group( app=request.app, user_id=req_ctx.user_id, workspace_id=path_params.workspace_id, @@ -132,6 +99,7 @@ async def replace_workspace_group(request: web.Request): delete=body_params.delete, product_name=req_ctx.product_name, ) + return envelope_json_response(workspace_group) @routes.delete( @@ -140,10 +108,10 @@ async def replace_workspace_group(request: web.Request): ) @login_required @permission_required("workspaces.*") -@_handle_workspaces_groups_exceptions +@handle_plugin_requests_exceptions async def delete_workspace_group(request: web.Request): - req_ctx = RequestContext.model_validate(request) - path_params = parse_request_path_parameters_as(_WorkspacesGroupsPathParams, request) + req_ctx = WorkspacesRequestContext.model_validate(request) + path_params = parse_request_path_parameters_as(WorkspacesGroupsPathParams, request) await _groups_api.delete_workspace_group( app=request.app, diff --git a/services/web/server/src/simcore_service_webserver/workspaces/_models.py b/services/web/server/src/simcore_service_webserver/workspaces/_models.py new file mode 100644 index 00000000000..fec1d7d8fcb --- /dev/null +++ b/services/web/server/src/simcore_service_webserver/workspaces/_models.py @@ -0,0 +1,73 @@ +import logging + +from models_library.basic_types import IDStr +from models_library.rest_base import RequestParameters, StrictRequestParameters +from models_library.rest_filters import Filters, FiltersQueryParameters +from models_library.rest_ordering import ( + OrderBy, + OrderDirection, + create_ordering_query_model_classes, +) +from models_library.rest_pagination import PageQueryParameters +from models_library.trash import RemoveQueryParams +from models_library.users import GroupID, UserID +from models_library.workspaces import WorkspaceID +from pydantic import BaseModel, ConfigDict, Field +from servicelib.request_keys import RQT_USERID_KEY + +from .._constants import RQ_PRODUCT_KEY + +_logger = logging.getLogger(__name__) + + +class WorkspacesRequestContext(RequestParameters): + user_id: UserID = Field(..., alias=RQT_USERID_KEY) # type: ignore[literal-required] + product_name: str = Field(..., alias=RQ_PRODUCT_KEY) # type: ignore[literal-required] + + +class WorkspacesPathParams(StrictRequestParameters): + workspace_id: WorkspaceID + + +_WorkspacesListOrderQueryParams: type[ + RequestParameters +] = create_ordering_query_model_classes( + ordering_fields={ + "modified_at", + "name", + }, + default=OrderBy(field=IDStr("modified_at"), direction=OrderDirection.DESC), + ordering_fields_api_to_column_map={"modified_at": "modified"}, +) + + +class WorkspacesFilters(Filters): + trashed: bool | None = Field( + default=False, + description="Set to true to list trashed, false to list non-trashed (default), None to list all", + ) + + +class WorkspacesListQueryParams( + PageQueryParameters, + FiltersQueryParameters[WorkspacesFilters], + _WorkspacesListOrderQueryParams, # type: ignore[misc, valid-type] +): + ... + + +class WorkspacesGroupsPathParams(BaseModel): + workspace_id: WorkspaceID + group_id: GroupID + model_config = ConfigDict(extra="forbid") + + +class WorkspacesGroupsBodyParams(BaseModel): + read: bool + write: bool + delete: bool + model_config = ConfigDict(extra="forbid") + + +class WorkspaceTrashQueryParams(RemoveQueryParams): + ... diff --git a/services/web/server/src/simcore_service_webserver/workspaces/_trash_api.py b/services/web/server/src/simcore_service_webserver/workspaces/_trash_api.py new file mode 100644 index 00000000000..18c3ae93b88 --- /dev/null +++ b/services/web/server/src/simcore_service_webserver/workspaces/_trash_api.py @@ -0,0 +1,122 @@ +import logging + +import arrow +from aiohttp import web +from models_library.folders import FolderID +from models_library.products import ProductName +from models_library.projects import ProjectID +from models_library.users import UserID +from models_library.workspaces import WorkspaceID, WorkspaceUpdateDB +from simcore_postgres_database.utils_repos import transaction_context + +from ..db.plugin import get_asyncpg_engine +from ..folders._trash_api import trash_folder, untrash_folder +from ..projects._trash_api import trash_project, untrash_project +from ._workspaces_api import check_user_workspace_access +from ._workspaces_db import update_workspace + +_logger = logging.getLogger(__name__) + + +async def _check_exists_and_access( + app: web.Application, + *, + product_name: ProductName, + user_id: UserID, + workspace_id: WorkspaceID, +): + await check_user_workspace_access( + app=app, + user_id=user_id, + workspace_id=workspace_id, + product_name=product_name, + permission="delete", + ) + + +async def trash_workspace( + app: web.Application, + *, + product_name: ProductName, + user_id: UserID, + workspace_id: WorkspaceID, + force_stop_first: bool, +): + await _check_exists_and_access( + app, product_name=product_name, user_id=user_id, workspace_id=workspace_id + ) + + trashed_at = arrow.utcnow().datetime + + async with transaction_context(get_asyncpg_engine(app)) as connection: + # EXPLICIT trash + await update_workspace( + app, + connection, + product_name=product_name, + workspace_id=workspace_id, + updates=WorkspaceUpdateDB(trashed=trashed_at, trashed_by=user_id), + ) + + # IMPLICIT trash + child_folders: list[FolderID] = [] # TODO: find children. Check with MD + + for folder_id in child_folders: + await trash_folder( + app, + product_name=product_name, + user_id=user_id, + folder_id=folder_id, + force_stop_first=force_stop_first, + ) + + child_projects: list[ProjectID] = [] # TODO: find children. Check with MD + + for project_id in child_projects: + await trash_project( + app, + product_name=product_name, + user_id=user_id, + project_id=project_id, + force_stop_first=force_stop_first, + explicit=False, + ) + + +async def untrash_workspace( + app: web.Application, + *, + product_name: ProductName, + user_id: UserID, + workspace_id: WorkspaceID, +): + await _check_exists_and_access( + app, product_name=product_name, user_id=user_id, workspace_id=workspace_id + ) + + async with transaction_context(get_asyncpg_engine(app)) as connection: + # EXPLICIT UNtrash + await update_workspace( + app, + connection, + product_name=product_name, + workspace_id=workspace_id, + updates=WorkspaceUpdateDB(trashed=None, trashed_by=None), + ) + + child_folders: list[FolderID] = [] # TODO: find children. Check with MD + + for folder_id in child_folders: + await untrash_folder( + app, + product_name=product_name, + user_id=user_id, + folder_id=folder_id, + ) + + child_projects: list[ProjectID] = [] # TODO: find children. Check with MD + + for project_id in child_projects: + await untrash_project( + app, product_name=product_name, user_id=user_id, project_id=project_id + ) diff --git a/services/web/server/src/simcore_service_webserver/workspaces/_trash_handlers.py b/services/web/server/src/simcore_service_webserver/workspaces/_trash_handlers.py new file mode 100644 index 00000000000..b2d3a4b41a8 --- /dev/null +++ b/services/web/server/src/simcore_service_webserver/workspaces/_trash_handlers.py @@ -0,0 +1,66 @@ +import logging + +from aiohttp import web +from servicelib.aiohttp import status +from servicelib.aiohttp.requests_validation import ( + parse_request_path_parameters_as, + parse_request_query_parameters_as, +) + +from .._meta import API_VTAG as VTAG +from ..application_settings_utils import requires_dev_feature_enabled +from ..login.decorators import get_user_id, login_required +from ..products.api import get_product_name +from ..security.decorators import permission_required +from . import _trash_api +from ._exceptions_handlers import handle_plugin_requests_exceptions +from ._models import WorkspacesPathParams, WorkspaceTrashQueryParams + +_logger = logging.getLogger(__name__) + + +routes = web.RouteTableDef() + + +@routes.post(f"/{VTAG}/workspaces/{{workspace_id}}:trash", name="trash_workspace") +@requires_dev_feature_enabled +@login_required +@permission_required("workspaces.*") +@handle_plugin_requests_exceptions +async def trash_workspace(request: web.Request): + user_id = get_user_id(request) + product_name = get_product_name(request) + path_params = parse_request_path_parameters_as(WorkspacesPathParams, request) + query_params: WorkspaceTrashQueryParams = parse_request_query_parameters_as( + WorkspaceTrashQueryParams, request + ) + + await _trash_api.trash_workspace( + request.app, + product_name=product_name, + user_id=user_id, + workspace_id=path_params.workspace_id, + force_stop_first=query_params.force, + ) + + return web.json_response(status=status.HTTP_204_NO_CONTENT) + + +@routes.post(f"/{VTAG}/workspaces/{{workspace_id}}:untrash", name="untrash_workspace") +@requires_dev_feature_enabled +@login_required +@permission_required("workspaces.*") +@handle_plugin_requests_exceptions +async def untrash_workspace(request: web.Request): + user_id = get_user_id(request) + product_name = get_product_name(request) + path_params = parse_request_path_parameters_as(WorkspacesPathParams, request) + + await _trash_api.untrash_workspace( + request.app, + product_name=product_name, + user_id=user_id, + workspace_id=path_params.workspace_id, + ) + + return web.json_response(status=status.HTTP_204_NO_CONTENT) diff --git a/services/web/server/src/simcore_service_webserver/workspaces/_workspaces_api.py b/services/web/server/src/simcore_service_webserver/workspaces/_workspaces_api.py index a645037f5a4..3fd6633bb06 100644 --- a/services/web/server/src/simcore_service_webserver/workspaces/_workspaces_api.py +++ b/services/web/server/src/simcore_service_webserver/workspaces/_workspaces_api.py @@ -10,7 +10,11 @@ from models_library.products import ProductName from models_library.rest_ordering import OrderBy from models_library.users import UserID -from models_library.workspaces import UserWorkspaceAccessRightsDB, WorkspaceID +from models_library.workspaces import ( + UserWorkspaceAccessRightsDB, + WorkspaceID, + WorkspaceUpdateDB, +) from pydantic import NonNegativeInt from ..projects._db_utils import PermissionStr @@ -21,8 +25,24 @@ _logger = logging.getLogger(__name__) +def _to_api_model(workspace_db: UserWorkspaceAccessRightsDB) -> WorkspaceGet: + return WorkspaceGet( + workspace_id=workspace_db.workspace_id, + name=workspace_db.name, + description=workspace_db.description, + thumbnail=workspace_db.thumbnail, + created_at=workspace_db.created, + modified_at=workspace_db.modified, + trashed_at=workspace_db.trashed, + trashed_by=workspace_db.trashed_by if workspace_db.trashed else None, + my_access_rights=workspace_db.my_access_rights, + access_rights=workspace_db.access_rights, + ) + + async def create_workspace( app: web.Application, + *, user_id: UserID, name: str, description: str | None, @@ -45,20 +65,12 @@ async def create_workspace( workspace_id=created_workspace_db.workspace_id, product_name=product_name, ) - return WorkspaceGet( - workspace_id=workspace_db.workspace_id, - name=workspace_db.name, - description=workspace_db.description, - thumbnail=workspace_db.thumbnail, - created_at=workspace_db.created, - modified_at=workspace_db.modified, - my_access_rights=workspace_db.my_access_rights, - access_rights=workspace_db.access_rights, - ) + return _to_api_model(workspace_db) async def get_workspace( app: web.Application, + *, user_id: UserID, workspace_id: WorkspaceID, product_name: ProductName, @@ -70,22 +82,15 @@ async def get_workspace( product_name=product_name, permission="read", ) - return WorkspaceGet( - workspace_id=workspace_db.workspace_id, - name=workspace_db.name, - description=workspace_db.description, - thumbnail=workspace_db.thumbnail, - created_at=workspace_db.created, - modified_at=workspace_db.modified, - my_access_rights=workspace_db.my_access_rights, - access_rights=workspace_db.access_rights, - ) + return _to_api_model(workspace_db) async def list_workspaces( app: web.Application, + *, user_id: UserID, product_name: ProductName, + filter_trashed: bool | None, offset: NonNegativeInt, limit: int, order_by: OrderBy, @@ -94,38 +99,27 @@ async def list_workspaces( app, user_id=user_id, product_name=product_name, + filter_trashed=filter_trashed, offset=offset, limit=limit, order_by=order_by, ) return WorkspaceGetPage( - items=[ - WorkspaceGet( - workspace_id=workspace.workspace_id, - name=workspace.name, - description=workspace.description, - thumbnail=workspace.thumbnail, - created_at=workspace.created, - modified_at=workspace.modified, - my_access_rights=workspace.my_access_rights, - access_rights=workspace.access_rights, - ) - for workspace in workspaces - ], + items=[_to_api_model(workspace_db) for workspace_db in workspaces], total=total_count, ) async def update_workspace( app: web.Application, + *, + product_name: ProductName, user_id: UserID, workspace_id: WorkspaceID, - name: str, - description: str | None, - thumbnail: str | None, - product_name: ProductName, + **updates, ) -> WorkspaceGet: + await check_user_workspace_access( app=app, user_id=user_id, @@ -136,10 +130,8 @@ async def update_workspace( await db.update_workspace( app, workspace_id=workspace_id, - name=name, - description=description, - thumbnail=thumbnail, product_name=product_name, + updates=WorkspaceUpdateDB(**updates), ) workspace_db = await db.get_workspace_for_user( app, @@ -147,20 +139,12 @@ async def update_workspace( workspace_id=workspace_id, product_name=product_name, ) - return WorkspaceGet( - workspace_id=workspace_db.workspace_id, - name=workspace_db.name, - description=workspace_db.description, - thumbnail=workspace_db.thumbnail, - created_at=workspace_db.created, - modified_at=workspace_db.modified, - my_access_rights=workspace_db.my_access_rights, - access_rights=workspace_db.access_rights, - ) + return _to_api_model(workspace_db) async def delete_workspace( app: web.Application, + *, user_id: UserID, workspace_id: WorkspaceID, product_name: ProductName, @@ -191,5 +175,10 @@ async def check_user_workspace_access( app=app, user_id=user_id, workspace_id=workspace_id, product_name=product_name ) if getattr(workspace_db.my_access_rights, permission, False) is False: - raise WorkspaceAccessForbiddenError + raise WorkspaceAccessForbiddenError( + user_id=user_id, + workspace_id=workspace_id, + product_name=product_name, + permission_checked=permission, + ) return workspace_db diff --git a/services/web/server/src/simcore_service_webserver/workspaces/_workspaces_db.py b/services/web/server/src/simcore_service_webserver/workspaces/_workspaces_db.py index 5f80868a27f..7c55e0a9428 100644 --- a/services/web/server/src/simcore_service_webserver/workspaces/_workspaces_db.py +++ b/services/web/server/src/simcore_service_webserver/workspaces/_workspaces_db.py @@ -15,6 +15,7 @@ UserWorkspaceAccessRightsDB, WorkspaceDB, WorkspaceID, + WorkspaceUpdateDB, ) from pydantic import NonNegativeInt from simcore_postgres_database.models.workspaces import workspaces @@ -46,6 +47,13 @@ workspaces.c.thumbnail, workspaces.c.created, workspaces.c.modified, + workspaces.c.trashed, + workspaces.c.trashed_by, +) + +assert set(WorkspaceDB.model_fields) == {c.name for c in _SELECTION_ARGS} # nosec +assert set(WorkspaceUpdateDB.model_fields).issubset( # nosec + c.name for c in workspaces.columns ) @@ -105,6 +113,7 @@ async def list_workspaces_for_user( *, user_id: UserID, product_name: ProductName, + filter_trashed: bool | None, offset: NonNegativeInt, limit: NonNegativeInt, order_by: OrderBy, @@ -125,6 +134,13 @@ async def list_workspaces_for_user( .where(workspaces.c.product_name == product_name) ) + if filter_trashed is not None: + base_query = base_query.where( + workspaces.c.trashed.is_not(None) + if filter_trashed + else workspaces.c.trashed.is_(None) + ) + # Select total count from base_query subquery = base_query.subquery() count_query = select(func.count()).select_from(subquery) @@ -188,21 +204,20 @@ async def update_workspace( app: web.Application, connection: AsyncConnection | None = None, *, - workspace_id: WorkspaceID, - name: str, - description: str | None, - thumbnail: str | None, product_name: ProductName, + workspace_id: WorkspaceID, + updates: WorkspaceUpdateDB, ) -> WorkspaceDB: + # NOTE: at least 'touch' if updated_values is empty + _updates = { + **updates.dict(exclude_unset=True), + "modified": func.now(), + } + async with transaction_context(get_asyncpg_engine(app), connection) as conn: result = await conn.stream( workspaces.update() - .values( - name=name, - description=description, - thumbnail=thumbnail, - modified=func.now(), - ) + .values(**_updates) .where( (workspaces.c.workspace_id == workspace_id) & (workspaces.c.product_name == product_name) diff --git a/services/web/server/src/simcore_service_webserver/workspaces/_workspaces_handlers.py b/services/web/server/src/simcore_service_webserver/workspaces/_workspaces_handlers.py index a501253a382..fb2f7c9f1f6 100644 --- a/services/web/server/src/simcore_service_webserver/workspaces/_workspaces_handlers.py +++ b/services/web/server/src/simcore_service_webserver/workspaces/_workspaces_handlers.py @@ -1,104 +1,50 @@ -import functools import logging from aiohttp import web from models_library.api_schemas_webserver.workspaces import ( - CreateWorkspaceBodyParams, - PutWorkspaceBodyParams, + WorkspaceCreateBodyParams, WorkspaceGet, WorkspaceGetPage, + WorkspaceReplaceBodyParams, ) -from models_library.basic_types import IDStr -from models_library.rest_base import RequestParameters, StrictRequestParameters -from models_library.rest_ordering import ( - OrderBy, - OrderDirection, - create_ordering_query_model_classes, -) -from models_library.rest_pagination import Page, PageQueryParameters +from models_library.rest_ordering import OrderBy +from models_library.rest_pagination import Page from models_library.rest_pagination_utils import paginate_data -from models_library.users import UserID -from models_library.workspaces import WorkspaceID -from pydantic import Field from servicelib.aiohttp import status from servicelib.aiohttp.requests_validation import ( parse_request_body_as, parse_request_path_parameters_as, parse_request_query_parameters_as, ) -from servicelib.aiohttp.typing_extension import Handler from servicelib.mimetype_constants import MIMETYPE_APPLICATION_JSON -from servicelib.request_keys import RQT_USERID_KEY from servicelib.rest_constants import RESPONSE_MODEL_POLICY -from .._constants import RQ_PRODUCT_KEY from .._meta import API_VTAG as VTAG from ..login.decorators import login_required from ..security.decorators import permission_required from ..utils_aiohttp import envelope_json_response from . import _workspaces_api -from .errors import WorkspaceAccessForbiddenError, WorkspaceNotFoundError +from ._exceptions_handlers import handle_plugin_requests_exceptions +from ._models import ( + WorkspacesFilters, + WorkspacesListQueryParams, + WorkspacesPathParams, + WorkspacesRequestContext, +) _logger = logging.getLogger(__name__) -def handle_workspaces_exceptions(handler: Handler): - @functools.wraps(handler) - async def wrapper(request: web.Request) -> web.StreamResponse: - try: - return await handler(request) - - except WorkspaceNotFoundError as exc: - raise web.HTTPNotFound(reason=f"{exc}") from exc - - except WorkspaceAccessForbiddenError as exc: - raise web.HTTPForbidden(reason=f"{exc}") from exc - - return wrapper - - -# -# workspaces COLLECTION ------------------------- -# - routes = web.RouteTableDef() -class WorkspacesRequestContext(RequestParameters): - user_id: UserID = Field(..., alias=RQT_USERID_KEY) # type: ignore[literal-required] - product_name: str = Field(..., alias=RQ_PRODUCT_KEY) # type: ignore[literal-required] - - -class WorkspacesPathParams(StrictRequestParameters): - workspace_id: WorkspaceID - - -WorkspacesListOrderQueryParams: type[ - RequestParameters -] = create_ordering_query_model_classes( - ordering_fields={ - "modified_at", - "name", - }, - default=OrderBy(field=IDStr("modified_at"), direction=OrderDirection.DESC), - ordering_fields_api_to_column_map={"modified_at": "modified"}, -) - - -class WorkspacesListQueryParams( - PageQueryParameters, - WorkspacesListOrderQueryParams, # type: ignore[misc, valid-type] -): - ... - - @routes.post(f"/{VTAG}/workspaces", name="create_workspace") @login_required @permission_required("workspaces.*") -@handle_workspaces_exceptions +@handle_plugin_requests_exceptions async def create_workspace(request: web.Request): req_ctx = WorkspacesRequestContext.model_validate(request) - body_params = await parse_request_body_as(CreateWorkspaceBodyParams, request) + body_params = await parse_request_body_as(WorkspaceCreateBodyParams, request) workspace: WorkspaceGet = await _workspaces_api.create_workspace( request.app, @@ -115,17 +61,22 @@ async def create_workspace(request: web.Request): @routes.get(f"/{VTAG}/workspaces", name="list_workspaces") @login_required @permission_required("workspaces.*") -@handle_workspaces_exceptions +@handle_plugin_requests_exceptions async def list_workspaces(request: web.Request): req_ctx = WorkspacesRequestContext.model_validate(request) query_params: WorkspacesListQueryParams = parse_request_query_parameters_as( WorkspacesListQueryParams, request ) + if not query_params.filters: + query_params.filters = WorkspacesFilters() + + assert query_params.filters workspaces: WorkspaceGetPage = await _workspaces_api.list_workspaces( app=request.app, user_id=req_ctx.user_id, product_name=req_ctx.product_name, + filter_trashed=query_params.filters.trashed, offset=query_params.offset, limit=query_params.limit, order_by=OrderBy.model_validate(query_params.order_by), @@ -149,7 +100,7 @@ async def list_workspaces(request: web.Request): @routes.get(f"/{VTAG}/workspaces/{{workspace_id}}", name="get_workspace") @login_required @permission_required("workspaces.*") -@handle_workspaces_exceptions +@handle_plugin_requests_exceptions async def get_workspace(request: web.Request): req_ctx = WorkspacesRequestContext.model_validate(request) path_params = parse_request_path_parameters_as(WorkspacesPathParams, request) @@ -170,20 +121,18 @@ async def get_workspace(request: web.Request): ) @login_required @permission_required("workspaces.*") -@handle_workspaces_exceptions +@handle_plugin_requests_exceptions async def replace_workspace(request: web.Request): req_ctx = WorkspacesRequestContext.model_validate(request) path_params = parse_request_path_parameters_as(WorkspacesPathParams, request) - body_params = await parse_request_body_as(PutWorkspaceBodyParams, request) + body_params = await parse_request_body_as(WorkspaceReplaceBodyParams, request) workspace: WorkspaceGet = await _workspaces_api.update_workspace( app=request.app, user_id=req_ctx.user_id, workspace_id=path_params.workspace_id, - name=body_params.name, - description=body_params.description, product_name=req_ctx.product_name, - thumbnail=body_params.thumbnail, + **body_params.model_dump(), ) return envelope_json_response(workspace) @@ -194,7 +143,7 @@ async def replace_workspace(request: web.Request): ) @login_required @permission_required("workspaces.*") -@handle_workspaces_exceptions +@handle_plugin_requests_exceptions async def delete_workspace(request: web.Request): req_ctx = WorkspacesRequestContext.model_validate(request) path_params = parse_request_path_parameters_as(WorkspacesPathParams, request) diff --git a/services/web/server/src/simcore_service_webserver/workspaces/plugin.py b/services/web/server/src/simcore_service_webserver/workspaces/plugin.py index 4773b056b49..d67a9167c92 100644 --- a/services/web/server/src/simcore_service_webserver/workspaces/plugin.py +++ b/services/web/server/src/simcore_service_webserver/workspaces/plugin.py @@ -7,7 +7,7 @@ from servicelib.aiohttp.application_keys import APP_SETTINGS_KEY from servicelib.aiohttp.application_setup import ModuleCategory, app_module_setup -from . import _groups_handlers, _workspaces_handlers +from . import _groups_handlers, _trash_handlers, _workspaces_handlers _logger = logging.getLogger(__name__) @@ -25,3 +25,4 @@ def setup_workspaces(app: web.Application): # routes app.router.add_routes(_workspaces_handlers.routes) app.router.add_routes(_groups_handlers.routes) + app.router.add_routes(_trash_handlers.routes) diff --git a/services/web/server/tests/conftest.py b/services/web/server/tests/conftest.py index 97a96fa2847..7085050f331 100644 --- a/services/web/server/tests/conftest.py +++ b/services/web/server/tests/conftest.py @@ -75,6 +75,7 @@ "pytest_simcore.simcore_service_library_fixtures", "pytest_simcore.simcore_services", "pytest_simcore.socketio_client", + "pytest_simcore.openapi_specs", ] diff --git a/services/web/server/tests/unit/conftest.py b/services/web/server/tests/unit/conftest.py index 40dd2bd79b9..695a7aa1ed4 100644 --- a/services/web/server/tests/unit/conftest.py +++ b/services/web/server/tests/unit/conftest.py @@ -14,13 +14,8 @@ import pytest import yaml -from openapi_core.schema.specs.models import Spec as OpenApiSpecs from pytest_simcore.helpers.dict_tools import ConfigDict from pytest_simcore.helpers.webserver_projects import empty_project_data -from simcore_service_webserver.rest._utils import ( - get_openapi_specs_path, - load_openapi_specs, -) CURRENT_DIR = Path(sys.argv[0] if __name__ == "__main__" else __file__).resolve().parent @@ -81,9 +76,3 @@ def disable_gc_manual_guest_users(mocker): "simcore_service_webserver.garbage_collector._core.remove_users_manually_marked_as_guests", return_value=None, ) - - -@pytest.fixture -def openapi_specs(api_version_prefix) -> OpenApiSpecs: - spec_path = get_openapi_specs_path(api_version_prefix) - return load_openapi_specs(spec_path) diff --git a/services/web/server/tests/unit/isolated/test_diagnostics.py b/services/web/server/tests/unit/isolated/test_diagnostics.py index 6ceb6b9e005..3f18e81fd09 100644 --- a/services/web/server/tests/unit/isolated/test_diagnostics.py +++ b/services/web/server/tests/unit/isolated/test_diagnostics.py @@ -35,7 +35,7 @@ def add_routes(self, *args, **kwargs): @pytest.fixture -def app_mock(openapi_specs): +def app_mock(): app = MockApp() # emulates security is initialized @@ -44,9 +44,7 @@ def app_mock(openapi_specs): return app -def test_unique_application_keys( - app_mock, openapi_specs, mock_env_devel_environment: dict[str, str] -): +def test_unique_application_keys(app_mock, mock_env_devel_environment: dict[str, str]): setup_settings(app_mock) setup_rest(app_mock) setup_diagnostics(app_mock) diff --git a/services/web/server/tests/unit/with_dbs/03/test__openapi_specs.py b/services/web/server/tests/unit/with_dbs/03/test__openapi_specs.py index eafb6ed29b9..1128f9a707a 100644 --- a/services/web/server/tests/unit/with_dbs/03/test__openapi_specs.py +++ b/services/web/server/tests/unit/with_dbs/03/test__openapi_specs.py @@ -3,22 +3,25 @@ # pylint: disable=unused-argument # pylint: disable=unused-variable -from typing import NamedTuple + +from collections.abc import Callable +from pathlib import Path import pytest from aiohttp import web from faker import Faker -from openapi_core.schema.specs.models import Spec as OpenApiSpecs from pytest_simcore.helpers.monkeypatch_envs import setenvs_from_dict from pytest_simcore.helpers.typing_env import EnvVarsDict +from pytest_simcore.openapi_specs import Entrypoint from simcore_service_webserver.application import create_application from simcore_service_webserver.application_settings import get_application_settings +from simcore_service_webserver.rest._utils import get_openapi_specs_path -class Entrypoint(NamedTuple): - name: str - method: str - path: str +@pytest.fixture(scope="session") +def openapi_specs_path(api_version_prefix: str) -> Path: + # overrides pytest_simcore.openapi_specs.app_openapi_specs_path fixture + return get_openapi_specs_path(api_version_prefix) @pytest.fixture @@ -51,6 +54,7 @@ def app_environment( @pytest.fixture def app(app_environment: EnvVarsDict) -> web.Application: + assert app_environment # Expects that: # - routings happen during setup! # - all plugins are setup but app is NOT started (i.e events are not triggered) @@ -61,54 +65,19 @@ def app(app_environment: EnvVarsDict) -> web.Application: @pytest.fixture -def expected_openapi_entrypoints(openapi_specs: OpenApiSpecs) -> set[Entrypoint]: - entrypoints: set[Entrypoint] = set() - - # openapi-specifications, i.e. "contract" - for path, path_obj in openapi_specs.paths.items(): - for operation, operation_obj in path_obj.operations.items(): - entrypoints.add( - Entrypoint( - method=operation.upper(), - path=path, - name=operation_obj.operation_id, - ) - ) - return entrypoints - - -@pytest.fixture -def app_entrypoints(app: web.Application) -> set[Entrypoint]: - entrypoints: set[Entrypoint] = set() - - # app routes, i.e. "exposed" - for resource_name, resource in app.router.named_resources().items(): - resource_path = resource.canonical - for route in resource: - assert route.name == resource_name - assert route.resource - assert route.name is not None - - if route.method == "HEAD": - continue - - entrypoints.add( - Entrypoint( - method=route.method, - path=resource_path, - name=route.name, - ) - ) - return entrypoints +def app_rest_entrypoints( + app: web.Application, + create_aiohttp_app_rest_entrypoints: Callable[[web.Application], set[Entrypoint]], +) -> set[Entrypoint]: + # check whether exposed routes implements openapi.json contract + return create_aiohttp_app_rest_entrypoints(app) def test_app_named_resources_against_openapi_specs( - expected_openapi_entrypoints: set[Entrypoint], - app_entrypoints: set[Entrypoint], + openapi_specs_entrypoints: set[Entrypoint], + app_rest_entrypoints: set[Entrypoint], ): - # check whether exposed routes implements openapi.json contract - - assert app_entrypoints == expected_openapi_entrypoints + assert app_rest_entrypoints == openapi_specs_entrypoints # NOTE: missing here is: # - input schemas (path, query and body) diff --git a/services/web/server/tests/unit/with_dbs/03/test_trash.py b/services/web/server/tests/unit/with_dbs/03/test_trash.py index 16a5f9dc147..2489ea6107c 100644 --- a/services/web/server/tests/unit/with_dbs/03/test_trash.py +++ b/services/web/server/tests/unit/with_dbs/03/test_trash.py @@ -7,7 +7,7 @@ import asyncio -from collections.abc import Callable +from collections.abc import AsyncIterable, Callable from uuid import UUID import arrow @@ -16,6 +16,7 @@ from aioresponses import aioresponses from models_library.api_schemas_webserver.folders_v2 import FolderGet from models_library.api_schemas_webserver.projects import ProjectGet, ProjectListItem +from models_library.api_schemas_webserver.workspaces import WorkspaceGet from models_library.rest_pagination import Page from pytest_mock import MockerFixture from pytest_simcore.helpers.assert_checks import assert_status @@ -395,3 +396,102 @@ async def test_trash_folder_with_content( data, _ = await assert_status(resp, status.HTTP_200_OK) got = ProjectGet.model_validate(data) assert got.trashed_at is None + + +@pytest.fixture +async def workspace( + client: TestClient, logged_user: UserInfoDict +) -> AsyncIterable[WorkspaceGet]: + + # CREATE a workspace + resp = await client.post("/v0/workspaces", json={"name": "My first workspace"}) + data, _ = await assert_status(resp, status.HTTP_201_CREATED) + workspace = WorkspaceGet.parse_obj(data) + + yield workspace + + # DELETE a workspace + resp = await client.delete(f"/v0/workspaces/{workspace.workspace_id}") + data, _ = await assert_status(resp, status.HTTP_204_NO_CONTENT) + + +@pytest.mark.acceptance_test( + "https://github.com/ITISFoundation/osparc-simcore/pull/6690" +) +async def test_trash_empty_workspace( + client: TestClient, logged_user: UserInfoDict, workspace: WorkspaceGet +): + assert client.app + + assert workspace.trashed_at is None + assert workspace.trashed_by is None + + # LIST NOT trashed (default) + resp = await client.get("/v0/workspaces") + await assert_status(resp, status.HTTP_200_OK) + + page = Page[WorkspaceGet].parse_obj(await resp.json()) + assert page.meta.total == 1 + assert page.data[0] == workspace + + # LIST trashed + resp = await client.get("/v0/workspaces", params={"filters": '{"trashed": true}'}) + await assert_status(resp, status.HTTP_200_OK) + + page = Page[WorkspaceGet].parse_obj(await resp.json()) + assert page.meta.total == 0 + + # ------------- + + _exclude_attrs = {"trashed_by", "trashed_at", "modified_at"} + + # TRASH + before_trash = arrow.utcnow().datetime + resp = await client.post(f"/v0/workspaces/{workspace.workspace_id}:trash") + await assert_status(resp, status.HTTP_204_NO_CONTENT) + + # LIST NOT trashed (default) + resp = await client.get("/v0/workspaces") + await assert_status(resp, status.HTTP_200_OK) + + page = Page[WorkspaceGet].parse_obj(await resp.json()) + assert page.meta.total == 0 + + # LIST trashed + resp = await client.get("/v0/workspaces", params={"filters": '{"trashed": true}'}) + await assert_status(resp, status.HTTP_200_OK) + + page = Page[WorkspaceGet].parse_obj(await resp.json()) + assert page.meta.total == 1 + assert page.data[0].dict(exclude=_exclude_attrs) == workspace.dict( + exclude=_exclude_attrs + ) + assert page.data[0].trashed_at is not None + assert before_trash < page.data[0].trashed_at + assert page.data[0].trashed_by == logged_user["id"] + + # -------- + + # UN_TRASH + resp = await client.post(f"/v0/workspaces/{workspace.workspace_id}:untrash") + await assert_status(resp, status.HTTP_204_NO_CONTENT) + + # LIST NOT trashed (default) + resp = await client.get("/v0/workspaces") + await assert_status(resp, status.HTTP_200_OK) + + page = Page[WorkspaceGet].parse_obj(await resp.json()) + assert page.meta.total == 1 + assert page.data[0].dict(exclude=_exclude_attrs) == workspace.dict( + exclude=_exclude_attrs + ) + + assert page.data[0].trashed_at is None + assert page.data[0].trashed_by is None + + # LIST trashed + resp = await client.get("/v0/workspaces", params={"filters": '{"trashed": true}'}) + await assert_status(resp, status.HTTP_200_OK) + + page = Page[WorkspaceGet].parse_obj(await resp.json()) + assert page.meta.total == 0 diff --git a/services/web/server/tests/unit/with_dbs/04/workspaces/test_workspaces.py b/services/web/server/tests/unit/with_dbs/04/workspaces/test_workspaces.py index ed2054595dd..5e7d81afd2b 100644 --- a/services/web/server/tests/unit/with_dbs/04/workspaces/test_workspaces.py +++ b/services/web/server/tests/unit/with_dbs/04/workspaces/test_workspaces.py @@ -50,7 +50,7 @@ async def test_workspaces_user_role_permissions( assert client.app url = client.app.router["list_workspaces"].url_for() - resp = await client.get(url.path) + resp = await client.get(f"{url}") await assert_status(resp, expected.ok) @@ -65,78 +65,75 @@ async def test_workspaces_workflow( # list user workspaces url = client.app.router["list_workspaces"].url_for() - resp = await client.get(url.path) + resp = await client.get(f"{url}") data, _ = await assert_status(resp, status.HTTP_200_OK) assert data == [] - # create a new workspace + # CREATE a new workspace url = client.app.router["create_workspace"].url_for() resp = await client.post( - url.path, + f"{url}", json={ "name": "My first workspace", "description": "Custom description", "thumbnail": None, }, ) - added_workspace, _ = await assert_status(resp, status.HTTP_201_CREATED) - assert WorkspaceGet.model_validate(added_workspace) + data, _ = await assert_status(resp, status.HTTP_201_CREATED) + added_workspace = WorkspaceGet.model_validate(data) - # list user workspaces + # LIST user workspaces url = client.app.router["list_workspaces"].url_for() - resp = await client.get(url.path) + resp = await client.get(f"{url}") data, _, meta, links = await assert_status( resp, status.HTTP_200_OK, include_meta=True, include_links=True ) assert len(data) == 1 - assert data[0]["workspaceId"] == added_workspace["workspaceId"] - assert data[0]["name"] == "My first workspace" - assert data[0]["description"] == "Custom description" + assert WorkspaceGet.parse_obj(data[0]) == added_workspace assert meta["count"] == 1 assert links - # get a user workspace + # GET a user workspace url = client.app.router["get_workspace"].url_for( - workspace_id=f"{added_workspace['workspaceId']}" + workspace_id=f"{added_workspace.workspace_id}" ) resp = await client.get(f"{url}") data, _ = await assert_status(resp, status.HTTP_200_OK) - assert data["workspaceId"] == added_workspace["workspaceId"] + assert data["workspaceId"] == added_workspace.workspace_id assert data["name"] == "My first workspace" assert data["description"] == "Custom description" - # update a workspace + # REPLACE a workspace url = client.app.router["replace_workspace"].url_for( - workspace_id=f"{added_workspace['workspaceId']}" + workspace_id=f"{added_workspace.workspace_id}" ) resp = await client.put( - url.path, + f"{url}", json={ "name": "My Second workspace", "description": "", }, ) data, _ = await assert_status(resp, status.HTTP_200_OK) - assert WorkspaceGet.model_validate(data) + replaced_workspace = WorkspaceGet.model_validate(data) - # list user workspaces + # LIST user workspaces url = client.app.router["list_workspaces"].url_for() - resp = await client.get(url.path) + resp = await client.get(f"{url}") data, _ = await assert_status(resp, status.HTTP_200_OK) assert len(data) == 1 - assert data[0]["name"] == "My Second workspace" - assert data[0]["description"] == "" + assert WorkspaceGet.parse_obj(data[0]) == replaced_workspace - # delete a workspace + # DELETE a workspace url = client.app.router["delete_workspace"].url_for( - workspace_id=f"{added_workspace['workspaceId']}" + workspace_id=f"{added_workspace.workspace_id}" ) - resp = await client.delete(url.path) + resp = await client.delete(f"{url}") data, _ = await assert_status(resp, status.HTTP_204_NO_CONTENT) - # list user workspaces + # LIST user workspaces url = client.app.router["list_workspaces"].url_for() - resp = await client.get(url.path) + resp = await client.get(f"{url}") data, _ = await assert_status(resp, status.HTTP_200_OK) assert data == [] @@ -151,3 +148,4 @@ async def test_project_workspace_movement_full_workflow( assert client.app # NOTE: MD: not yet implemented + # SEE https://github.com/ITISFoundation/osparc-simcore/issues/6778 diff --git a/services/web/server/tests/unit/with_dbs/04/workspaces/test_workspaces__folders_and_projects_crud.py b/services/web/server/tests/unit/with_dbs/04/workspaces/test_workspaces__folders_and_projects_crud.py index c2bbab0616a..477413d274d 100644 --- a/services/web/server/tests/unit/with_dbs/04/workspaces/test_workspaces__folders_and_projects_crud.py +++ b/services/web/server/tests/unit/with_dbs/04/workspaces/test_workspaces__folders_and_projects_crud.py @@ -12,6 +12,7 @@ import pytest from aiohttp.test_utils import TestClient +from models_library.api_schemas_webserver.workspaces import WorkspaceGet from pytest_mock import MockerFixture from pytest_simcore.helpers.assert_checks import assert_status from pytest_simcore.helpers.webserver_login import LoggedUser, UserInfoDict @@ -54,21 +55,22 @@ async def test_workspaces_full_workflow_with_folders_and_projects( ): assert client.app - # create a new workspace + # Create a new workspace url = client.app.router["create_workspace"].url_for() resp = await client.post( - url.path, + f"{url}", json={ "name": "My first workspace", "description": "Custom description", "thumbnail": None, }, ) - added_workspace, _ = await assert_status(resp, status.HTTP_201_CREATED) + data, _ = await assert_status(resp, status.HTTP_201_CREATED) + added_workspace = WorkspaceGet.model_validate(data) - # Create project in workspace + # Create project **in workspace** project_data = deepcopy(fake_project) - project_data["workspace_id"] = f"{added_workspace['workspaceId']}" + project_data["workspace_id"] = f"{added_workspace.workspace_id}" project = await create_project( client.app, project_data, @@ -77,30 +79,33 @@ async def test_workspaces_full_workflow_with_folders_and_projects( ) # List project in workspace - base_url = client.app.router["list_projects"].url_for() - url = base_url.with_query({"workspace_id": f"{added_workspace['workspaceId']}"}) + url = ( + client.app.router["list_projects"] + .url_for() + .with_query({"workspace_id": f"{added_workspace.workspace_id}"}) + ) resp = await client.get(f"{url}") data, _ = await assert_status(resp, status.HTTP_200_OK) assert len(data) == 1 assert data[0]["uuid"] == project["uuid"] - assert data[0]["workspaceId"] == added_workspace["workspaceId"] + assert data[0]["workspaceId"] == added_workspace.workspace_id assert data[0]["folderId"] is None # Get project in workspace - base_url = client.app.router["get_project"].url_for(project_id=project["uuid"]) - resp = await client.get(f"{base_url}") + url = client.app.router["get_project"].url_for(project_id=project["uuid"]) + resp = await client.get(f"{url}") data, _ = await assert_status(resp, status.HTTP_200_OK) assert data["uuid"] == project["uuid"] - assert data["workspaceId"] == added_workspace["workspaceId"] + assert data["workspaceId"] == added_workspace.workspace_id assert data["folderId"] is None # Create folder in workspace url = client.app.router["create_folder"].url_for() resp = await client.post( - url.path, + f"{url}", json={ "name": "Original user folder", - "workspaceId": f"{added_workspace['workspaceId']}", + "workspaceId": f"{added_workspace.workspace_id}", }, ) first_folder, _ = await assert_status(resp, status.HTTP_201_CREATED) @@ -108,7 +113,7 @@ async def test_workspaces_full_workflow_with_folders_and_projects( # List folders in workspace base_url = client.app.router["list_folders"].url_for() url = base_url.with_query( - {"workspace_id": f"{added_workspace['workspaceId']}", "folder_id": "null"} + {"workspace_id": f"{added_workspace.workspace_id}", "folder_id": "null"} ) resp = await client.get(f"{url}") data, _ = await assert_status(resp, status.HTTP_200_OK) @@ -120,14 +125,14 @@ async def test_workspaces_full_workflow_with_folders_and_projects( folder_id=f"{first_folder['folderId']}", project_id=f"{project['uuid']}", ) - resp = await client.put(url.path) + resp = await client.put(f"{url}") await assert_status(resp, status.HTTP_204_NO_CONTENT) # List projects in specific folder in workspace base_url = client.app.router["list_projects"].url_for() url = base_url.with_query( { - "workspace_id": f"{added_workspace['workspaceId']}", + "workspace_id": f"{added_workspace.workspace_id}", "folder_id": f"{first_folder['folderId']}", } ) @@ -140,8 +145,11 @@ async def test_workspaces_full_workflow_with_folders_and_projects( # Create new user async with LoggedUser(client) as new_logged_user: # Try to list folder that user doesn't have access to - base_url = client.app.router["list_projects"].url_for() - url = base_url.with_query({"workspace_id": f"{added_workspace['workspaceId']}"}) + url = ( + client.app.router["list_projects"] + .url_for() + .with_query({"workspace_id": f"{added_workspace.workspace_id}"}) + ) resp = await client.get(f"{url}") _, errors = await assert_status( resp, @@ -152,7 +160,7 @@ async def test_workspaces_full_workflow_with_folders_and_projects( # Now we will share the workspace with the new user await update_or_insert_workspace_group( client.app, - workspace_id=added_workspace["workspaceId"], + workspace_id=added_workspace.workspace_id, group_id=new_logged_user["primary_gid"], read=True, write=True, @@ -160,33 +168,42 @@ async def test_workspaces_full_workflow_with_folders_and_projects( ) # New user list root folders inside of workspace - base_url = client.app.router["list_folders"].url_for() - url = base_url.with_query( - {"workspace_id": f"{added_workspace['workspaceId']}", "folder_id": "null"} + url = ( + client.app.router["list_folders"] + .url_for() + .with_query( + {"workspace_id": f"{added_workspace.workspace_id}", "folder_id": "null"} + ) ) resp = await client.get(f"{url}") data, _ = await assert_status(resp, status.HTTP_200_OK) assert len(data) == 1 # New user list root projects inside of workspace - base_url = client.app.router["list_projects"].url_for() - url = base_url.with_query( - { - "workspace_id": f"{added_workspace['workspaceId']}", - "folder_id": "none", - } + url = ( + client.app.router["list_projects"] + .url_for() + .with_query( + { + "workspace_id": f"{added_workspace.workspace_id}", + "folder_id": "none", + } + ) ) resp = await client.get(f"{url}") data, _ = await assert_status(resp, status.HTTP_200_OK) assert len(data) == 0 # New user list projects in specific folder inside of workspace - base_url = client.app.router["list_projects"].url_for() - url = base_url.with_query( - { - "workspace_id": f"{added_workspace['workspaceId']}", - "folder_id": f"{first_folder['folderId']}", - } + url = ( + client.app.router["list_projects"] + .url_for() + .with_query( + { + "workspace_id": f"{added_workspace.workspace_id}", + "folder_id": f"{first_folder['folderId']}", + } + ) ) resp = await client.get(f"{url}") data, _ = await assert_status(resp, status.HTTP_200_OK) @@ -196,10 +213,10 @@ async def test_workspaces_full_workflow_with_folders_and_projects( # New user with write permission creates a folder url = client.app.router["create_folder"].url_for() resp = await client.post( - url.path, + f"{url}", json={ "name": "New user folder", - "workspaceId": f"{added_workspace['workspaceId']}", + "workspaceId": f"{added_workspace.workspace_id}", }, ) await assert_status(resp, status.HTTP_201_CREATED) @@ -207,7 +224,7 @@ async def test_workspaces_full_workflow_with_folders_and_projects( # Now we will remove write permissions await update_or_insert_workspace_group( client.app, - workspace_id=added_workspace["workspaceId"], + workspace_id=added_workspace.workspace_id, group_id=new_logged_user["primary_gid"], read=True, write=False, @@ -217,10 +234,10 @@ async def test_workspaces_full_workflow_with_folders_and_projects( # Now error is raised on the creation of folder as user doesn't have write access url = client.app.router["create_folder"].url_for() resp = await client.post( - url.path, + f"{url}", json={ "name": "New user second folder", - "workspaceId": f"{added_workspace['workspaceId']}", + "workspaceId": f"{added_workspace.workspace_id}", }, ) await assert_status(resp, status.HTTP_403_FORBIDDEN) @@ -228,7 +245,7 @@ async def test_workspaces_full_workflow_with_folders_and_projects( # But user has still read permissions base_url = client.app.router["list_folders"].url_for() url = base_url.with_query( - {"workspace_id": f"{added_workspace['workspaceId']}", "folder_id": "null"} + {"workspace_id": f"{added_workspace.workspace_id}", "folder_id": "null"} ) resp = await client.get(f"{url}") data, _ = await assert_status(resp, status.HTTP_200_OK) @@ -271,18 +288,19 @@ async def test_workspaces_delete_folders( # create a new workspace url = client.app.router["create_workspace"].url_for() resp = await client.post( - url.path, + f"{url}", json={ "name": "My first workspace", "description": "Custom description", "thumbnail": None, }, ) - added_workspace, _ = await assert_status(resp, status.HTTP_201_CREATED) + data, _ = await assert_status(resp, status.HTTP_201_CREATED) + added_workspace = WorkspaceGet.parse_obj(data) # Create project in workspace project_data = deepcopy(fake_project) - project_data["workspace_id"] = f"{added_workspace['workspaceId']}" + project_data["workspace_id"] = f"{added_workspace.workspace_id}" first_project = await create_project( client.app, project_data, @@ -297,8 +315,11 @@ async def test_workspaces_delete_folders( ) # List project in workspace - base_url = client.app.router["list_projects"].url_for() - url = base_url.with_query({"workspace_id": f"{added_workspace['workspaceId']}"}) + url = ( + client.app.router["list_projects"] + .url_for() + .with_query({"workspace_id": f"{added_workspace.workspace_id}"}) + ) resp = await client.get(f"{url}") data, _ = await assert_status(resp, status.HTTP_200_OK) assert len(data) == 2 @@ -306,10 +327,10 @@ async def test_workspaces_delete_folders( # Create folder in workspace url = client.app.router["create_folder"].url_for() resp = await client.post( - url.path, + f"{url}", json={ "name": "Original user folder", - "workspaceId": f"{added_workspace['workspaceId']}", + "workspaceId": f"{added_workspace.workspace_id}", }, ) first_folder, _ = await assert_status(resp, status.HTTP_201_CREATED) @@ -317,10 +338,10 @@ async def test_workspaces_delete_folders( # Create sub folder of previous folder url = client.app.router["create_folder"].url_for() resp = await client.post( - url.path, + f"{url}", json={ "name": "Second user folder", - "workspaceId": f"{added_workspace['workspaceId']}", + "workspaceId": f"{added_workspace.workspace_id}", "parentFolderId": f"{first_folder['folderId']}", }, ) @@ -331,7 +352,7 @@ async def test_workspaces_delete_folders( folder_id=f"{first_folder['folderId']}", project_id=f"{first_project['uuid']}", ) - resp = await client.put(url.path) + resp = await client.put(f"{url}") await assert_status(resp, status.HTTP_204_NO_CONTENT) # Move second project in specific folder in workspace @@ -339,19 +360,19 @@ async def test_workspaces_delete_folders( folder_id=f"{second_folder['folderId']}", project_id=f"{second_project['uuid']}", ) - resp = await client.put(url.path) + resp = await client.put(f"{url}") await assert_status(resp, status.HTTP_204_NO_CONTENT) # Delete folder url = client.app.router["delete_folder"].url_for( folder_id=f"{first_folder['folderId']}" ) - resp = await client.delete(url.path) + resp = await client.delete(f"{url}") await assert_status(resp, status.HTTP_204_NO_CONTENT) - fire_and_forget_tasks = client.app[APP_FIRE_AND_FORGET_TASKS_KEY] - t1: asyncio.Task = list(fire_and_forget_tasks)[0] - t2: asyncio.Task = list(fire_and_forget_tasks)[1] + fire_and_forget_tasks = list(client.app[APP_FIRE_AND_FORGET_TASKS_KEY]) + t1: asyncio.Task = fire_and_forget_tasks[0] + t2: asyncio.Task = fire_and_forget_tasks[1] assert t1.get_name().startswith("fire_and_forget_task_delete_project_task_") assert t2.get_name().startswith("fire_and_forget_task_delete_project_task_") await t1 @@ -360,8 +381,11 @@ async def test_workspaces_delete_folders( assert len(client.app[APP_FIRE_AND_FORGET_TASKS_KEY]) == 0 # List project in workspace (The projects should have been deleted) - base_url = client.app.router["list_projects"].url_for() - url = base_url.with_query({"workspace_id": f"{added_workspace['workspaceId']}"}) + url = ( + client.app.router["list_projects"] + .url_for() + .with_query({"workspace_id": f"{added_workspace.workspace_id}"}) + ) resp = await client.get(f"{url}") data, _ = await assert_status(resp, status.HTTP_200_OK) assert len(data) == 0 @@ -382,7 +406,7 @@ async def test_listing_folders_and_projects_in_workspace__multiple_workspaces_cr # create a new workspace url = client.app.router["create_workspace"].url_for() resp = await client.post( - url.path, + f"{url}", json={ "name": "My first workspace", "description": "Custom description", @@ -404,7 +428,7 @@ async def test_listing_folders_and_projects_in_workspace__multiple_workspaces_cr # Create folder in workspace url = client.app.router["create_folder"].url_for() resp = await client.post( - url.path, + f"{url}", json={ "name": "Original user folder", "workspaceId": f"{added_workspace_1['workspaceId']}", @@ -415,7 +439,7 @@ async def test_listing_folders_and_projects_in_workspace__multiple_workspaces_cr # create a new workspace url = client.app.router["create_workspace"].url_for() resp = await client.post( - url.path, + f"{url}", json={ "name": "My first workspace", "description": "Custom description", @@ -437,7 +461,7 @@ async def test_listing_folders_and_projects_in_workspace__multiple_workspaces_cr # Create folder in workspace url = client.app.router["create_folder"].url_for() resp = await client.post( - url.path, + f"{url}", json={ "name": "Original user folder", "workspaceId": f"{added_workspace_2['workspaceId']}", @@ -446,17 +470,23 @@ async def test_listing_folders_and_projects_in_workspace__multiple_workspaces_cr first_folder, _ = await assert_status(resp, status.HTTP_201_CREATED) # List projects in workspace 1 - base_url = client.app.router["list_projects"].url_for() - url = base_url.with_query({"workspace_id": f"{added_workspace_1['workspaceId']}"}) - resp = await client.get(url) + url = ( + client.app.router["list_projects"] + .url_for() + .with_query({"workspace_id": f"{added_workspace_1['workspaceId']}"}) + ) + resp = await client.get(f"{url}") data, _ = await assert_status(resp, status.HTTP_200_OK) assert len(data) == 1 # List folders in workspace 1 - base_url = client.app.router["list_folders"].url_for() - url = base_url.with_query( - {"workspace_id": f"{added_workspace_1['workspaceId']}", "folder_id": "null"} + url = ( + client.app.router["list_folders"] + .url_for() + .with_query( + {"workspace_id": f"{added_workspace_1['workspaceId']}", "folder_id": "null"} + ) ) - resp = await client.get(url) + resp = await client.get(f"{url}") data, _ = await assert_status(resp, status.HTTP_200_OK) assert len(data) == 1 diff --git a/tests/e2e-playwright/tests/conftest.py b/tests/e2e-playwright/tests/conftest.py index ca2ec5a579e..20c40c3a291 100644 --- a/tests/e2e-playwright/tests/conftest.py +++ b/tests/e2e-playwright/tests/conftest.py @@ -19,7 +19,7 @@ import arrow import pytest from faker import Faker -from playwright.sync_api import APIRequestContext, BrowserContext, Page +from playwright.sync_api import APIRequestContext, BrowserContext, Page, expect from playwright.sync_api._generated import Playwright from pydantic import AnyUrl, TypeAdapter from pytest_simcore.helpers.faker_factories import DEFAULT_TEST_PASSWORD @@ -414,6 +414,17 @@ def log_in_and_out( page.wait_for_timeout(500) +def _open_with_resources(page: Page, *, click_it: bool): + study_title_field = page.get_by_test_id("studyTitleField") + # wait until the title is automatically filled up + expect(study_title_field).not_to_have_value("", timeout=5000) + + open_with_resources_button = page.get_by_test_id("openWithResources") + if click_it: + open_with_resources_button.click() + return open_with_resources_button + + @pytest.fixture def create_new_project_and_delete( page: Page, @@ -460,8 +471,7 @@ def _( if template_id is not None: if is_product_billable: open_button.click() - # Open project with default resources - open_button = page.get_by_test_id("openWithResources") + open_button = _open_with_resources(page, click_it=False) # it returns a Long Running Task with page.expect_response( re.compile(rf"/projects\?from_study\={template_id}") @@ -506,14 +516,10 @@ def wait_for_done(response): else: open_button.click() if is_product_billable: - # Open project with default resources - open_button = page.get_by_test_id("openWithResources") - open_button.click() + _open_with_resources(page, click_it=True) open_with_resources_clicked = True if is_product_billable and not open_with_resources_clicked: - # Open project with default resources - open_button = page.get_by_test_id("openWithResources") - open_button.click() + _open_with_resources(page, click_it=True) project_data = response_info.value.json() assert project_data project_uuid = project_data["data"]["uuid"]