Skip to content

Roadmap / feature ideas

A non-exhaustive list of features the module could grow into. These are ideas, not commitments — the order roughly reflects how transformative each one would be relative to what the module does today.

Items 1–3 would change what the module is. Items 4–7 would round out the "document collaboration platform" claim. The rest are polish and integration points.

1. Per-user revocable WebDAV sessions

Current state. The lock list shows "who has file X open in LibreOffice". The per-file revocation lever (drush webdav:revoke-file) bumps a counter that invalidates every outstanding URL for that file, across every user. There's no "log this one user out of this one file" lever for the URL-token path. The Basic-auth path has no per-session revocation lever at all today — credentials are the user's live Drupal password and stay valid until the user changes it (or is blocked).

What's missing. An admin UI that, for a given lock or user, both releases the open Sabre lock and invalidates outstanding WebDAV URLs for that user only. Today's revocation model is per-file; this would add a per-(user, file) dimension. Pairs naturally with per-user app passwords for the Basic-auth path — instead of "log this user out of WebDAV entirely by making them change their Drupal password", an admin would revoke one named app password (a Cyberduck mount, an automation script, …) without affecting the user's other WebDAV clients or their Drupal login.

Sketch. Extend RevocationStore so the keyed state is (uid, fid) → counter instead of fid → counter. The HMAC over the URL incorporates the per-(uid, fid) counter alongside the master secret. The admin UI grows a "force end session" button on each lock row. Cost: bigger keyvalue footprint (O(users × files)), but small in practice — only "touched" pairs get rows. For Basic auth: a webdav_app_passwords table keyed by user + named credential, bcrypt-verified. Replace the live Drupal-password check in BasicAuthenticator with an app-password lookup. See user-memory note project_webdav_basic_auth.md for the v2 app-password design.

2. Conflict detection and "save as copy" recovery

