Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
3cf35bc
feat: :package: add runtime deps and bump NC version requirement
moodyjmz May 22, 2026
0375e6f
feat: :sparkles: add TypeScript services for templates, files and config
moodyjmz May 22, 2026
74c1304
feat: :sparkles: add FileCard and TemplateSection Vue 3 components
moodyjmz May 22, 2026
c5b25a4
feat: :sparkles: add OfficeOverview main view and wire into App
moodyjmz May 22, 2026
49c7f1f
fix: :rotating_light: resolve all lint errors and add stylelint config
moodyjmz May 22, 2026
35b7d43
refactor: :recycle: apply post-review improvements to overview compon…
moodyjmz May 22, 2026
fbb5fa2
chore: bump max-version to 35 for NC35 compatibility
moodyjmz May 22, 2026
feb2cf7
feat: add database migration creating the office_wopi token table
moodyjmz May 22, 2026
27744db
feat: add ExpiredTokenException for WOPI token validation
moodyjmz May 22, 2026
a1d79ac
feat: add UnknownTokenException for WOPI token lookup failures
moodyjmz May 22, 2026
c6ed381
feat: add Wopi entity mapping the office_wopi table
moodyjmz May 22, 2026
f07d041
feat: add WopiMapper for token persistence and lookup
moodyjmz May 22, 2026
9fffd03
feat: add DiscoveryService to fetch and cache WOPI discovery XML
moodyjmz May 22, 2026
832bd30
feat: add TokenManager to generate WOPI access tokens for files
moodyjmz May 22, 2026
b40a9aa
feat: add WopiController implementing CheckFileInfo, GetFile and PutFile
moodyjmz May 22, 2026
6324175
✨ feat: register TokenManager in DI container with session user injec…
moodyjmz May 22, 2026
f615de6
✨ feat: add Admin settings class registering the office settings section
moodyjmz May 22, 2026
46bc891
✨ feat: register Admin settings in Application bootstrap
moodyjmz May 22, 2026
73b9062
✨ feat: add SettingsController with admin get/set endpoints
moodyjmz May 22, 2026
db593eb
✨ feat: add admin settings PHP template
moodyjmz May 22, 2026
4cbb069
✨ feat: add AdminSettings Vue component
moodyjmz May 22, 2026
91138ea
✨ feat: add settings-admin entry point mounting AdminSettings
moodyjmz May 22, 2026
1d89ba7
✨ feat: add EditorController generating WOPI token and editor URL
moodyjmz May 22, 2026
5c2eaff
✨ feat: add editor PHP template passing editor URL to Vue
moodyjmz May 22, 2026
5cdca91
✨ feat: add Editor Vue component rendering the WOPI iframe with origi…
moodyjmz May 22, 2026
65fcc1f
✨ feat: add editor entry point mounting Editor component
moodyjmz May 22, 2026
b970dc9
🔧 chore: add editor and settings-admin entry points to vite config
moodyjmz May 22, 2026
2600f1d
🐛 fix: correct query-string separator in buildEditorUrl
moodyjmz May 22, 2026
8907380
🔒 security: prevent XPath injection via file extension in getUrlSrc
moodyjmz May 22, 2026
0dbad67
🔒 fix(security): prevent XPath injection via file extension in getUrlSrc
moodyjmz May 22, 2026
cec316e
🔒 security: validate wopi_url scheme in setAdmin to limit SSRF surface
moodyjmz May 22, 2026
959c413
🔒 fix(security): validate wopi_url scheme in setAdmin to limit SSRF s…
moodyjmz May 22, 2026
c9a89b7
🔒 security: fix range-request handling and close file handles in putFile
moodyjmz May 22, 2026
e339f7c
🔒 fix(security): fix range-request handling and close file handles in…
moodyjmz May 22, 2026
c328e1f
✨ feat: add hourly CleanupJob to purge expired WOPI tokens
moodyjmz May 22, 2026
07bc401
✨ feat: add hourly CleanupJob to purge expired WOPI tokens
moodyjmz May 22, 2026
8e268fd
✨ feat: add office_wopi_locks migration for WOPI lock storage
moodyjmz May 23, 2026
ab3924b
✨ feat: add office_wopi_locks migration for WOPI lock storage
moodyjmz May 23, 2026
bf8dec7
✨ feat: add WopiLock entity and WopiLockMapper
moodyjmz May 23, 2026
734ee24
✨ feat: add WopiLock entity and WopiLockMapper
moodyjmz May 23, 2026
d3b9c8e
✨ feat: add WOPI lock operations (Lock, Unlock, RefreshLock, GetLock)
moodyjmz May 23, 2026
7c4cef3
✨ feat: add WOPI lock operations (Lock, Unlock, RefreshLock, GetLock)
moodyjmz May 23, 2026
bb2d73b
🔒 security: enforce WOPI lock and version checks on PutFile
moodyjmz May 23, 2026
147e7c8
🔒 fix(security): enforce WOPI lock and version checks on PutFile
moodyjmz May 23, 2026
b73bab7
♻️ refactor: extend CleanupJob to also purge expired WOPI locks
moodyjmz May 23, 2026
386255c
♻️ refactor: extend CleanupJob to also purge expired WOPI locks
moodyjmz May 23, 2026
a0dc563
🔧 chore: move background-jobs and settings registration to info.xml
moodyjmz May 23, 2026
d0b0574
🔧 chore: move background-jobs and settings registration to info.xml
moodyjmz May 23, 2026
76518a5
🐛 fix: guard fclose() on php://input after putContent()
moodyjmz May 23, 2026
602a554
🐛 fix: guard fclose() on php://input after putContent()
moodyjmz May 23, 2026
5a708d2
🐛 fix: set Content-Type: application/octet-stream on WOPI GetFile res…
moodyjmz May 23, 2026
92caf9e
🐛 fix: set Content-Type: application/octet-stream on WOPI GetFile res…
moodyjmz May 23, 2026
24bb79a
🔒 security: reject WOPI lock operations on read-only tokens
moodyjmz May 23, 2026
05c49fb
🔒 fix(security): reject WOPI lock operations on read-only tokens
moodyjmz May 23, 2026
60b586f
✨ feat: add hide_download support to WOPI token row
moodyjmz May 23, 2026
f05e079
✨ feat: add hide_download support to WOPI token row
moodyjmz May 23, 2026
f2c4016
✨ feat: add public ShareController for WOPI share-link access
moodyjmz May 23, 2026
a926829
✨ feat: add public ShareController for WOPI share-link access
moodyjmz May 23, 2026
b20d144
✨ feat: propagate hideDownload flags in CheckFileInfo response
moodyjmz May 23, 2026
15508b7
✨ feat: propagate hideDownload flags in CheckFileInfo response
moodyjmz May 23, 2026
6c576ba
🔒 security: sanitize guestName and document P3 known gaps
moodyjmz May 23, 2026
c4315cf
✨ feat: add DiscoveryService::getSupportedMimeTypes()
moodyjmz May 23, 2026
b60a666
✨ feat: issue user token for authenticated visitors on share links
moodyjmz May 23, 2026
fd549d6
✨ feat: inject file-actions script and MIME types on Files app pages
moodyjmz May 23, 2026
1ef75ac
✨ feat: register Files app file action to open documents in Office
moodyjmz May 23, 2026
fde4d25
✨ feat: merge overview and WOPI branches
moodyjmz May 23, 2026
279e593
🐛 fix: navigate directly to in-app editor from overview
moodyjmz May 23, 2026
0e48dbb
🐛 fix: use history.back() on UI_Close instead of window.close()
moodyjmz May 23, 2026
9a8e3a8
🐛 fix: use document icon instead of cloud for app icon
moodyjmz May 23, 2026
5feb7b4
✨ feat: decouple openFile from hardcoded WOPI editor URL
moodyjmz May 24, 2026
20342e6
🔧 chore: wire PageController to inject real editor URL for WOPI branch
moodyjmz May 24, 2026
b1348bc
📝 docs: add combined branch README covering full overview + WOPI setup
moodyjmz May 24, 2026
b229432
🔒 fix(security): sanitize guestName and document P3 known gaps
moodyjmz May 23, 2026
85de8bf
✨ feat: add DiscoveryService::getSupportedMimeTypes()
moodyjmz May 23, 2026
46e73a3
✨ feat: issue user token for authenticated visitors on share links
moodyjmz May 23, 2026
a344c9c
✨ feat: inject file-actions script and MIME types on Files app pages
moodyjmz May 23, 2026
d157337
✨ feat: register Files app file action to open documents in Office
moodyjmz May 23, 2026
dc53070
🐛 fix: use history.back() on UI_Close instead of window.close()
moodyjmz May 23, 2026
086e54f
📝 docs: replace scaffold README with WOPI backend developer guide
moodyjmz May 24, 2026
3696fac
🐛 fix: resolve genuine Psalm errors across WOPI backend
moodyjmz May 24, 2026
6a99943
🔧 chore: upgrade Psalm to v6 and add baseline for false positives
moodyjmz May 24, 2026
2ee173b
📦 chore: add package-lock.json
moodyjmz May 24, 2026
933de98
🎨 style: apply PHP CS Fixer (import ordering, docblock alignment)
moodyjmz May 24, 2026
7a4d324
🐛 fix: use document icon instead of cloud for app icon
moodyjmz May 24, 2026
71e1759
♻️ revert: remove icon fix (out of scope for WOPI backend branch)
moodyjmz May 24, 2026
4948f0c
✨ feat(wopi): implement RenameFile and fix CheckFileInfo capability f…
moodyjmz May 24, 2026
896d5be
📝 docs: update README — WOPI spec compliance table, generic setup
moodyjmz May 24, 2026
e4d4ebc
🔀 merge: integrate feat/wopi-phase-5 into overview-and-wopi
moodyjmz May 25, 2026
0da0e0d
🔒 fix(wopi): close C-1 path traversal, H-3 unlocked writes, H-2 lock …
moodyjmz May 25, 2026
b3346aa
🔧 fix(psalm): fix Application.php TokenManager arity bug and sync bas…
moodyjmz May 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,16 @@ module.exports = {
'jsdoc/require-jsdoc': 'off',
'vue/first-attribute-linebreak': 'off',
},
overrides: [
{
// @nextcloud/eslint-config uses @babel/eslint-parser for .vue files,
// which cannot parse TypeScript in <script setup lang="ts">.
// Override to use @typescript-eslint/parser as the inner parser.
files: ['**/*.vue'],
parser: 'vue-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser',
},
},
],
}
5 changes: 5 additions & 0 deletions .stylelintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
extends: [
'@nextcloud/stylelint-config',
],
}
71 changes: 71 additions & 0 deletions PHASE3_DECISIONS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Phase 3 — Design Decisions

**Date:** 2026-05-23
**Scope:** WOPI share-link / guest token support

---

## D1 — User lock demotes guest write access

**Decision:** Yes — if a `TYPE_USER` lock exists on a file whose owner ≠ `editorUid`, the guest's `UserCanWrite` is forced to `false` in CheckFileInfo.

**Rationale:** `editorUid` is `null` for all guests, so they always fail the owner check. This is the safest default and matches both richdocuments and eurooffice-nextcloud behaviour. Two parties (a user and a guest) writing to the same file simultaneously would risk data loss.

---

## D2 — Share-level flags stored on the token row

**Decision:** `hide_download` is stamped onto the `oc_office_wopi` row at token-generation time (migration `1002`). It is never re-read from the share on subsequent requests.

**Rationale:** The `oc_office_wopi` token row is the right boundary — it is already the authority for `canwrite`, `owner_uid`, etc. Storing flags here avoids a per-request `IShareManager` lookup on every CheckFileInfo heartbeat. This is the richdocuments pattern.

**Trade-off accepted:** Share revocation mid-session is not enforced. A deleted/revoked share leaves its issued tokens valid until they expire (10 h TTL). Acceptable for Phase 3; can be revisited if needed.

---

## D3 — Share revocation window accepted

**Decision:** No per-request share re-validation. See D2.

