Skip to content

feat(pages): page and widget type API (#3100, step 2) - #47

Open
rubenvdlinde wants to merge 1 commit into
stack/r1-page-modelfrom
stack/r2-page-api
Open

rubenvdlinde wants to merge 1 commit into
stack/r1-page-modelfrom
stack/r2-page-api

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Collaborator

Step 2 of the page rework on nextcloud#3100 (follows the review on nextcloud#3075). Stacked on #46.

What

  • GET /api/2/contexts/{contextId}/pages/{pageId}: a page with its widgets (settings map, source: {nodeRelId} or null). Read access on the application.
  • POST /api/2/contexts/{contextId}/pages: add a grid page with title, emoji, description.
  • PATCH /api/2/contexts/{contextId}/pages/{pageId}: change the page fields (left out keeps, empty emoji/description removes) and/or send widgets. The widgets of the page are synced by id in one transaction: listed ids are updated, widgets without an id are inserted, widgets of the page that are not listed are deleted. An id of another page is a 400.
  • DELETE /api/2/contexts/{contextId}/pages/{pageId}: grid pages only, 400 for the start page; deletes widgets, settings and sources.
  • GET /api/2/widget-types: header, text ("Description") and data, each with its settings schema and hasSource.
  • Writes need manage permission on the application (RequirePermission MANAGE in the middleware, checked again in PageService). Non-members get 404.
  • Every setting is validated against its type's schema (GridWidgetTypes, carried over from the earlier stack and reduced to one settings schema per type; unknown settings are dropped, defaults filled in). A source on a type without one is a 400.
  • A data widget's source is {nodeRelId} of this application (400 otherwise) or {nodeType, nodeId}; the latter is added to the application (and its start page, like ContextService::update) after the same canManageNodeById check, 403 if not allowed.
  • The context response already lists its pages; it now also carries their title, emoji and description (step 1).
  • Imported widgets (importContext) are validated against the types too; invalid ones are skipped.
  • OpenAPI and TypeScript types regenerated.

nextcloud#3100 points covered

API (all five endpoints), "Saving a page syncs its widgets by id in one transaction", "Reading needs read access to the application. Changes need manage access", "The server checks every setting against the type's schema on save".

Tests (Nextcloud 34, PostgreSQL 16, in the container)

  • tests/unit/Service/PageServiceTest.php: OK (26 tests, 71 assertions) (sync, node add, 403 on unmanaged node and non-manager, 400 cases, start page)
  • tests/unit/Controller/ContextPageControllerTest.php: OK (13 tests, 23 assertions) (200/400/403/404 mapping)
  • tests/unit/Service/GridWidgetTypesTest.php: OK (9 tests, 29 assertions)
  • tests/unit/Service/WidgetServiceTest.php (real DB, incl. sync): OK (7 tests, 22 assertions)
  • tests/unit/Service/ContextServiceTest.php: OK (6 tests, 20 assertions); ContextPagesRoundTripTest.php (real DB): OK (2 tests, 10 assertions)
  • whole unit suite: OK (420 tests, 857 assertions)
  • Live with curl: owner POST/PATCH/GET 200, start page DELETE 400, foreign nodeRelId 400; read-only sharee GET 200 and POST/PATCH/DELETE 403; non-member 404 on all four.
  • composer cs:check: no files; psalm: no errors. Inherited: the OpenAPI generator's existing warnings on other controllers.

Note: an empty settings map serializes as [] (PHP array), as elsewhere in the API.

Prepared in the Conduction fork for porting upstream by @remko48. Prepared with Claude Code.

GET, POST, PATCH and DELETE /api/2/contexts/{contextId}/pages[/{pageId}]
and GET /api/2/widget-types per nextcloud#3100. PATCH changes the
title, emoji and description and syncs the widgets of a grid page by id in
one transaction. Settings are validated against the schema of their widget
type; a data widget's source must be a node of the application, or a table
or view the user manages, which is added to the application first.
Imported widgets are validated the same way.

Assisted-by: ClaudeCode:claude-opus-5-5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant