From 8feffe356effde715bd5bcf6da7cca53e60ff4c4 Mon Sep 17 00:00:00 2001 From: Remko Date: Mon, 12 Oct 2026 10:09:18 +0200 Subject: [PATCH 1/2] feat(api): list widget types and create views without a table on api/2 Two api/2 endpoints for grid views: one returns the widget types with the schemas of their configuration and content, the other creates a view without a table, owned by the user who creates it. Creating is rate limited like the other mutation endpoints. Co-authored-by: Ruben van der Linde Assisted-by: ClaudeCode:claude-opus-5-5 Signed-off-by: Remko --- appinfo/routes.php | 4 + lib/Controller/ApiViewsController.php | 85 ++++ lib/ResponseDefinitions.php | 17 + openapi.json | 417 ++++++++++++++++++ src/types/openapi/openapi.ts | 222 ++++++++++ .../Controller/ApiViewsControllerTest.php | 81 ++++ 6 files changed, 826 insertions(+) create mode 100644 lib/Controller/ApiViewsController.php create mode 100644 tests/unit/Controller/ApiViewsControllerTest.php diff --git a/appinfo/routes.php b/appinfo/routes.php index ad9b79e77e..ffc584bc73 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -128,6 +128,10 @@ // API v2 ['name' => 'ApiGeneral#index', 'url' => '/api/2/init', 'verb' => 'GET'], // -> tables + // views without a table and the widget types their grids hold + ['name' => 'ApiViews#widgetTypes', 'url' => '/api/2/views/widget-types', 'verb' => 'GET'], + ['name' => 'ApiViews#create', 'url' => '/api/2/views', 'verb' => 'POST'], + ['name' => 'ApiTables#index', 'url' => '/api/2/tables', 'verb' => 'GET'], ['name' => 'ApiTables#show', 'url' => '/api/2/tables/{id}', 'verb' => 'GET'], ['name' => 'ApiTables#showScheme', 'url' => '/api/2/tables/scheme/{id}', 'verb' => 'GET'], diff --git a/lib/Controller/ApiViewsController.php b/lib/Controller/ApiViewsController.php new file mode 100644 index 0000000000..b202836da4 --- /dev/null +++ b/lib/Controller/ApiViewsController.php @@ -0,0 +1,85 @@ +, array{}> + * + * 200: Widget types returned + */ + #[NoAdminRequired] + public function widgetTypes(): DataResponse { + return new DataResponse(array_values($this->gridWidgetTypes->all())); + } + + /** + * [api v2] Create a view without a table, such as a grid view + * + * The view belongs to the user who creates it and can be placed in an application menu. + * + * @param string $title Title of the view + * @param string|null $emoji Emoji shown with the title + * @param string $type Type of the view, `grid` for a page of widgets + * @param string|null $technicalName Technical name, lowercase letters, numbers and underscores + * @param string $description Description shown on the page + * @return DataResponse|DataResponse + * + * 200: View created + * 400: Invalid type or technical name + * 403: No permissions + */ + #[NoAdminRequired] + #[UserRateLimit(limit: 20, period: 60)] + public function create(string $title, ?string $emoji = null, string $type = 'grid', ?string $technicalName = null, string $description = ''): DataResponse { + try { + return new DataResponse($this->viewService->create($title, $emoji, null, $this->userId, $technicalName, null, $type, $description)->jsonSerialize()); + } catch (PermissionError $e) { + return $this->handlePermissionError($e); + } catch (BadRequestError $e) { + return $this->handleBadRequestError($e); + } catch (InternalError $e) { + return $this->handleError($e); + } + } +} diff --git a/lib/ResponseDefinitions.php b/lib/ResponseDefinitions.php index 60b0d32899..e2e07bae94 100644 --- a/lib/ResponseDefinitions.php +++ b/lib/ResponseDefinitions.php @@ -65,6 +65,23 @@ * grid: array{widgets: list, layout: list}, * } * + * @psalm-type TablesGridWidgetProperty = array{ + * type: string, + * title: string, + * default: mixed, + * options?: list, + * required?: bool, + * } + * + * @psalm-type TablesGridWidgetType = array{ + * type: string, + * title: string, + * defaultWidth: int, + * defaultHeight: int, + * configuration: array, + * properties: array, + * } + * * @psalm-type TablesTable = array{ * id: int, * uuid: string, diff --git a/openapi.json b/openapi.json index 7ab01eead9..f2cbeb8aa7 100644 --- a/openapi.json +++ b/openapi.json @@ -394,6 +394,85 @@ } } }, + "GridWidgetProperty": { + "type": "object", + "required": [ + "type", + "title", + "default" + ], + "properties": { + "type": { + "type": "string" + }, + "title": { + "type": "string" + }, + "default": { + "type": "object" + }, + "options": { + "type": "array", + "items": { + "type": "object", + "required": [ + "value", + "label" + ], + "properties": { + "value": { + "type": "string" + }, + "label": { + "type": "string" + } + } + } + }, + "required": { + "type": "boolean" + } + } + }, + "GridWidgetType": { + "type": "object", + "required": [ + "type", + "title", + "defaultWidth", + "defaultHeight", + "configuration", + "properties" + ], + "properties": { + "type": { + "type": "string" + }, + "title": { + "type": "string" + }, + "defaultWidth": { + "type": "integer", + "format": "int64" + }, + "defaultHeight": { + "type": "integer", + "format": "int64" + }, + "configuration": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/GridWidgetProperty" + } + }, + "properties": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/GridWidgetProperty" + } + } + } + }, "ImportState": { "type": "object", "required": [ @@ -6769,6 +6848,344 @@ } } }, + "/ocs/v2.php/apps/tables/api/2/views/widget-types": { + "get": { + "operationId": "api_views-widget-types", + "summary": "[api v2] The widget types a grid view can hold", + "description": "Every type carries two schemas: the configuration of the widget on the page and its content.", + "tags": [ + "api_views" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Widget types returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GridWidgetType" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/tables/api/2/views": { + "post": { + "operationId": "api_views-create", + "summary": "[api v2] Create a view without a table, such as a grid view", + "description": "The view belongs to the user who creates it and can be placed in an application menu.", + "tags": [ + "api_views" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "title" + ], + "properties": { + "title": { + "type": "string", + "description": "Title of the view" + }, + "emoji": { + "type": "string", + "nullable": true, + "default": null, + "description": "Emoji shown with the title" + }, + "type": { + "type": "string", + "default": "grid", + "description": "Type of the view, `grid` for a page of widgets" + }, + "technicalName": { + "type": "string", + "nullable": true, + "default": null, + "description": "Technical name, lowercase letters, numbers and underscores" + }, + "description": { + "type": "string", + "default": "", + "description": "Description shown on the page" + } + } + } + } + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "View created", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "$ref": "#/components/schemas/View" + } + } + } + } + } + } + } + }, + "400": { + "description": "Invalid type or technical name", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "403": { + "description": "No permissions", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "500": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, "/ocs/v2.php/apps/tables/api/2/tables": { "get": { "operationId": "api_tables-index", diff --git a/src/types/openapi/openapi.ts b/src/types/openapi/openapi.ts index 7e2ea13246..5d6c41b386 100644 --- a/src/types/openapi/openapi.ts +++ b/src/types/openapi/openapi.ts @@ -508,6 +508,46 @@ export type paths = { readonly patch?: never; readonly trace?: never; }; + readonly "/ocs/v2.php/apps/tables/api/2/views/widget-types": { + readonly parameters: { + readonly query?: never; + readonly header?: never; + readonly path?: never; + readonly cookie?: never; + }; + /** + * [api v2] The widget types a grid view can hold + * @description Every type carries two schemas: the configuration of the widget on the page and its content. + */ + readonly get: operations["api_views-widget-types"]; + readonly put?: never; + readonly post?: never; + readonly delete?: never; + readonly options?: never; + readonly head?: never; + readonly patch?: never; + readonly trace?: never; + }; + readonly "/ocs/v2.php/apps/tables/api/2/views": { + readonly parameters: { + readonly query?: never; + readonly header?: never; + readonly path?: never; + readonly cookie?: never; + }; + readonly get?: never; + readonly put?: never; + /** + * [api v2] Create a view without a table, such as a grid view + * @description The view belongs to the user who creates it and can be placed in an application menu. + */ + readonly post: operations["api_views-create"]; + readonly delete?: never; + readonly options?: never; + readonly head?: never; + readonly patch?: never; + readonly trace?: never; + }; readonly "/ocs/v2.php/apps/tables/api/2/tables": { readonly parameters: { readonly query?: never; @@ -1184,6 +1224,30 @@ export type components = { readonly [key: string]: Record; }; }; + readonly GridWidgetProperty: { + readonly type: string; + readonly title: string; + readonly default: Record; + readonly options?: readonly { + readonly value: string; + readonly label: string; + }[]; + readonly required?: boolean; + }; + readonly GridWidgetType: { + readonly type: string; + readonly title: string; + /** Format: int64 */ + readonly defaultWidth: number; + /** Format: int64 */ + readonly defaultHeight: number; + readonly configuration: { + readonly [key: string]: components["schemas"]["GridWidgetProperty"]; + }; + readonly properties: { + readonly [key: string]: components["schemas"]["GridWidgetProperty"]; + }; + }; readonly ImportState: { /** Format: int64 */ readonly found_columns_count: number; @@ -4550,6 +4614,164 @@ export interface operations { }; }; }; + readonly "api_views-widget-types": { + readonly parameters: { + readonly query?: never; + readonly header: { + /** @description Required to be true for the API request to pass */ + readonly "OCS-APIRequest": boolean; + }; + readonly path?: never; + readonly cookie?: never; + }; + readonly requestBody?: never; + readonly responses: { + /** @description Widget types returned */ + readonly 200: { + headers: { + readonly [name: string]: unknown; + }; + content: { + readonly "application/json": { + readonly ocs: { + readonly meta: components["schemas"]["OCSMeta"]; + readonly data: readonly components["schemas"]["GridWidgetType"][]; + }; + }; + }; + }; + /** @description Current user is not logged in */ + readonly 401: { + headers: { + readonly [name: string]: unknown; + }; + content: { + readonly "application/json": { + readonly ocs: { + readonly meta: components["schemas"]["OCSMeta"]; + readonly data: unknown; + }; + }; + }; + }; + }; + }; + readonly "api_views-create": { + readonly parameters: { + readonly query?: never; + readonly header: { + /** @description Required to be true for the API request to pass */ + readonly "OCS-APIRequest": boolean; + }; + readonly path?: never; + readonly cookie?: never; + }; + readonly requestBody: { + readonly content: { + readonly "application/json": { + /** @description Title of the view */ + readonly title: string; + /** + * @description Emoji shown with the title + * @default null + */ + readonly emoji?: string | null; + /** + * @description Type of the view, `grid` for a page of widgets + * @default grid + */ + readonly type?: string; + /** + * @description Technical name, lowercase letters, numbers and underscores + * @default null + */ + readonly technicalName?: string | null; + /** + * @description Description shown on the page + * @default + */ + readonly description?: string; + }; + }; + }; + readonly responses: { + /** @description View created */ + readonly 200: { + headers: { + readonly [name: string]: unknown; + }; + content: { + readonly "application/json": { + readonly ocs: { + readonly meta: components["schemas"]["OCSMeta"]; + readonly data: components["schemas"]["View"]; + }; + }; + }; + }; + /** @description Invalid type or technical name */ + readonly 400: { + headers: { + readonly [name: string]: unknown; + }; + content: { + readonly "application/json": { + readonly ocs: { + readonly meta: components["schemas"]["OCSMeta"]; + readonly data: { + readonly message: string; + }; + }; + }; + }; + }; + /** @description Current user is not logged in */ + readonly 401: { + headers: { + readonly [name: string]: unknown; + }; + content: { + readonly "application/json": { + readonly ocs: { + readonly meta: components["schemas"]["OCSMeta"]; + readonly data: unknown; + }; + }; + }; + }; + /** @description No permissions */ + readonly 403: { + headers: { + readonly [name: string]: unknown; + }; + content: { + readonly "application/json": { + readonly ocs: { + readonly meta: components["schemas"]["OCSMeta"]; + readonly data: { + readonly message: string; + }; + }; + }; + }; + }; + readonly 500: { + headers: { + readonly [name: string]: unknown; + }; + content: { + readonly "application/json": { + readonly ocs: { + readonly meta: components["schemas"]["OCSMeta"]; + readonly data: { + readonly message: string; + }; + }; + }; + }; + }; + }; + }; readonly "api_tables-index": { readonly parameters: { readonly query?: never; diff --git a/tests/unit/Controller/ApiViewsControllerTest.php b/tests/unit/Controller/ApiViewsControllerTest.php new file mode 100644 index 0000000000..531689189b --- /dev/null +++ b/tests/unit/Controller/ApiViewsControllerTest.php @@ -0,0 +1,81 @@ +viewService = $this->createMock(ViewService::class); + $l10n = $this->createMock(IL10N::class); + $l10n->method('t')->willReturnArgument(0); + $this->gridWidgetTypes = new GridWidgetTypes($l10n, $this->createMock(ViewMapper::class)); + $this->controller = new ApiViewsController($this->createMock(IRequest::class), $this->createMock(LoggerInterface::class), $l10n, 'alice', $this->viewService, $this->gridWidgetTypes); + } + + public function testWidgetTypesListsEveryTypeWithBothSchemas(): void { + $types = $this->controller->widgetTypes()->getData(); + + $this->assertCount(count($this->gridWidgetTypes->all()), $types); + foreach ($types as $type) { + $this->assertArrayHasKey('configuration', $type); + $this->assertArrayHasKey('properties', $type); + } + } + + public function testCreateHandsTheStandaloneViewToTheService(): void { + $view = new View(); + $view->setId(6); + $view->setType(View::TYPE_GRID); + $view->setCreatedBy('alice'); + $this->viewService->expects($this->once()) + ->method('create') + ->with('Home', '🧩', null, 'alice', 'home', null, View::TYPE_GRID, 'Start here') + ->willReturn($view); + + $response = $this->controller->create('Home', '🧩', 'grid', 'home', 'Start here'); + + $this->assertSame(Http::STATUS_OK, $response->getStatus()); + $this->assertSame(6, $response->getData()['id']); + } + + public function testCreateTurnsABadRequestInto400(): void { + $this->viewService->method('create')->willThrowException(new BadRequestError('Technical name must start with a lowercase letter')); + + $response = $this->controller->create('Home', null, 'grid', 'Not Valid'); + + $this->assertSame(Http::STATUS_BAD_REQUEST, $response->getStatus()); + } + + public function testCreateTurnsAPermissionErrorInto403(): void { + $this->viewService->method('create')->willThrowException(new PermissionError('no')); + + $response = $this->controller->create('Home'); + + $this->assertSame(Http::STATUS_FORBIDDEN, $response->getStatus()); + } +} From 777c1b01698065ed902d5e563da4959bfc535101 Mon Sep 17 00:00:00 2001 From: Remko Date: Mon, 12 Oct 2026 13:50:34 +0200 Subject: [PATCH 2/2] fix(api): validate grid view creation and route it on the controller - the title and emoji of a new grid view are validated like on update, so an empty or too long title or an invalid emoji is a 400 instead of a 200 or a database error - the endpoint drops the technicalName and type parameters: a view without a table is named by its id and is always a grid view - widget property and widget types are typed as their known values - both routes are declared with #[ApiRoute] on the controller; the spec moves them, which reorders openapi.json Assisted-by: ClaudeCode:claude-opus-5-5 Signed-off-by: Remko --- appinfo/routes.php | 4 - lib/Controller/ApiViewsController.php | 24 +- lib/ResponseDefinitions.php | 4 +- openapi.json | 2609 +++++++++-------- src/types/openapi/openapi.ts | 392 ++- .../Controller/ApiViewsControllerTest.php | 27 +- 6 files changed, 1541 insertions(+), 1519 deletions(-) diff --git a/appinfo/routes.php b/appinfo/routes.php index ffc584bc73..ad9b79e77e 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -128,10 +128,6 @@ // API v2 ['name' => 'ApiGeneral#index', 'url' => '/api/2/init', 'verb' => 'GET'], // -> tables - // views without a table and the widget types their grids hold - ['name' => 'ApiViews#widgetTypes', 'url' => '/api/2/views/widget-types', 'verb' => 'GET'], - ['name' => 'ApiViews#create', 'url' => '/api/2/views', 'verb' => 'POST'], - ['name' => 'ApiTables#index', 'url' => '/api/2/tables', 'verb' => 'GET'], ['name' => 'ApiTables#show', 'url' => '/api/2/tables/{id}', 'verb' => 'GET'], ['name' => 'ApiTables#showScheme', 'url' => '/api/2/tables/scheme/{id}', 'verb' => 'GET'], diff --git a/lib/Controller/ApiViewsController.php b/lib/Controller/ApiViewsController.php index b202836da4..9a69a89509 100644 --- a/lib/Controller/ApiViewsController.php +++ b/lib/Controller/ApiViewsController.php @@ -9,13 +9,18 @@ namespace OCA\Tables\Controller; +use InvalidArgumentException; +use OCA\Tables\Db\View; use OCA\Tables\Errors\BadRequestError; use OCA\Tables\Errors\InternalError; use OCA\Tables\Errors\PermissionError; use OCA\Tables\ResponseDefinitions; use OCA\Tables\Service\GridWidgetTypes; +use OCA\Tables\Service\ValueObject\Emoji; +use OCA\Tables\Service\ValueObject\Title; use OCA\Tables\Service\ViewService; use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Attribute\ApiRoute; use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\Attribute\UserRateLimit; use OCP\AppFramework\Http\DataResponse; @@ -49,31 +54,38 @@ public function __construct( * 200: Widget types returned */ #[NoAdminRequired] + #[ApiRoute(verb: 'GET', url: '/api/2/views/widget-types')] public function widgetTypes(): DataResponse { return new DataResponse(array_values($this->gridWidgetTypes->all())); } /** - * [api v2] Create a view without a table, such as a grid view + * [api v2] Create a grid view, a view without a table * * The view belongs to the user who creates it and can be placed in an application menu. + * It is named by its id, so it takes no technical name. * * @param string $title Title of the view * @param string|null $emoji Emoji shown with the title - * @param string $type Type of the view, `grid` for a page of widgets - * @param string|null $technicalName Technical name, lowercase letters, numbers and underscores * @param string $description Description shown on the page * @return DataResponse|DataResponse * * 200: View created - * 400: Invalid type or technical name + * 400: Invalid title or emoji * 403: No permissions */ #[NoAdminRequired] #[UserRateLimit(limit: 20, period: 60)] - public function create(string $title, ?string $emoji = null, string $type = 'grid', ?string $technicalName = null, string $description = ''): DataResponse { + #[ApiRoute(verb: 'POST', url: '/api/2/views')] + public function create(string $title, ?string $emoji = null, string $description = ''): DataResponse { try { - return new DataResponse($this->viewService->create($title, $emoji, null, $this->userId, $technicalName, null, $type, $description)->jsonSerialize()); + $validTitle = (string)new Title($title); + $validEmoji = $emoji === null || $emoji === '' ? null : (string)new Emoji($emoji); + } catch (InvalidArgumentException $e) { + return $this->handleBadRequestError(new BadRequestError($e->getMessage(), $e->getCode(), $e)); + } + try { + return new DataResponse($this->viewService->create($validTitle, $validEmoji, null, $this->userId, null, null, View::TYPE_GRID, $description)->jsonSerialize()); } catch (PermissionError $e) { return $this->handlePermissionError($e); } catch (BadRequestError $e) { diff --git a/lib/ResponseDefinitions.php b/lib/ResponseDefinitions.php index d099db6717..0d76d7e377 100644 --- a/lib/ResponseDefinitions.php +++ b/lib/ResponseDefinitions.php @@ -69,7 +69,7 @@ * } * * @psalm-type TablesGridWidgetProperty = array{ - * type: string, + * type: 'string'|'text'|'color'|'boolean'|'integer'|'enum'|'target', * title: string, * default: TablesGridWidgetValue, * options?: list, @@ -77,7 +77,7 @@ * } * * @psalm-type TablesGridWidgetType = array{ - * type: string, + * type: 'header'|'text'|'data', * title: string, * defaultWidth: int, * defaultHeight: int, diff --git a/openapi.json b/openapi.json index e17f9f892b..41fefca0a7 100644 --- a/openapi.json +++ b/openapi.json @@ -406,7 +406,16 @@ ], "properties": { "type": { - "type": "string" + "type": "string", + "enum": [ + "string", + "text", + "color", + "boolean", + "integer", + "enum", + "target" + ] }, "title": { "type": "string" @@ -449,7 +458,12 @@ ], "properties": { "type": { - "type": "string" + "type": "string", + "enum": [ + "header", + "text", + "data" + ] }, "title": { "type": "string" @@ -6886,13 +6900,12 @@ } } }, - "/ocs/v2.php/apps/tables/api/2/views/widget-types": { + "/ocs/v2.php/apps/tables/api/2/tables": { "get": { - "operationId": "api_views-widget-types", - "summary": "[api v2] The widget types a grid view can hold", - "description": "Every type carries two schemas: the configuration of the widget on the page and its content.", + "operationId": "api_tables-index", + "summary": "[api v2] Returns all Tables", "tags": [ - "api_views" + "api_tables" ], "security": [ { @@ -6916,7 +6929,7 @@ ], "responses": { "200": { - "description": "Widget types returned", + "description": "Tables returned", "content": { "application/json": { "schema": { @@ -6938,7 +6951,45 @@ "data": { "type": "array", "items": { - "$ref": "#/components/schemas/GridWidgetType" + "$ref": "#/components/schemas/Table" + } + } + } + } + } + } + } + } + }, + "500": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } } } } @@ -6977,15 +7028,12 @@ } } } - } - }, - "/ocs/v2.php/apps/tables/api/2/views": { + }, "post": { - "operationId": "api_views-create", - "summary": "[api v2] Create a view without a table, such as a grid view", - "description": "The view belongs to the user who creates it and can be placed in an application menu.", + "operationId": "api_tables-create", + "summary": "[api v2] Create a new table and return it", "tags": [ - "api_views" + "api_tables" ], "security": [ { @@ -7007,29 +7055,22 @@ "properties": { "title": { "type": "string", - "description": "Title of the view" + "description": "Title of the table" }, "emoji": { "type": "string", "nullable": true, - "default": null, - "description": "Emoji shown with the title" - }, - "type": { - "type": "string", - "default": "grid", - "description": "Type of the view, `grid` for a page of widgets" + "description": "Emoji for the table" }, - "technicalName": { + "description": { "type": "string", "nullable": true, - "default": null, - "description": "Technical name, lowercase letters, numbers and underscores" + "description": "Description for the table" }, - "description": { + "template": { "type": "string", - "default": "", - "description": "Description shown on the page" + "default": "custom", + "description": "Template to use if wanted" } } } @@ -7050,7 +7091,7 @@ ], "responses": { "200": { - "description": "View created", + "description": "Tables returned", "content": { "application/json": { "schema": { @@ -7070,7 +7111,7 @@ "$ref": "#/components/schemas/OCSMeta" }, "data": { - "$ref": "#/components/schemas/View" + "$ref": "#/components/schemas/Table" } } } @@ -7080,45 +7121,7 @@ } }, "400": { - "description": "Invalid type or technical name", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "message" - ], - "properties": { - "message": { - "type": "string" - } - } - } - } - } - } - } - } - } - }, - "403": { - "description": "No permissions", + "description": "Invalid request data", "content": { "application/json": { "schema": { @@ -7224,10 +7227,10 @@ } } }, - "/ocs/v2.php/apps/tables/api/2/tables": { + "/ocs/v2.php/apps/tables/api/2/tables/{id}": { "get": { - "operationId": "api_tables-index", - "summary": "[api v2] Returns all Tables", + "operationId": "api_tables-show", + "summary": "[api v2] Get a table object", "tags": [ "api_tables" ], @@ -7240,6 +7243,16 @@ } ], "parameters": [ + { + "name": "id", + "in": "path", + "description": "Table ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, { "name": "OCS-APIRequest", "in": "header", @@ -7253,7 +7266,7 @@ ], "responses": { "200": { - "description": "Tables returned", + "description": "Table returned", "content": { "application/json": { "schema": { @@ -7273,10 +7286,7 @@ "$ref": "#/components/schemas/OCSMeta" }, "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Table" - } + "$ref": "#/components/schemas/Table" } } } @@ -7285,8 +7295,8 @@ } } }, - "500": { - "description": "", + "403": { + "description": "No permissions", "content": { "application/json": { "schema": { @@ -7323,8 +7333,8 @@ } } }, - "401": { - "description": "Current user is not logged in", + "500": { + "description": "", "content": { "application/json": { "schema": { @@ -7343,79 +7353,26 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } } } } } } } - } - } - }, - "post": { - "operationId": "api_tables-create", - "summary": "[api v2] Create a new table and return it", - "tags": [ - "api_tables" - ], - "security": [ - { - "bearer_auth": [] }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "title" - ], - "properties": { - "title": { - "type": "string", - "description": "Title of the table" - }, - "emoji": { - "type": "string", - "nullable": true, - "description": "Emoji for the table" - }, - "description": { - "type": "string", - "nullable": true, - "description": "Description for the table" - }, - "template": { - "type": "string", - "default": "custom", - "description": "Template to use if wanted" - } - } - } - } - } - }, - "parameters": [ - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Tables returned", + "404": { + "description": "Not found", "content": { "application/json": { "schema": { @@ -7435,7 +7392,15 @@ "$ref": "#/components/schemas/OCSMeta" }, "data": { - "$ref": "#/components/schemas/Table" + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } } } } @@ -7444,297 +7409,8 @@ } } }, - "400": { - "description": "Invalid request data", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "message" - ], - "properties": { - "message": { - "type": "string" - } - } - } - } - } - } - } - } - } - }, - "500": { - "description": "", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "message" - ], - "properties": { - "message": { - "type": "string" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/tables/api/2/tables/{id}": { - "get": { - "operationId": "api_tables-show", - "summary": "[api v2] Get a table object", - "tags": [ - "api_tables" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Table ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Table returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "$ref": "#/components/schemas/Table" - } - } - } - } - } - } - } - }, - "403": { - "description": "No permissions", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "message" - ], - "properties": { - "message": { - "type": "string" - } - } - } - } - } - } - } - } - } - }, - "500": { - "description": "", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "message" - ], - "properties": { - "message": { - "type": "string" - } - } - } - } - } - } - } - } - } - }, - "404": { - "description": "Not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "message" - ], - "properties": { - "message": { - "type": "string" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", + "401": { + "description": "Current user is not logged in", "content": { "application/json": { "schema": { @@ -11626,9 +11302,275 @@ } } } - } - }, - "parameters": [ + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Column created", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "$ref": "#/components/schemas/Column" + } + } + } + } + } + } + } + }, + "400": { + "description": "Invalid request data", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "403": { + "description": "No permission", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "500": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + }, + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/tables/api/2/favorites/{nodeType}/{nodeId}": { + "post": { + "operationId": "api_favorite-create", + "summary": "[api v2] Add a node (table or view) to user favorites", + "tags": [ + "api_favorite" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "nodeType", + "in": "path", + "description": "any Application::NODE_TYPE_* constant", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "nodeId", + "in": "path", + "description": "identifier of the node", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, { "name": "OCS-APIRequest", "in": "header", @@ -11642,37 +11584,7 @@ ], "responses": { "200": { - "description": "Column created", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "$ref": "#/components/schemas/Column" - } - } - } - } - } - } - } - }, - "400": { - "description": "Invalid request data", + "description": "Tables returned", "content": { "application/json": { "schema": { @@ -11692,15 +11604,7 @@ "$ref": "#/components/schemas/OCSMeta" }, "data": { - "type": "object", - "required": [ - "message" - ], - "properties": { - "message": { - "type": "string" - } - } + "type": "object" } } } @@ -11710,7 +11614,7 @@ } }, "403": { - "description": "No permission", + "description": "No permissions", "content": { "application/json": { "schema": { @@ -11782,11 +11686,6 @@ } } } - }, - "text/plain": { - "schema": { - "type": "string" - } } } }, @@ -11857,12 +11756,10 @@ } } } - } - }, - "/ocs/v2.php/apps/tables/api/2/favorites/{nodeType}/{nodeId}": { - "post": { - "operationId": "api_favorite-create", - "summary": "[api v2] Add a node (table or view) to user favorites", + }, + "delete": { + "operationId": "api_favorite-destroy", + "summary": "[api v2] Remove a node (table or view) to from favorites", "tags": [ "api_favorite" ], @@ -11908,7 +11805,7 @@ ], "responses": { "200": { - "description": "Tables returned", + "description": "Deleted table returned", "content": { "application/json": { "schema": { @@ -12064,14 +11961,215 @@ "ocs": { "type": "object", "required": [ - "meta", - "data" + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/tables/api/2/contexts": { + "get": { + "operationId": "context-index", + "summary": "[api v2] Get all contexts available to the requesting person", + "description": "Return an empty array if no contexts were found", + "tags": [ + "context" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "reporting in available contexts", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Context" + } + } + } + } + } + } + } + } + }, + "500": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "post": { + "operationId": "context-create", + "summary": "[api v2] Create a new context and return it", + "tags": [ + "context" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "name", + "iconName" + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the context" + }, + "iconName": { + "type": "string", + "description": "Material design icon name of the context" + }, + "description": { + "type": "string", + "default": "", + "description": "Descriptive text of the context" + }, + "nodes": { + "type": "array", + "default": [], + "description": "optional nodes to be connected to this context", + "items": { + "type": "object", + "required": [ + "id", + "type" ], "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" + "id": { + "type": "integer", + "format": "int64" }, - "data": {} + "type": { + "type": "integer", + "format": "int64" + }, + "permissions": { + "type": "integer", + "format": "int64" + } } } } @@ -12079,43 +12177,8 @@ } } } - } - }, - "delete": { - "operationId": "api_favorite-destroy", - "summary": "[api v2] Remove a node (table or view) to from favorites", - "tags": [ - "api_favorite" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], + }, "parameters": [ - { - "name": "nodeType", - "in": "path", - "description": "any Application::NODE_TYPE_* constant", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "nodeId", - "in": "path", - "description": "identifier of the node", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, { "name": "OCS-APIRequest", "in": "header", @@ -12129,7 +12192,7 @@ ], "responses": { "200": { - "description": "Deleted table returned", + "description": "returning the full context information", "content": { "application/json": { "schema": { @@ -12149,7 +12212,7 @@ "$ref": "#/components/schemas/OCSMeta" }, "data": { - "type": "object" + "$ref": "#/components/schemas/Context" } } } @@ -12158,8 +12221,8 @@ } } }, - "403": { - "description": "No permissions", + "500": { + "description": "", "content": { "application/json": { "schema": { @@ -12196,8 +12259,8 @@ } } }, - "500": { - "description": "", + "400": { + "description": "invalid parameters were supplied", "content": { "application/json": { "schema": { @@ -12234,8 +12297,8 @@ } } }, - "404": { - "description": "Not found", + "403": { + "description": "lacking permissions on a resource", "content": { "application/json": { "schema": { @@ -12303,11 +12366,10 @@ } } }, - "/ocs/v2.php/apps/tables/api/2/contexts": { + "/ocs/v2.php/apps/tables/api/2/contexts/{contextId}": { "get": { - "operationId": "context-index", - "summary": "[api v2] Get all contexts available to the requesting person", - "description": "Return an empty array if no contexts were found", + "operationId": "context-show", + "summary": "[api v2] Get information about the requests context", "tags": [ "context" ], @@ -12320,6 +12382,16 @@ } ], "parameters": [ + { + "name": "contextId", + "in": "path", + "description": "ID of the context", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, { "name": "OCS-APIRequest", "in": "header", @@ -12333,7 +12405,7 @@ ], "responses": { "200": { - "description": "reporting in available contexts", + "description": "returning the full context information", "content": { "application/json": { "schema": { @@ -12353,10 +12425,7 @@ "$ref": "#/components/schemas/OCSMeta" }, "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Context" - } + "$ref": "#/components/schemas/Context" } } } @@ -12403,6 +12472,44 @@ } } }, + "404": { + "description": "context not found or not available anymore", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, "401": { "description": "Current user is not logged in", "content": { @@ -12433,9 +12540,9 @@ } } }, - "post": { - "operationId": "context-create", - "summary": "[api v2] Create a new context and return it", + "put": { + "operationId": "context-update", + "summary": "[api v2] Update an existing context and return it", "tags": [ "context" ], @@ -12448,52 +12555,53 @@ } ], "requestBody": { - "required": true, + "required": false, "content": { "application/json": { "schema": { "type": "object", - "required": [ - "name", - "iconName" - ], "properties": { "name": { "type": "string", - "description": "Name of the context" + "nullable": true, + "description": "provide this parameter to set a new name" }, "iconName": { "type": "string", - "description": "Material design icon name of the context" + "nullable": true, + "description": "provide this parameter to set a new icon" }, "description": { "type": "string", - "default": "", - "description": "Descriptive text of the context" + "nullable": true, + "description": "provide this parameter to set a new description" }, "nodes": { - "type": "array", - "default": [], - "description": "optional nodes to be connected to this context", - "items": { - "type": "object", - "required": [ - "id", - "type" - ], - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "type": { - "type": "integer", - "format": "int64" - }, - "permissions": { - "type": "integer", - "format": "int64" - } + "type": "object", + "nullable": true, + "description": "provide this parameter to set a new list of nodes.", + "required": [ + "id", + "type", + "permissions", + "order" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "type": { + "type": "integer", + "format": "int64" + }, + "permissions": { + "type": "integer", + "format": "int64" + }, + "order": { + "type": "integer", + "format": "int64" } } } @@ -12503,6 +12611,16 @@ } }, "parameters": [ + { + "name": "contextId", + "in": "path", + "description": "ID of the context", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, { "name": "OCS-APIRequest", "in": "header", @@ -12536,7 +12654,45 @@ "$ref": "#/components/schemas/OCSMeta" }, "data": { - "$ref": "#/components/schemas/Context" + "$ref": "#/components/schemas/Context" + } + } + } + } + } + } + } + }, + "500": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } } } } @@ -12545,8 +12701,8 @@ } } }, - "500": { - "description": "", + "404": { + "description": "Not found", "content": { "application/json": { "schema": { @@ -12583,8 +12739,8 @@ } } }, - "400": { - "description": "invalid parameters were supplied", + "403": { + "description": "No permissions", "content": { "application/json": { "schema": { @@ -12621,8 +12777,8 @@ } } }, - "403": { - "description": "lacking permissions on a resource", + "400": { + "description": "bad request", "content": { "application/json": { "schema": { @@ -12688,12 +12844,10 @@ } } } - } - }, - "/ocs/v2.php/apps/tables/api/2/contexts/{contextId}": { - "get": { - "operationId": "context-show", - "summary": "[api v2] Get information about the requests context", + }, + "delete": { + "operationId": "context-destroy", + "summary": "[api v2] Delete an existing context and return it", "tags": [ "context" ], @@ -12797,7 +12951,45 @@ } }, "404": { - "description": "context not found or not available anymore", + "description": "Not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "403": { + "description": "No permissions", "content": { "application/json": { "schema": { @@ -12863,10 +13055,12 @@ } } } - }, - "put": { - "operationId": "context-update", - "summary": "[api v2] Update an existing context and return it", + } + }, + "/ocs/v2.php/apps/tables/api/2/contexts/{contextId}/scheme/export": { + "get": { + "operationId": "context-export-scheme", + "summary": "[api v2] Export the scheme of a context", "tags": [ "context" ], @@ -12878,62 +13072,6 @@ "basic_auth": [] } ], - "requestBody": { - "required": false, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "description": "provide this parameter to set a new name" - }, - "iconName": { - "type": "string", - "nullable": true, - "description": "provide this parameter to set a new icon" - }, - "description": { - "type": "string", - "nullable": true, - "description": "provide this parameter to set a new description" - }, - "nodes": { - "type": "object", - "nullable": true, - "description": "provide this parameter to set a new list of nodes.", - "required": [ - "id", - "type", - "permissions", - "order" - ], - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "type": { - "type": "integer", - "format": "int64" - }, - "permissions": { - "type": "integer", - "format": "int64" - }, - "order": { - "type": "integer", - "format": "int64" - } - } - } - } - } - } - } - }, "parameters": [ { "name": "contextId", @@ -12958,7 +13096,7 @@ ], "responses": { "200": { - "description": "returning the full context information", + "description": "returning the scheme of the context", "content": { "application/json": { "schema": { @@ -12978,7 +13116,10 @@ "$ref": "#/components/schemas/OCSMeta" }, "data": { - "$ref": "#/components/schemas/Context" + "type": "object", + "additionalProperties": { + "type": "object" + } } } } @@ -13101,44 +13242,6 @@ } } }, - "400": { - "description": "bad request", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "message" - ], - "properties": { - "message": { - "type": "string" - } - } - } - } - } - } - } - } - } - }, "401": { "description": "Current user is not logged in", "content": { @@ -13168,10 +13271,12 @@ } } } - }, - "delete": { - "operationId": "context-destroy", - "summary": "[api v2] Delete an existing context and return it", + } + }, + "/ocs/v2.php/apps/tables/api/2/contexts/{contextId}/scheme/preview-changes": { + "post": { + "operationId": "context-preview-scheme-changes", + "summary": "[api v2] Preview the changes that would be applied to a context scheme", "tags": [ "context" ], @@ -13183,6 +13288,25 @@ "basic_auth": [] } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "updateScheme" + ], + "properties": { + "updateScheme": { + "$ref": "#/components/schemas/Context", + "description": "New scheme of the context" + } + } + } + } + } + }, "parameters": [ { "name": "contextId", @@ -13207,7 +13331,7 @@ ], "responses": { "200": { - "description": "returning the full context information", + "description": "returning the changes that would be applied to the context scheme", "content": { "application/json": { "schema": { @@ -13227,7 +13351,48 @@ "$ref": "#/components/schemas/OCSMeta" }, "data": { - "$ref": "#/components/schemas/Context" + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "500": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } } } } @@ -13236,8 +13401,8 @@ } } }, - "500": { - "description": "", + "404": { + "description": "Not found", "content": { "application/json": { "schema": { @@ -13274,8 +13439,8 @@ } } }, - "404": { - "description": "Not found", + "403": { + "description": "No permissions", "content": { "application/json": { "schema": { @@ -13312,8 +13477,8 @@ } } }, - "403": { - "description": "No permissions", + "400": { + "description": "Bad request", "content": { "application/json": { "schema": { @@ -13381,10 +13546,10 @@ } } }, - "/ocs/v2.php/apps/tables/api/2/contexts/{contextId}/scheme/export": { - "get": { - "operationId": "context-export-scheme", - "summary": "[api v2] Export the scheme of a context", + "/ocs/v2.php/apps/tables/api/2/contexts/{contextId}/scheme/import": { + "post": { + "operationId": "context-import-scheme", + "summary": "[api v2] Import the scheme of a context", "tags": [ "context" ], @@ -13396,6 +13561,84 @@ "basic_auth": [] } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "name", + "iconName", + "description", + "nodes", + "tables" + ], + "properties": { + "name": { + "type": "string", + "description": "Title of the context" + }, + "iconName": { + "type": "string", + "description": "Identifier of the context icon" + }, + "description": { + "type": "string", + "description": "Description of the context" + }, + "nodes": { + "type": "array", + "description": "Ordered meta data of the related nodes", + "items": { + "type": "object", + "required": [ + "node_type", + "node_uuid", + "permissions" + ], + "properties": { + "node_type": { + "type": "integer", + "format": "int64" + }, + "node_uuid": { + "type": "string" + }, + "permissions": { + "type": "integer", + "format": "int64" + } + } + } + }, + "tables": { + "type": "object", + "description": "Tables to be added or modified", + "required": [ + "addTables", + "modifyTables" + ], + "properties": { + "addTables": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Table" + } + }, + "modifyTables": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Table" + } + } + } + } + } + } + } + } + }, "parameters": [ { "name": "contextId", @@ -13420,7 +13663,7 @@ ], "responses": { "200": { - "description": "returning the scheme of the context", + "description": "context updated successfully", "content": { "application/json": { "schema": { @@ -13566,6 +13809,44 @@ } } }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, "401": { "description": "Current user is not logged in", "content": { @@ -13597,10 +13878,10 @@ } } }, - "/ocs/v2.php/apps/tables/api/2/contexts/{contextId}/scheme/preview-changes": { - "post": { - "operationId": "context-preview-scheme-changes", - "summary": "[api v2] Preview the changes that would be applied to a context scheme", + "/ocs/v2.php/apps/tables/api/2/contexts/{contextId}/transfer": { + "put": { + "operationId": "context-transfer", + "summary": "[api v2] Transfer the ownership of a context and return it", "tags": [ "context" ], @@ -13619,12 +13900,20 @@ "schema": { "type": "object", "required": [ - "updateScheme" + "newOwnerId" ], "properties": { - "updateScheme": { - "$ref": "#/components/schemas/Context", - "description": "New scheme of the context" + "newOwnerId": { + "type": "string", + "description": "ID of the new owner" + }, + "newOwnerType": { + "type": "integer", + "format": "int64", + "default": 0, + "description": "any Application::OWNER_TYPE_* constant", + "minimum": 0, + "maximum": 0 } } } @@ -13639,7 +13928,8 @@ "required": true, "schema": { "type": "integer", - "format": "int64" + "format": "int64", + "minimum": 0 } }, { @@ -13655,7 +13945,7 @@ ], "responses": { "200": { - "description": "returning the changes that would be applied to the context scheme", + "description": "Ownership transferred", "content": { "application/json": { "schema": { @@ -13675,10 +13965,7 @@ "$ref": "#/components/schemas/OCSMeta" }, "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } + "$ref": "#/components/schemas/Context" } } } @@ -13725,8 +14012,8 @@ } } }, - "404": { - "description": "Not found", + "403": { + "description": "No permissions", "content": { "application/json": { "schema": { @@ -13763,8 +14050,8 @@ } } }, - "403": { - "description": "No permissions", + "404": { + "description": "Not found", "content": { "application/json": { "schema": { @@ -13802,7 +14089,7 @@ } }, "400": { - "description": "Bad request", + "description": "Invalid request", "content": { "application/json": { "schema": { @@ -13862,99 +14149,54 @@ "data": {} } } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/tables/api/2/contexts/{contextId}/scheme/import": { - "post": { - "operationId": "context-import-scheme", - "summary": "[api v2] Import the scheme of a context", - "tags": [ - "context" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "name", - "iconName", - "description", - "nodes", - "tables" - ], - "properties": { - "name": { - "type": "string", - "description": "Title of the context" - }, - "iconName": { - "type": "string", - "description": "Identifier of the context icon" - }, - "description": { - "type": "string", - "description": "Description of the context" - }, - "nodes": { - "type": "array", - "description": "Ordered meta data of the related nodes", - "items": { - "type": "object", - "required": [ - "node_type", - "node_uuid", - "permissions" - ], - "properties": { - "node_type": { - "type": "integer", - "format": "int64" - }, - "node_uuid": { - "type": "string" - }, - "permissions": { - "type": "integer", - "format": "int64" - } - } - } - }, - "tables": { + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/tables/api/2/contexts/{contextId}/pages/{pageId}": { + "put": { + "operationId": "context-update-content-order", + "summary": "[api v2] Update the order on a page of a context", + "tags": [ + "context" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "content" + ], + "properties": { + "content": { "type": "object", - "description": "Tables to be added or modified", + "description": "content items with it and order values", "required": [ - "addTables", - "modifyTables" + "id", + "order" ], "properties": { - "addTables": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Table" - } + "id": { + "type": "integer", + "format": "int64" }, - "modifyTables": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Table" - } + "order": { + "type": "integer", + "format": "int64" } } } @@ -13974,6 +14216,16 @@ "format": "int64" } }, + { + "name": "pageId", + "in": "path", + "description": "ID of the page", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, { "name": "OCS-APIRequest", "in": "header", @@ -13987,7 +14239,7 @@ ], "responses": { "200": { - "description": "context updated successfully", + "description": "content updated successfully", "content": { "application/json": { "schema": { @@ -14007,10 +14259,7 @@ "$ref": "#/components/schemas/OCSMeta" }, "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } + "$ref": "#/components/schemas/Context" } } } @@ -14134,7 +14383,7 @@ } }, "400": { - "description": "Bad request", + "description": "Invalid request", "content": { "application/json": { "schema": { @@ -14202,12 +14451,12 @@ } } }, - "/ocs/v2.php/apps/tables/api/2/contexts/{contextId}/transfer": { - "put": { - "operationId": "context-transfer", - "summary": "[api v2] Transfer the ownership of a context and return it", + "/ocs/v2.php/apps/tables/api/2/config/table/{id}": { + "get": { + "operationId": "config-get-table-config", + "summary": "Gets the config for a specific table", "tags": [ - "context" + "config" ], "security": [ { @@ -14217,43 +14466,15 @@ "basic_auth": [] } ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "newOwnerId" - ], - "properties": { - "newOwnerId": { - "type": "string", - "description": "ID of the new owner" - }, - "newOwnerType": { - "type": "integer", - "format": "int64", - "default": 0, - "description": "any Application::OWNER_TYPE_* constant", - "minimum": 0, - "maximum": 0 - } - } - } - } - } - }, "parameters": [ { - "name": "contextId", + "name": "id", "in": "path", - "description": "ID of the context", + "description": "Table id", "required": true, "schema": { "type": "integer", - "format": "int64", - "minimum": 0 + "format": "int64" } }, { @@ -14269,7 +14490,7 @@ ], "responses": { "200": { - "description": "Ownership transferred", + "description": "Table config returned", "content": { "application/json": { "schema": { @@ -14289,7 +14510,7 @@ "$ref": "#/components/schemas/OCSMeta" }, "data": { - "$ref": "#/components/schemas/Context" + "$ref": "#/components/schemas/NotifyConfig" } } } @@ -14298,8 +14519,8 @@ } } }, - "500": { - "description": "", + "401": { + "description": "Current user is not logged in", "content": { "application/json": { "schema": { @@ -14318,102 +14539,57 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": { - "type": "object", - "required": [ - "message" - ], - "properties": { - "message": { - "type": "string" - } - } - } + "data": {} } } } } } } + } + } + } + }, + "/ocs/v2.php/apps/tables/api/2/config/view/{id}": { + "get": { + "operationId": "config-get-view-config", + "summary": "Gets the config for a specific view", + "tags": [ + "config" + ], + "security": [ + { + "bearer_auth": [] }, - "403": { - "description": "No permissions", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "message" - ], - "properties": { - "message": { - "type": "string" - } - } - } - } - } - } - } - } + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "View id", + "required": true, + "schema": { + "type": "integer", + "format": "int64" } }, - "404": { - "description": "Not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "message" - ], - "properties": { - "message": { - "type": "string" - } - } - } - } - } - } - } - } + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true } - }, - "400": { - "description": "Invalid request", + } + ], + "responses": { + "200": { + "description": "View config returned", "content": { "application/json": { "schema": { @@ -14433,15 +14609,7 @@ "$ref": "#/components/schemas/OCSMeta" }, "data": { - "type": "object", - "required": [ - "message" - ], - "properties": { - "message": { - "type": "string" - } - } + "$ref": "#/components/schemas/NotifyConfig" } } } @@ -14481,12 +14649,12 @@ } } }, - "/ocs/v2.php/apps/tables/api/2/contexts/{contextId}/pages/{pageId}": { - "put": { - "operationId": "context-update-content-order", - "summary": "[api v2] Update the order on a page of a context", + "/ocs/v2.php/apps/tables/api/2/config/{key}": { + "post": { + "operationId": "config-set-value", + "summary": "Sets a config value for a specific key", "tags": [ - "context" + "config" ], "security": [ { @@ -14503,26 +14671,12 @@ "schema": { "type": "object", "required": [ - "content" + "value" ], "properties": { - "content": { + "value": { "type": "object", - "description": "content items with it and order values", - "required": [ - "id", - "order" - ], - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "order": { - "type": "integer", - "format": "int64" - } - } + "description": "Config value" } } } @@ -14531,23 +14685,12 @@ }, "parameters": [ { - "name": "contextId", - "in": "path", - "description": "ID of the context", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "pageId", + "name": "key", "in": "path", - "description": "ID of the page", + "description": "Config key", "required": true, "schema": { - "type": "integer", - "format": "int64" + "type": "string" } }, { @@ -14563,37 +14706,7 @@ ], "responses": { "200": { - "description": "content updated successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "$ref": "#/components/schemas/Context" - } - } - } - } - } - } - } - }, - "500": { - "description": "", + "description": "Config updated", "content": { "application/json": { "schema": { @@ -14613,15 +14726,7 @@ "$ref": "#/components/schemas/OCSMeta" }, "data": { - "type": "object", - "required": [ - "message" - ], - "properties": { - "message": { - "type": "string" - } - } + "type": "boolean" } } } @@ -14630,8 +14735,8 @@ } } }, - "404": { - "description": "Not found", + "400": { + "description": "bad request", "content": { "application/json": { "schema": { @@ -14706,143 +14811,6 @@ } } }, - "400": { - "description": "Invalid request", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "message" - ], - "properties": { - "message": { - "type": "string" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/tables/api/2/config/table/{id}": { - "get": { - "operationId": "config-get-table-config", - "summary": "Gets the config for a specific table", - "tags": [ - "config" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Table id", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Table config returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "$ref": "#/components/schemas/NotifyConfig" - } - } - } - } - } - } - } - }, "401": { "description": "Current user is not logged in", "content": { @@ -14874,14 +14842,16 @@ } } }, - "/ocs/v2.php/apps/tables/api/2/config/view/{id}": { + "/ocs/v2.php/apps/tables/api/2/public/{token}/columns": { "get": { - "operationId": "config-get-view-config", - "summary": "Gets the config for a specific view", + "operationId": "api_public_columns-index-by-public-link", + "summary": "[api v2] Get all columns for a table or a view shared by link", + "description": "Return an empty array if no columns were found", "tags": [ - "config" + "api_public_columns" ], "security": [ + {}, { "bearer_auth": [] }, @@ -14891,13 +14861,13 @@ ], "parameters": [ { - "name": "id", + "name": "token", "in": "path", - "description": "View id", + "description": "The share token", "required": true, "schema": { - "type": "integer", - "format": "int64" + "type": "string", + "pattern": "^[a-zA-Z0-9]{16}$" } }, { @@ -14913,7 +14883,7 @@ ], "responses": { "200": { - "description": "View config returned", + "description": "Columns are returned", "content": { "application/json": { "schema": { @@ -14933,7 +14903,10 @@ "$ref": "#/components/schemas/OCSMeta" }, "data": { - "$ref": "#/components/schemas/NotifyConfig" + "type": "array", + "items": { + "$ref": "#/components/schemas/PublicColumn" + } } } } @@ -14942,8 +14915,8 @@ } } }, - "401": { - "description": "Current user is not logged in", + "403": { + "description": "No permissions", "content": { "application/json": { "schema": { @@ -14962,75 +14935,26 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } + } } } } } } } - } - } - } - }, - "/ocs/v2.php/apps/tables/api/2/config/{key}": { - "post": { - "operationId": "config-set-value", - "summary": "Sets a config value for a specific key", - "tags": [ - "config" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "value" - ], - "properties": { - "value": { - "type": "object", - "description": "Config value" - } - } - } - } - } - }, - "parameters": [ - { - "name": "key", - "in": "path", - "description": "Config key", - "required": true, - "schema": { - "type": "string" - } }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Config updated", + "400": { + "description": "Invalid request parameters", "content": { "application/json": { "schema": { @@ -15050,7 +14974,15 @@ "$ref": "#/components/schemas/OCSMeta" }, "data": { - "type": "boolean" + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + } + } } } } @@ -15059,8 +14991,8 @@ } } }, - "400": { - "description": "bad request", + "404": { + "description": "Not found", "content": { "application/json": { "schema": { @@ -15097,8 +15029,8 @@ } } }, - "403": { - "description": "No permissions", + "500": { + "description": "Internal error", "content": { "application/json": { "schema": { @@ -15134,6 +15066,71 @@ } } } + } + } + } + }, + "/ocs/v2.php/apps/tables/api/2/views/widget-types": { + "get": { + "operationId": "api_views-widget-types", + "summary": "[api v2] The widget types a grid view can hold", + "description": "Every type carries two schemas: the configuration of the widget on the page and its content.", + "tags": [ + "api_views" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Widget types returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GridWidgetType" + } + } + } + } + } + } + } + } }, "401": { "description": "Current user is not logged in", @@ -15166,16 +15163,15 @@ } } }, - "/ocs/v2.php/apps/tables/api/2/public/{token}/columns": { - "get": { - "operationId": "api_public_columns-index-by-public-link", - "summary": "[api v2] Get all columns for a table or a view shared by link", - "description": "Return an empty array if no columns were found", + "/ocs/v2.php/apps/tables/api/2/views": { + "post": { + "operationId": "api_views-create", + "summary": "[api v2] Create a grid view, a view without a table", + "description": "The view belongs to the user who creates it and can be placed in an application menu. It is named by its id, so it takes no technical name.", "tags": [ - "api_public_columns" + "api_views" ], "security": [ - {}, { "bearer_auth": [] }, @@ -15183,17 +15179,37 @@ "basic_auth": [] } ], - "parameters": [ - { - "name": "token", - "in": "path", - "description": "The share token", - "required": true, - "schema": { - "type": "string", - "pattern": "^[a-zA-Z0-9]{16}$" + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "title" + ], + "properties": { + "title": { + "type": "string", + "description": "Title of the view" + }, + "emoji": { + "type": "string", + "nullable": true, + "default": null, + "description": "Emoji shown with the title" + }, + "description": { + "type": "string", + "default": "", + "description": "Description shown on the page" + } + } + } } - }, + } + }, + "parameters": [ { "name": "OCS-APIRequest", "in": "header", @@ -15207,7 +15223,7 @@ ], "responses": { "200": { - "description": "Columns are returned", + "description": "View created", "content": { "application/json": { "schema": { @@ -15227,10 +15243,7 @@ "$ref": "#/components/schemas/OCSMeta" }, "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PublicColumn" - } + "$ref": "#/components/schemas/View" } } } @@ -15239,8 +15252,8 @@ } } }, - "403": { - "description": "No permissions", + "400": { + "description": "Invalid title or emoji", "content": { "application/json": { "schema": { @@ -15277,8 +15290,8 @@ } } }, - "400": { - "description": "Invalid request parameters", + "403": { + "description": "No permissions", "content": { "application/json": { "schema": { @@ -15315,8 +15328,8 @@ } } }, - "404": { - "description": "Not found", + "500": { + "description": "", "content": { "application/json": { "schema": { @@ -15353,8 +15366,8 @@ } } }, - "500": { - "description": "Internal error", + "401": { + "description": "Current user is not logged in", "content": { "application/json": { "schema": { @@ -15373,17 +15386,7 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": { - "type": "object", - "required": [ - "message" - ], - "properties": { - "message": { - "type": "string" - } - } - } + "data": {} } } } diff --git a/src/types/openapi/openapi.ts b/src/types/openapi/openapi.ts index 43dc0ab64e..e92d7d76bb 100644 --- a/src/types/openapi/openapi.ts +++ b/src/types/openapi/openapi.ts @@ -508,46 +508,6 @@ export type paths = { readonly patch?: never; readonly trace?: never; }; - readonly "/ocs/v2.php/apps/tables/api/2/views/widget-types": { - readonly parameters: { - readonly query?: never; - readonly header?: never; - readonly path?: never; - readonly cookie?: never; - }; - /** - * [api v2] The widget types a grid view can hold - * @description Every type carries two schemas: the configuration of the widget on the page and its content. - */ - readonly get: operations["api_views-widget-types"]; - readonly put?: never; - readonly post?: never; - readonly delete?: never; - readonly options?: never; - readonly head?: never; - readonly patch?: never; - readonly trace?: never; - }; - readonly "/ocs/v2.php/apps/tables/api/2/views": { - readonly parameters: { - readonly query?: never; - readonly header?: never; - readonly path?: never; - readonly cookie?: never; - }; - readonly get?: never; - readonly put?: never; - /** - * [api v2] Create a view without a table, such as a grid view - * @description The view belongs to the user who creates it and can be placed in an application menu. - */ - readonly post: operations["api_views-create"]; - readonly delete?: never; - readonly options?: never; - readonly head?: never; - readonly patch?: never; - readonly trace?: never; - }; readonly "/ocs/v2.php/apps/tables/api/2/tables": { readonly parameters: { readonly query?: never; @@ -1021,6 +981,46 @@ export type paths = { readonly patch?: never; readonly trace?: never; }; + readonly "/ocs/v2.php/apps/tables/api/2/views/widget-types": { + readonly parameters: { + readonly query?: never; + readonly header?: never; + readonly path?: never; + readonly cookie?: never; + }; + /** + * [api v2] The widget types a grid view can hold + * @description Every type carries two schemas: the configuration of the widget on the page and its content. + */ + readonly get: operations["api_views-widget-types"]; + readonly put?: never; + readonly post?: never; + readonly delete?: never; + readonly options?: never; + readonly head?: never; + readonly patch?: never; + readonly trace?: never; + }; + readonly "/ocs/v2.php/apps/tables/api/2/views": { + readonly parameters: { + readonly query?: never; + readonly header?: never; + readonly path?: never; + readonly cookie?: never; + }; + readonly get?: never; + readonly put?: never; + /** + * [api v2] Create a grid view, a view without a table + * @description The view belongs to the user who creates it and can be placed in an application menu. It is named by its id, so it takes no technical name. + */ + readonly post: operations["api_views-create"]; + readonly delete?: never; + readonly options?: never; + readonly head?: never; + readonly patch?: never; + readonly trace?: never; + }; readonly "/ocs/v2.php/apps/tables/api/2/public/{token}/rows": { readonly parameters: { readonly query?: never; @@ -1226,7 +1226,8 @@ export type components = { readonly broken?: boolean; }; readonly GridWidgetProperty: { - readonly type: string; + /** @enum {string} */ + readonly type: "string" | "text" | "color" | "boolean" | "integer" | "enum" | "target"; readonly title: string; readonly default: components["schemas"]["GridWidgetValue"]; readonly options?: readonly { @@ -1236,7 +1237,8 @@ export type components = { readonly required?: boolean; }; readonly GridWidgetType: { - readonly type: string; + /** @enum {string} */ + readonly type: "header" | "text" | "data"; readonly title: string; /** Format: int64 */ readonly defaultWidth: number; @@ -4621,164 +4623,6 @@ export interface operations { }; }; }; - readonly "api_views-widget-types": { - readonly parameters: { - readonly query?: never; - readonly header: { - /** @description Required to be true for the API request to pass */ - readonly "OCS-APIRequest": boolean; - }; - readonly path?: never; - readonly cookie?: never; - }; - readonly requestBody?: never; - readonly responses: { - /** @description Widget types returned */ - readonly 200: { - headers: { - readonly [name: string]: unknown; - }; - content: { - readonly "application/json": { - readonly ocs: { - readonly meta: components["schemas"]["OCSMeta"]; - readonly data: readonly components["schemas"]["GridWidgetType"][]; - }; - }; - }; - }; - /** @description Current user is not logged in */ - readonly 401: { - headers: { - readonly [name: string]: unknown; - }; - content: { - readonly "application/json": { - readonly ocs: { - readonly meta: components["schemas"]["OCSMeta"]; - readonly data: unknown; - }; - }; - }; - }; - }; - }; - readonly "api_views-create": { - readonly parameters: { - readonly query?: never; - readonly header: { - /** @description Required to be true for the API request to pass */ - readonly "OCS-APIRequest": boolean; - }; - readonly path?: never; - readonly cookie?: never; - }; - readonly requestBody: { - readonly content: { - readonly "application/json": { - /** @description Title of the view */ - readonly title: string; - /** - * @description Emoji shown with the title - * @default null - */ - readonly emoji?: string | null; - /** - * @description Type of the view, `grid` for a page of widgets - * @default grid - */ - readonly type?: string; - /** - * @description Technical name, lowercase letters, numbers and underscores - * @default null - */ - readonly technicalName?: string | null; - /** - * @description Description shown on the page - * @default - */ - readonly description?: string; - }; - }; - }; - readonly responses: { - /** @description View created */ - readonly 200: { - headers: { - readonly [name: string]: unknown; - }; - content: { - readonly "application/json": { - readonly ocs: { - readonly meta: components["schemas"]["OCSMeta"]; - readonly data: components["schemas"]["View"]; - }; - }; - }; - }; - /** @description Invalid type or technical name */ - readonly 400: { - headers: { - readonly [name: string]: unknown; - }; - content: { - readonly "application/json": { - readonly ocs: { - readonly meta: components["schemas"]["OCSMeta"]; - readonly data: { - readonly message: string; - }; - }; - }; - }; - }; - /** @description Current user is not logged in */ - readonly 401: { - headers: { - readonly [name: string]: unknown; - }; - content: { - readonly "application/json": { - readonly ocs: { - readonly meta: components["schemas"]["OCSMeta"]; - readonly data: unknown; - }; - }; - }; - }; - /** @description No permissions */ - readonly 403: { - headers: { - readonly [name: string]: unknown; - }; - content: { - readonly "application/json": { - readonly ocs: { - readonly meta: components["schemas"]["OCSMeta"]; - readonly data: { - readonly message: string; - }; - }; - }; - }; - }; - readonly 500: { - headers: { - readonly [name: string]: unknown; - }; - content: { - readonly "application/json": { - readonly ocs: { - readonly meta: components["schemas"]["OCSMeta"]; - readonly data: { - readonly message: string; - }; - }; - }; - }; - }; - }; - }; readonly "api_tables-index": { readonly parameters: { readonly query?: never; @@ -8372,6 +8216,154 @@ export interface operations { }; }; }; + readonly "api_views-widget-types": { + readonly parameters: { + readonly query?: never; + readonly header: { + /** @description Required to be true for the API request to pass */ + readonly "OCS-APIRequest": boolean; + }; + readonly path?: never; + readonly cookie?: never; + }; + readonly requestBody?: never; + readonly responses: { + /** @description Widget types returned */ + readonly 200: { + headers: { + readonly [name: string]: unknown; + }; + content: { + readonly "application/json": { + readonly ocs: { + readonly meta: components["schemas"]["OCSMeta"]; + readonly data: readonly components["schemas"]["GridWidgetType"][]; + }; + }; + }; + }; + /** @description Current user is not logged in */ + readonly 401: { + headers: { + readonly [name: string]: unknown; + }; + content: { + readonly "application/json": { + readonly ocs: { + readonly meta: components["schemas"]["OCSMeta"]; + readonly data: unknown; + }; + }; + }; + }; + }; + }; + readonly "api_views-create": { + readonly parameters: { + readonly query?: never; + readonly header: { + /** @description Required to be true for the API request to pass */ + readonly "OCS-APIRequest": boolean; + }; + readonly path?: never; + readonly cookie?: never; + }; + readonly requestBody: { + readonly content: { + readonly "application/json": { + /** @description Title of the view */ + readonly title: string; + /** + * @description Emoji shown with the title + * @default null + */ + readonly emoji?: string | null; + /** + * @description Description shown on the page + * @default + */ + readonly description?: string; + }; + }; + }; + readonly responses: { + /** @description View created */ + readonly 200: { + headers: { + readonly [name: string]: unknown; + }; + content: { + readonly "application/json": { + readonly ocs: { + readonly meta: components["schemas"]["OCSMeta"]; + readonly data: components["schemas"]["View"]; + }; + }; + }; + }; + /** @description Invalid title or emoji */ + readonly 400: { + headers: { + readonly [name: string]: unknown; + }; + content: { + readonly "application/json": { + readonly ocs: { + readonly meta: components["schemas"]["OCSMeta"]; + readonly data: { + readonly message: string; + }; + }; + }; + }; + }; + /** @description Current user is not logged in */ + readonly 401: { + headers: { + readonly [name: string]: unknown; + }; + content: { + readonly "application/json": { + readonly ocs: { + readonly meta: components["schemas"]["OCSMeta"]; + readonly data: unknown; + }; + }; + }; + }; + /** @description No permissions */ + readonly 403: { + headers: { + readonly [name: string]: unknown; + }; + content: { + readonly "application/json": { + readonly ocs: { + readonly meta: components["schemas"]["OCSMeta"]; + readonly data: { + readonly message: string; + }; + }; + }; + }; + }; + readonly 500: { + headers: { + readonly [name: string]: unknown; + }; + content: { + readonly "application/json": { + readonly ocs: { + readonly meta: components["schemas"]["OCSMeta"]; + readonly data: { + readonly message: string; + }; + }; + }; + }; + }; + }; + }; readonly "public_rowocs-get-rows": { readonly parameters: { readonly query?: { diff --git a/tests/unit/Controller/ApiViewsControllerTest.php b/tests/unit/Controller/ApiViewsControllerTest.php index 1348ca74ab..6710c5a6ac 100644 --- a/tests/unit/Controller/ApiViewsControllerTest.php +++ b/tests/unit/Controller/ApiViewsControllerTest.php @@ -56,19 +56,38 @@ public function testCreateHandsTheStandaloneViewToTheService(): void { $view->setCreatedBy('alice'); $this->viewService->expects($this->once()) ->method('create') - ->with('Home', '🧩', null, 'alice', 'home', null, View::TYPE_GRID, 'Start here') + ->with('Home', '🧩', null, 'alice', null, null, View::TYPE_GRID, 'Start here') ->willReturn($view); - $response = $this->controller->create('Home', '🧩', 'grid', 'home', 'Start here'); + $response = $this->controller->create(' Home ', '🧩', 'Start here'); $this->assertSame(Http::STATUS_OK, $response->getStatus()); $this->assertSame(6, $response->getData()['id']); } + public static function invalidInput(): array { + return [ + 'empty title' => [' ', null], + 'title over 200 bytes' => [str_repeat('a', 201), null], + 'emoji that is not one emoji' => ['Home', 'not an emoji'], + ]; + } + + /** + * @dataProvider invalidInput + */ + public function testCreateRefusesInvalidInputWith400(string $title, ?string $emoji): void { + $this->viewService->expects($this->never())->method('create'); + + $response = $this->controller->create($title, $emoji); + + $this->assertSame(Http::STATUS_BAD_REQUEST, $response->getStatus()); + } + public function testCreateTurnsABadRequestInto400(): void { - $this->viewService->method('create')->willThrowException(new BadRequestError('Technical name must start with a lowercase letter')); + $this->viewService->method('create')->willThrowException(new BadRequestError('rejected by the service')); - $response = $this->controller->create('Home', null, 'grid', 'Not Valid'); + $response = $this->controller->create('Home'); $this->assertSame(Http::STATUS_BAD_REQUEST, $response->getStatus()); }