**Rationale:** Adds latency and couples the WOPI token lifetime to the share object. The 10 h token TTL bounds the exposure window. eurooffice-nextcloud (which re-validates per request) uses a different architecture with no WOPI token table — not applicable here.

---

## D4 — Guests may issue WOPI locks (same as authenticated users)

**Decision:** No special guest check in `executeOperation`. Guests with `canWrite = true` may `LOCK`, `UNLOCK`, and `REFRESH_LOCK`.

**Rationale:** richdocuments allows guests to lock. Blocking guests from locking would cause EO to skip `PutFile` (EO locks before writing), breaking guest editing entirely. The 30-minute lock TTL and `CleanupJob` are the mitigations against lock-and-abandon abuse.

---

## D5 — Share scope for Phase 3

**Decision:** All three types handled in one shot:
- **File shares** — share node is a `File`; returned directly.
- **Folder shares** — share node is a `Folder`; resolved by `fileId` or relative `path` parameter. NC's `Folder::get()` / `getFirstNodeById()` throw `NotFoundException` on traversal — no extra guard needed.
- **Password-protected shares** — checked via `ISession::get('public_link_authenticated')`. Supports both legacy string format and current array-of-IDs format (matches richdocuments).

**Deferred:** Federated/remote shares. Internal user-through-share tokens (authenticated user viewing a share link gets a guest token for Phase 3; full user-token path deferred to Phase 4).

