Document every exported symbol and how callers use the library.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-29 19:25:44 +02:00
co-authored by Cursor
parent d7768d44d6
commit afbd76445d
11 changed files with 1226 additions and 107 deletions
+38 -82
View File
@@ -4,100 +4,56 @@ Shared Go library for Nextcloud ExApp Services: AppAPI authentication, OCS JSON
Import: `gitea.neitzel.de/konrad/go-nc-exapp` (package `gonexapp`).
## Scope
```bash
go get gitea.neitzel.de/konrad/go-nc-exapp
```
**Included**
- [Guide](docs/guide.md) — how to call each capability
- [API](docs/api.md) — every exported symbol
- [Domain language](CONTEXT.md)
- **Credentials** — Nextcloud base URL, AppAPI secret, and requesting user identity
- **AuthHeaders** — outbound AppAPI authorization for OCS and other Nextcloud calls
- **WithUser** — credentials scoped to a specific requesting user
- **UserFromRequest** — extract the requesting user from inbound AppAPI-proxied requests
- **OCSClient** — authenticated OCS calls that always append `format=json`
- **AppAPIPreferences** — parameterized get/set of a string ExApp preference (caller supplies app id and key)
- **AppAPINotifications** — `Send` (Recipient = Credentials user) and `SendTo` (explicit Recipient); Subject required; Message, Link, and rich-object params optional. AppAPI’s notification OCS is limited (no actions, no custom icon)
- **Groups** — Users and Groups reads: `UserGroups`, `GroupMembers`, `ListGroups` (no search/paging). Directory calls (`GroupMembers` / `ListGroups`) run as the Credentials user and need an admin or subadmin
- **Access Gate** — optional Required Groups enforcement (`Wrap` + `Check`), English denied HTML for browsers (200 + `frame-ancestors 'self'`), positive membership cache; default skip for lifecycle paths and **`/js/`** top-menu scripts; env helpers for `REQUIRED_GROUPS` / `REQUIRED_GROUPS_CACHE_SECONDS`
- **Top Menu visibility** — `TopMenuAdminRequired` helper for deploy env `TOP_MENU_ADMIN_REQUIRED` (`0` / `1` for AppAPI top-menu OCS)
- **App navigation** — optional Files-style shell (`AppNavigation.Handler`). The ExApp supplies the tree, the page for each item, and an optional header. The selected item is the `item` query parameter (override with `SelectKey`). Other query parameters, including a Visit folder, are left in place. By default the shell loads the Nextcloud theme stylesheets, paints `--image-background`, and copies the surrounding page’s `data-theme-*` markers; set `DisableTheme` to skip the stylesheets. An item may set `Icon` to a same-origin image URL. `NextcloudIcons` names the core SVGs Nextcloud already serves (`NextcloudIcons.Folder`, `NextcloudIcons.Password`, and the rest). At 1024px and below, the tree is hidden until the user opens it with the navigation button; choosing an item, pressing Escape, or clicking outside closes it. The shell includes the Dialog. Not mounting the handler keeps the ExApp’s own page. Lifecycle routes, HaRP startup, and Top Menu registration stay in the ExApp.
- **Dialog** — `DialogHTML()` is the modal for a Message, a Confirm, or a Prompt. Insert it on a page the ExApp renders itself; App navigation already includes it. The page calls `exappDialog.message`, `exappDialog.confirm`, or `exappDialog.prompt` and waits for the choice. Fixed buttons are the English words OK and Cancel. The agreeing button’s word may be replaced. The choice stays in the page.
## Included
**Excluded**
- [Credentials](docs/guide.md#credentials) — Nextcloud base URL, AppAPI secret, and requesting user
- [AuthHeaders](docs/guide.md#authheaders) — outbound AppAPI authorization
- [WithUser](docs/guide.md#withuser) — credentials scoped to one user
- [UserFromRequest](docs/guide.md#userfromrequest) — requesting user on an inbound request
- [OCSClient](docs/guide.md#ocsclient) — authenticated OCS calls with `format=json`
- [AppAPIPreferences](docs/guide.md#appapipreferences) — one string preference for the requesting user
- [AppAPINotifications](docs/guide.md#appapinotifications) — one bell notification
- [Groups](docs/guide.md#groups) — user groups, group members, and the group list
- [Access Gate](docs/guide.md#access-gate) — optional Required Groups check
- [Top Menu visibility](docs/guide.md#top-menu-visibility) — `TOP_MENU_ADMIN_REQUIRED`
- [App navigation](docs/guide.md#app-navigation) — optional Files-style shell
- [Dialog](docs/guide.md#dialog) — message, confirm, and prompt
- ExApp lifecycle HTTP routes (`/heartbeat`, `/enabled`, …) — the Gate *skips* these by default but does not implement them
- HaRP listen / `serve()` and unix-socket bootstrap
## Excluded
- ExApp lifecycle HTTP routes (`/heartbeat`, `/enabled`, and `/init`). The Access Gate skips these by default and does not implement them
- HaRP listen, `serve()`, and unix-socket bootstrap
- Top-menu, script, and iframe UI registration
- WebDAV and file storage (see **go-nc-files**)
- **Visit** folder resolution (see **go-nc-files**)
- Fan-out Notifications (`SendToGroup` / `SendToAdmins`)
- A Library default privileged / admin user for directory OCS (callers who need that use `WithUser` themselves)
- CheckDNS (or any ExApp) wiring for Notifications or Groups — products opt in separately
## Usage
```go
cred := gonexapp.Credentials{
BaseURL: "https://nextcloud.example",
AppID: "myexapp",
AppVersion: "0.1.0",
AAVersion: "1.0.0",
AppSecret: os.Getenv("APP_SECRET"),
UserID: "alice",
}
prefs := gonexapp.NewAppAPIPreferences(cred, "myexapp", "savedDefault")
value, err := prefs.Get()
err = gonexapp.NewAppAPINotifications(cred).Send(gonexapp.Notification{Subject: "Job finished"})
members, err := gonexapp.NewGroups(cred).GroupMembers("CheckDNS")
groupsEnv, groupsSet := os.LookupEnv("REQUIRED_GROUPS")
groups := gonexapp.ResolveRequiredGroups(groupsEnv, groupsSet, nil)
ttl := gonexapp.ParseCacheSeconds(os.Getenv("REQUIRED_GROUPS_CACHE_SECONDS"), gonexapp.DefaultCacheSeconds)
handler := gonexapp.AccessGate{Cred: cred, Groups: groups, CacheTTL: ttl}.Wrap(inner)
```
Each ExApp chooses its own preference keys; this library does not hardcode product-specific names.
Declare `REQUIRED_GROUPS` and `REQUIRED_GROUPS_CACHE_SECONDS` in the ExApp `info.xml` so Deploy options can set them.
The Gate skips `/heartbeat`, `/enabled`, `/init`, and any path under **`/js/`** (AppAPI top-menu bootstrap). Serve the registered top-menu script under `/js/…` so a non-member still loads it and can show Denied UI in the Nextcloud shell. API routes stay gated.
Denied HTML is **200** with `Content-Security-Policy: … frame-ancestors 'self'`. Without that header AppAPI’s proxy defaults to `frame-ancestors 'none'` and a denied iframe stays blank. Non-HTML denials remain **403**.
### Top Menu visibility (`TOP_MENU_ADMIN_REQUIRED`)
Declare in `info.xml` under `<environment-variables>`. At enable time the ExApp reads the env and passes `"0"` or `"1"` to AppAPI’s top-menu OCS `adminRequired`. Only `0` and `1` are valid; anything else falls back to `DefaultTopMenuAdminRequired` (`true` → admins only).
```go
adminRequired := gonexapp.TopMenuAdminRequired(
os.Getenv(gonexapp.EnvTopMenuAdminRequired),
gonexapp.DefaultTopMenuAdminRequired,
)
// use adminRequired in POST …/ui/top-menu when registering the menu entry
```
**Applying a change:** AppAPI registers the top menu when the ExApp receives `PUT /enabled?enabled=1`. Changing the deploy env alone does not update the menu entry.
1. Set the new value in Deploy options (UI) or `occ app_api:app:register … --env TOP_MENU_ADMIN_REQUIRED=…` / update deploy config.
2. Recreate or restart the ExApp container so the new env is present.
3. Re-run lifecycle: disable then enable the ExApp (UI or `occ app_api:app:disable` / `app_api:app:enable`), or `occ app_api:app:update … -e` after an image/info update.
Route `access_level` in `info.xml` is separate and only changes when AppAPI re-reads `info.xml` on register/update — not via this env.
Runnable package examples: `go test -run Example`.
## Domain language
See [CONTEXT.md](./CONTEXT.md) for AppAPI credentials, Requesting user, Recipient, ExApp preference, Notification, OCS, Required Groups, Users and Groups, Access Gate, App navigation, and Top Menu visibility terminology.
- Visit folder resolution (see **go-nc-files**)
- Fan-out notifications (`SendToGroup`, `SendToAdmins`)
- A library default admin user for directory OCS (callers pass that user with `WithUser`)
## Testing
Unit tests use `httptest` fake OCS servers. No live Nextcloud is required for Library CI.
Unit tests use `httptest` fake OCS servers. No live Nextcloud is required.
`go test ./...` fails when [`docs/api.md`](docs/api.md) does not match the exported API. Regenerate it with:
```bash
UPDATE_API_DOCS=1 go test -run TestAPIDoc -count=1
```
Runnable package examples: `go test -run Example`.
## Related
- **go-nc-files** — WebDAV, Working Folder, Saved Default, Visit resolution
- Workspace ADR 0013 — extraction from CheckDNS
- Workspace ADR `docs/adr/go-nc-exapp/0001-required-groups-access-gate.md` — Access Gate decisions
- Workspace ADR `docs/adr/go-nc-exapp/0002-users-and-groups-as-requesting-user.md` — directory OCS as Requesting user
- Workspace ADR `docs/adr/go-nc-exapp/0001-required-groups-access-gate.md` — Access Gate
- Workspace ADR `docs/adr/go-nc-exapp/0002-users-and-groups-as-requesting-user.md` — directory OCS as the requesting user
- Workspace ADR `docs/adr/go-nc-exapp/0003-app-navigation-shell.md` — App navigation shell
- Workspace ADR `docs/adr/go-nc-exapp/0004-dialog-in-exapp-page.md` — Dialog