Current state. WebDAV PUT silently overwrites whatever is on disk. If two users edit the same file at the same time (lock expiry, network partition, LibreOffice's autosave behavior), the losing write is just gone. Sabre's ETag plumbing is in the code path (EntityFileNode::getETag) but no If-Match check fires on PUT.

What's missing. A way for the server to refuse a PUT whose client-side ETag doesn't match the current entity revision, plus a UX flow that turns the refusal into "the file changed since you opened it — save as copy under a new name?".

Sketch. In EntityFileNode::put, if the request carries an If-Match header, compare the supplied ETag to the entity's current value; on mismatch, throw \Sabre\DAV\Exception\PreconditionFailed. Add a Drupal status message + a "save as copy" form action when the user re-opens. LibreOffice surfaces 412 as a "save failed" dialog; documenting the workflow in docs/libreoffice-macos.md and docs/libreoffice-windows.md is part of the feature.

3. DASL search and a virtual "all files" directory

Current state. The module's Tree resolves single files by fid. There's no listable directory. LibreOffice's "Open from Server…" dialog needs PROPFIND on a directory to be useful.

What's missing. A SEARCH verb handler (RFC 5323 — DASL) that exposes "files visible to me" or "files of bundle X" as searchable. Pairs with a virtual /webdav/files/ collection that PROPFINDs to a list of fids the current user can download.

Sketch. A new Drupal\webdav\Tree\SearchableCollection impl, backed by an entity-query against File entities filtered through file_access. Sabre has DASL support out of the box; the work is on the Drupal side (access checks, paging, search index integration if Solr / ES is wired).

4. Operator-shared expiring URLs

Current state. WebDAV URLs are bound to a session-derived password and an access webdav permission. There's no way for an operator to mint a "share this with this person until Friday" URL for a recipient who doesn't have a Drupal account.

What's missing. A ShareToken config entity (fid + grantee email + expires_at + signature). On the file's contextual menu, "share via WebDAV → expires in 7 days → recipient: foo@example". The recipient gets an email with a one-time URL that mints short-lived WebDAV credentials when claimed.

Sketch. A new entity, a tiny mail template, a controller that exchanges a share-token cookie for a per-session WebDAV password. Distinct from access webdav because the grantee can be non-Drupal-user.

5. Webhook on PUT

Current state. A successful WebDAV PUT updates the File entity and is observable via Drupal entity hooks, but external systems (Slack, search indexers, the user's own audit_trail module) need to subscribe to internal events.

What's missing. A WebDavPutCompletedEvent and a configurable webhook endpoint. Site builders register a URL; the module POSTs JSON {fid, uid, mime, bytes_diff, timestamp} after each PUT.

Sketch. Symfony EventDispatcher event + a small config form + optional HMAC signing of the webhook body so the receiver can verify origin. EntityFileNode::put has a natural insertion point.

6. Trash / soft delete on DELETE

Current state. A WebDAV DELETE removes the File entity outright. Recoverable only from backups.

What's missing. Integration with the contrib trash module (or a built-in soft-delete table): a WebDAV DELETE becomes a 30-day-recoverable trash event with a "restore" action in the admin UI.

Sketch. Detect the trash module, wrap the entity delete in its trash API call if available; otherwise log a watchdog warning. A small config option toggles the behavior.

7. In-browser WebDAV file explorer

Current state. Every WebDAV interaction requires a desktop app handoff (LibreOffice, Word). Users on iPad / Chromebook are out of luck.

What's missing. A /admin/content/webdav-files Drupal page that PROPFINDs the user's WebDAV tree and renders an inline explorer with edit-in-Collabora / preview-with-PDF-viewer options.

Sketch. A controller + a small Vue/Lit JS component (re-using the existing webdav-link library pattern). Pairs naturally with item 3 (DASL search) and item 4 (share URLs).

8. Resumable / chunked uploads

Current state. Large file PUTs are all-or-nothing. A 100 MB ODP on a flaky network = full re-upload on every retry.

What's missing. RFC 8995-style Content-Range-driven chunked PUT support. Sabre supports it; Drupal's File API doesn't natively but bytes can be buffered in private://tmp/webdav-uploads/<fid>.part.

Sketch. Modify EntityFileNode::put to detect Content-Range headers, append to a .part file, finalize on the last chunk (rename to canonical path, run mime sniff, sync entity).

9. Per-file audit trail of WebDAV operations

Current state. Drupal watchdog records WebDAV PUT/DELETE at INFO level, but the messages aren't structured and aren't tamper-evident.

What's missing. Structured audit-log integration: every PUT / LOCK / UNLOCK / GET emits a signed record via the audit_trail contrib module (HMAC tamper-evident log). Particularly valuable where document provenance matters legally, such as notarial or records-management workflows.

Sketch. Optional dependency on audit_trail; an event subscriber on the WebDAV events that emits one audit row per operation.

10. Quota awareness

Current state. LibreOffice's "save" path silently fails when the server runs out of disk; the user only learns when the next PUT returns 507 (or worse — the response body says "Insufficient Storage" but LO interprets it generically).

What's missing. Implement Sabre's IQuota interface so PROPFIND surfaces DAV:quota-available-bytes / DAV:quota-used-bytes. LibreOffice reads these before writing and warns the user proactively.

Sketch. A tiny Drupal\webdav\Quota\DriveQuota service wired to diskFreeSpace() for the file URI's stream wrapper.

11. Multi-file "queue these to LibreOffice"

Current state. One click = one file open. Reviewing 20 contracts in sequence means 20 individual round-trips.

What's missing. A UI affordance (checkbox + button on a file list view) that opens N files in sequence with a tiny inter-open delay. Niche, but useful for bulk document-review workflows.

Sketch. A JS helper that iterates the mint endpoint with a sleep between iterations and assigns window.location.href each time. LibreOffice picks them up as separate documents.

12. Cloud-Office handoff (Microsoft Graph / Google Drive)

Current state. "Open with LibreOffice" only works if LibreOffice is installed locally. Users on a Chromebook or with "Office Online" subscriptions have no path.

What's missing. A new webdav_link_target plugin family ("cloud") that emits Microsoft Graph deep links / Google Drive "upload + open" intents instead of libreoffice: scheme URLs.

Sketch. Refactor WebDavLinkTarget into a plugin manager with two implementations: UriSchemeTarget (current behavior) and CloudTarget (new). The latter would need per-tenant OAuth config — non-trivial but tractable.

13. Per-user default editor preferences

Current state. Every user sees the same target list — a .docx shows both "Open with LibreOffice" and "Open with Microsoft Word" for everyone with access webdav.

What's missing. A per-user setting on /user/{uid}/edit ("My preferred editor: LibreOffice / Word / always ask"). The formatter renders the preferred target as the primary link and demotes the alternatives to a dropdown.

Sketch. A user_field on the user entity + a small render-time selector. Needs care around cache contexts (user would fragment the cache again — user.permissions doesn't capture per-user prefs, so this would have to go via a small JS preference cookie + a client-side reorder, not a render-time context).


Out-of-scope (intentional)

  • CalDAV / CardDAV: sabre/dav supports them, but they target a different user need than file editing.
  • Real-time co-editing: that's Collabora / OnlyOffice territory. The module hands files off to those when configured; it doesn't host the editor itself.
  • Mobile WebDAV clients: documented externally — the module speaks RFC 4918, mobile clients work, but the module won't ship vendor-specific shims.