---

## Architecture notes

- `UserCanNotWriteRelative` = `$wopi->isGuest() || $wopi->getHideDownload()` — guests can never write relative (Save As to owner storage), and hideDownload also blocks it.
- `HideExportOption`, `DisablePrint`, `DisableExport` are all derived from `hideDownload` at CheckFileInfo time.
- `generateFileToken` (authenticated users) does not accept a `hideDownload` param — always `false`. Share-level restrictions only apply to the guest path.
- `files_sharing` app is not declared as a formal dependency (matches richdocuments). `IShareManager::getShareByToken()` returns a clean 404 if the share is not found.

---

## Known gaps (deferred)

**KG1 — Password-protected share UI** (P4)
`ShareController` returns `401 Password required` when the session lacks `public_link_authenticated`. There is currently no redirect to `/s/{shareToken}` or embedded password form. Users must visit `/s/{shareToken}` first, then navigate to the editor URL. A P4 redirect or embedded challenge is needed.

**KG2 — Authenticated-user-through-share** (P4)
An authenticated NC user visiting a share link currently gets a guest token. richdocuments issues a user token (with the user's own uid) for authenticated visitors. Deferred to P4 — requires a `$userSession->isLoggedIn()` branch in `ShareController`.

**KG3 — Federated/remote share support** (deferred, not P4)
`ShareController` accepts any share type returned by `IShareManager::getShareByToken()`. Federated shares (TYPE_REMOTE, TYPE_REMOTE_GROUP) are not tested. `getHideDownload()` is confirmed in `OCP\Share\IShare` and returns `false` for non-link shares by default, so no crash risk. Full federated support is out of scope.
192 changes: 177 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,187 @@
# Office

A template to get started with Nextcloud app development.
A Nextcloud app that integrates Euro-Office as a WOPI host, providing a document hub
and full-page editor. Nextcloud acts as the WOPI host (file storage, token authority,
lock manager); Euro-Office acts as the WOPI client (rendering, editing).

## Usage
> **Note:** This is a combined test branch. Development happens on the overview and
> WOPI branches independently; changes here should be ported back to those branches.

- To get started easily use the [Appstore App generator](https://apps.nextcloud.com/developer/apps/generate) to
dynamically generate an App based on this repository with all the constants prefilled.
- Alternatively you can use the "Use this template" button on the top of this page to create a new repository based on
this repository. Afterwards adjust all the necessary constants like App ID, namespace, descriptions etc.
---

Once your app is ready follow the [instructions](https://nextcloudappstore.readthedocs.io/en/latest/developer.html) to
upload it to the Appstore.
## Features

## Resources
- **Overview page** at `/apps/office` — browse, filter, search, and create Documents,
Spreadsheets, Presentations, and Diagrams from one place
- **Filters** — All / Mine / Shared with me
- **Search** — within the active category, with an "Open in Files" escape hatch
- **View toggle** — Grid (thumbnail previews) or List, persisted per user
- **Template creator** — create new files from editor-provided templates
- **Full-page editor** at `/apps/office/open?fileId=N`
- **WOPI host implementation** — see [WOPI spec compliance](#wopi-spec-compliance) below
- **Files app integration** — DEFAULT file action for all MIME types advertised by the editor
- **Public share support** — guest tokens for link-share access
- **Range reads** — partial file delivery via HTTP Range for large documents
- **Clean navigation** — editor close (`history.back()`) returns the user to the overview

### Documentation for developers:
---

- General documentation and tutorials: https://nextcloud.com/developer
- Technical documentation: https://docs.nextcloud.com/server/latest/developer_manual
## Local development

### Help for developers:
### Requirements

- Official community chat: https://cloud.nextcloud.com/call/xs25tz5y
- Official community forum: https://help.nextcloud.com/c/dev/11
- [nextcloud-docker-dev](https://github.com/juliushaertl/nextcloud-docker-dev)
- NC ≥ 33
- Node ≥ 24 / npm ≥ 11
- Euro-Office server reachable from the NC container

### 1. Mount the app into the container

Add to `nextcloud-docker-dev/docker-compose.override.yml`:

```yaml
services:
nextcloud:
volumes:
- /path/to/office:/var/www/html/apps-extra/office
```

Restart the container after saving.

### 2. Enable the app

```bash
docker compose exec --user www-data nextcloud php occ app:enable office
```

If the Euro-Office connector app is also installed, disable it to prevent it from
competing for the DEFAULT file action:

```bash
docker compose exec --user www-data nextcloud php occ app:disable eurooffice
```

### 3. Build the frontend

```bash
npm ci
npm run build # one-off build
npm run watch # rebuild on file changes
```

---

## How it works

### User flow

1. User navigates to `/apps/office`
2. Overview lists all office files, grouped by type
3. User clicks a file → navigated to `/apps/office/open?fileId=N`
4. `EditorController` mints a WOPI token and builds the editor URL
5. Euro-Office loads the file via the WOPI protocol
6. User closes the editor → `history.back()` returns to the overview

### WOPI flow

```
Browser NC (WOPI host) Euro-Office (WOPI client)
| | |
| GET /apps/office/open | |
|------------------------->| |
| | mint WOPI token (TokenManager) |
| | build editor URL with wopisrc |
| editor iframe / page | |
|<-------------------------| |
| | GET /wopi/files/{id}?token=... |
| |<----------------------------------|
| | CheckFileInfo response |
| |---------------------------------->|
| | GET /wopi/files/{id}/contents |
| |<----------------------------------|
| | file bytes |
| |---------------------------------->|
| ← editing session → | |
| | POST /wopi/files/{id}/contents |
| |<----------------------------------|
| | 204 No Content |
| |---------------------------------->|
```

### Key classes

| Class | Responsibility |
|---|---|
| `PageController` | Renders overview page; injects editor URL into NC initial state |
| `EditorController` | Renders editor page; mints WOPI token; builds editor URL from discovery XML |
| `WopiController` | WOPI protocol endpoint — handles all `/wopi/files/` requests |
| `TokenManager` | Creates and validates WOPI tokens; manages token TTL and guest vs user access |
| `DiscoveryService` | Fetches and caches the editor's discovery XML; resolves MIME → action URL |
| `ShareController` | Issues guest tokens for public share links |
| `WopiMapper` / `WopiLockMapper` | Persistence for WOPI tokens and file locks |
| `CleanupJob` | Background job — expires stale locks and tokens |

---

## WOPI spec compliance

### Operations

| Operation | `X-WOPI-Override` | Status | Notes |
|---|---|---|---|
| CheckFileInfo | — | ✅ | `GET /wopi/files/{id}` |
| GetFile | — | ✅ | `GET /wopi/files/{id}/contents`; HTTP Range supported |
| PutFile | — | ✅ | `POST /wopi/files/{id}/contents`; lock-enforced, optimistic version check, quota check |
| Lock | `LOCK` | ✅ | |
| Unlock | `UNLOCK` | ✅ | |
| RefreshLock | `REFRESH_LOCK` | ✅ | |
| GetLock | `GET_LOCK` | ✅ | |
| UnlockAndRelock | `LOCK` + `X-WOPI-OldLock` | ✅ | |
| RenameFile | `RENAME_FILE` | ✅ | Authenticated users only; conflict returns 400 + `X-WOPI-InvalidFileNameError` |
| PutRelativeFile | `PUT_RELATIVE_FILE` | ⏳ Phase 6 | `UserCanNotWriteRelative: true` suppresses Save As in the editor UI |
| DeleteFile | `DELETE` | — | Deletion is handled by NC outside WOPI |

### CheckFileInfo capability flags

| Flag | Value | Notes |
|---|---|---|
| `SupportsUpdate` | `true` | PutFile is implemented |
| `SupportsLocks` | dynamic | `true` when an NC lock provider is available |
| `SupportsGetLock` | `true` | GetLock is implemented |
| `SupportsExtendedLockLength` | `true` | `lock_id` column is `VARCHAR(1024)` |
| `SupportsRename` | per session | `true` for authenticated users; `false` for guests |
| `UserCanRename` | per session | `true` for authenticated users; `false` for guests |
| `UserCanNotWriteRelative` | `true` | PutRelativeFile deferred to Phase 6 |
| `UserCanWrite` | per token | stamped at token-issue time from file/share permissions |
| `IsAnonymousUser` | per session | `true` for guest (share-link) sessions |
| `HasContentRange` | `true` | partial file reads via HTTP Range are supported |
| `HideExportOption` | per token | derived from share `hide_download` flag |
| `DisablePrint` | per token | derived from share `hide_download` flag |
| `DisableExport` | per token | derived from share `hide_download` flag |

---

## Public share support

Share link visitors (`/s/{token}`) receive a guest WOPI token via `ShareController`.
File access, locking, and `CheckFileInfo` flags (`HideExportOption`, `DisablePrint`,
`UserCanWrite`, etc.) are all derived from the share's permissions and `hide_download`
flag at token-issue time.

**Known gaps:**

- **KG1** — Password-protected shares: users must authenticate at `/s/{token}` before
navigating to the editor.
- **KG2** — Authenticated users arriving through share links receive guest tokens.
- **KG3** — Federated/remote shares not tested.

---

## Architecture notes

The WOPI token row (`oc_office_wopi`) is the authority for per-session flags
(`canwrite`, `hideDownload`, `ownerUid`). Flags are stamped at token-generation
time and not re-read on subsequent WOPI requests — this avoids a per-request
`IShareManager` lookup on every CheckFileInfo heartbeat, matching the richdocuments
pattern. Trade-off: share revocation mid-session is not enforced within the token TTL
(10 h).
8 changes: 7 additions & 1 deletion appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,14 @@
<category>office</category>
<bugs>https://github.com/nextcloud/office</bugs>
<dependencies>
<nextcloud min-version="31" max-version="32"/>
<nextcloud min-version="33" max-version="35"/>
</dependencies>
<background-jobs>
<job>OCA\Office\BackgroundJob\CleanupJob</job>
</background-jobs>
<settings>
<admin>OCA\Office\Settings\Admin</admin>
</settings>
<navigations>
<navigation>
<id>office</id>
Expand Down
5 changes: 4 additions & 1 deletion img/app-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 4 additions & 1 deletion img/app.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,17 @@

namespace OCA\Office\AppInfo;

use OCA\Office\Listener\LoadAdditionalScriptsListener;
use OCA\Office\TokenManager;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
use OCP\Collaboration\Resources\LoadAdditionalScriptsEvent;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\IRootFolder;
use OCP\IURLGenerator;
use OCP\IUserSession;

class Application extends App implements IBootstrap {
public const APP_ID = 'office';
Expand All @@ -18,6 +25,17 @@ public function __construct() {
}

public function register(IRegistrationContext $context): void {
$context->registerEventListener(LoadAdditionalScriptsEvent::class, LoadAdditionalScriptsListener::class);

$context->registerService(TokenManager::class, static function ($c) {
return new TokenManager(
$c->get(IRootFolder::class),
$c->get(\OCA\Office\Db\WopiMapper::class),
$c->get(IURLGenerator::class),
$c->get(IEventDispatcher::class),
$c->get(IUserSession::class)->getUser()?->getUID(),
);
});
}

public function boot(IBootContext $context): void {
Expand Down
Loading