Commit Graph
220 Commits
Author SHA1 Message Date
Nathan Vasse ab8e0ebc39 (frontend) share an item with contacts imported from a file
Plug the ui-kit share modal file import onto the new batch share
endpoint. The option only shows up when ALLOW_SHARE_IMPORT_FILE is
enabled in the config. Errors are rendered inside the import modal
instead of the global toast so the user can fix the file and retry
without losing context.

The e2e environment enables the flag to cover the flow end to end.
2026-07-28 11:37:10 +02:00
Nathan Vasse 16f11c12e7 (backend) add an item batch share endpoint
Sharing a folder with many contacts one call at a time is slow and can
leave a partial state when one of them fails. This endpoint accepts a
list of email/role rows, validates them all before any write, then
creates accesses for known users and invitations for unknown emails.
Rows targeting users already covered by an equal or higher role are
skipped and reported so the client can inform the user.

The feature is disabled by default and gated by the new
ALLOW_SHARE_IMPORT_FILE setting exposed in the config endpoint.
2026-07-28 11:26:07 +02:00
Nathan Vasse 9b545b6087 (frontend) show the messages widget button on the homepage
Anonymous visitors have no help menu, so the homepage loads the
widget floating button instead when the widget is configured. This
gives them the same support entry point as logged-in users.
2026-07-28 09:41:07 +02:00
Nathan Vasse d3d9dff6b6 📝(changelog) mention the storage gauge and reorder entries
The frontend storage gauge deserved its own changelog entry, and the
local backend line moves after the already released entries to keep
the section in insertion order.
2026-07-23 17:08:11 +02:00
Nathan Vasse 0f7ee3a3ed (backend) add a local entitlements backend with storage limits
Deployments without a DeployCenter service had no way to enforce
storage quotas. This backend computes each user's usage locally and
applies a configurable default limit, overridable per user in the
admin (0 meaning unlimited) and skippable for users created before a
cutoff so quotas can be rolled out to new users only. The quota is
soft: can_upload runs before the file size is known, so one upload
can overshoot before the next one is blocked.
2026-07-23 17:08:10 +02:00
Nicolas Clerc 5203cc4483 (backend) show human readable item size in the admin
The item size was displayed as a raw byte count in the admin detail
page, which is hard to read. Format it with filesizeformat.
2026-07-23 09:54:18 +02:00
Nicolas Clerc 5cd2816435 (backend) expose item existence in the malware detection admin
Detection records whose item is gone can only be cleaned up manually.
Add an "item exists" column and filter to the admin so orphan records
can be spotted and deleted easily.
2026-07-23 09:54:18 +02:00
Nicolas Clerc e5f22ea2c8 🐛(backend) delete malware detection record when purging an item
When an item was purged while its analysis was still pending or
processing, the detection record was left behind: the analysis kept
being relaunched and crashed on the missing file, leaving the record
stuck forever and holding a processing slot.
2026-07-23 09:54:05 +02:00
Nicolas Clerc 8ba9d7b3f9 (backend) make the upload ACL configurable
GCS based storages like S3NS reject presigned PUT URLs signing the
x-amz-acl header: their S3 compatibility layer consumes x-amz-*
headers having an x-goog-* equivalent, so the signature check no
longer finds the header in the request. Objects are private by
default on S3 and GCS, so the ACL can simply be dropped by setting
AWS_S3_UPLOAD_ACL to an empty string. The setting is exposed in the
config endpoint so the frontend can send a header matching the
signature.

See https://documentation.s3ns.fr/storage/docs/aws-simple-migration
2026-07-22 16:02:04 +02:00
Nicolas Clerc 6ff79c6fca 🔧(docker) harden the Dockerfile
Address the maintainability findings raised by the new SonarCloud
docker analyzer: drop the floating pip upgrade (nothing uses pip in
the image, the build relies on uv, and the base image already ships
a current pip), stop storing apk indexes in the image layers, quote
DRIVE_STATIC_ROOT and sort the core package list.
2026-07-22 15:45:12 +02:00
Nicolas Clerc bd6f6b8039 🐛(docker) pin collabora image and adapt to its new runtime contract
The collabora/code image published on 2026-07-18 (26.04.2.2.1) drops
the shell and the start script: our CMD-SHELL healthcheck could not
run at all (no /bin/sh) and extra_params was no longer read, so SSL
came back on and broke the plain-http WOPI discovery. Every e2e job
failed with "container drive-collabora-1 is unhealthy".

Pin the image and migrate to the new contract: coolwsd options go
through command arguments, and the health probe relies on the
built-in coolwsd --probe, overridden to target the http endpoint
since it defaults to https.
2026-07-22 15:45:12 +02:00
Nicolas Clerc 1776a7187a 🔖(minor) bump release version 0.20.0
Added

- (backend) allow converting a file while it is being analyzed
- (frontend) add file type, contact and modification date topbar filters
- (frontend) add location, file type, contact and date search filters

Fixed

- 🐛(nginx) let search engines see the noindex directive to drop public URLs
- 🐛(backend) find deleted root items when searching the trashbin
- 🐛(backend) exclude folders from file type search results
- 🐛(frontend) keep uploaded items usable while malware analysis runs
- 🐛(backend) stream export files from S3 without buffering
2026-07-15 13:44:19 +02:00
Nicolas Clerc 0d40256363 🐛(nginx) let search engines see the noindex directive
robots.txt blocked all crawling, so crawlers could never fetch the
pages and never saw the noindex meta tag: URLs discovered through
external links could still end up listed in search results.

Allow crawling in robots.txt and add a X-Robots-Tag noindex header on
frontend pages and media files so every response carries the directive.
2026-07-08 17:45:54 +02:00
Nicolas Clerc 8e5fb9971e 🐛(backend) find deleted root items when searching the trashbin
Search rebuilds the visible set from the user's accesses, skipping those
whose item was soft deleted. A root item holds its own access, so
deleting it made it unreachable from any location, trashbin included.
Hard deleted items remain excluded, and the scope filter still keeps
deleted items out of regular search results.
2026-07-08 16:37:59 +02:00
Nicolas Clerc ca6bbd50f7 🐛(backend) exclude folders from file type search results
The category filter keeps folders on explorer listings so navigation
stays possible. A search is not a navigation: folders have no file type
and only add noise to the results.
2026-07-08 16:31:11 +02:00
Nicolas Clerc ebf39cf9bb (frontend) filter the search modal by location, type, contact and date
Replace the search modal type/workspace/scope filters with the location,
file type, shared-with and modification date filters, matching the new
search design.
2026-06-29 16:49:52 +02:00
Nicolas Clerc 84986fdf6c (frontend) filter items by modification date
Add a "Modified" filter to the topbar with Today / Last 7 days /
Last 30 days / This year presets and a compact custom date range
picker, wired to the updated_at range filter.
2026-06-29 15:42:58 +02:00
Nicolas Clerc dd7b20ba23 🐛(backend) stream export files from S3 without buffering
default_storage.open() downloads the whole object in memory before the
first read, so exporting folders holding large files can exhaust the
worker memory. Stream straight from the boto3 response body instead.
2026-06-23 18:00:58 +02:00
Nicolas Clerc d49b79a7ef (backend) wait for analysis before converting a file
Conversion reads the source bytes, so it must not run before malware
analysis confirms the file is safe. convert_file now waits while the
source is analyzing and drops the placeholder if it never clears.
2026-06-23 17:22:52 +02:00
Nicolas Clerc 5ed80ae77e 🐛(frontend) keep analyzing items accessible
Marking the analyzing state as transient locked freshly uploaded items in
the UI while malware detection ran. The uploader must keep full access
during analysis, so split polling from the transient UI lock and surface
the analyzing label as a non-blocking badge. The 404 conversion toast is
now limited to converting placeholders.
2026-06-23 17:22:52 +02:00
Nicolas Clerc 4fd3c79566 🔖(minor) bump release version 0.19.0
Added

- (backend) manage reconciliation requests for user accounts
- (backend) add recursive folder export as ZIP archive
- (frontend) add folder export action
- (backend) background conversion of legacy Office files
- (backend) allow grist file upload
- (frontend) add CTA on public link for anonymous and authenticated users

Changed

- 🐛(backend) replace VersionId by Etag for WOPI
- 🐛(backend) sanitize slash in template-created filenames

Removed

- 🔥(backend) drop deprecated numchild columns from item
2026-06-09 13:08:43 +02:00
neilcroft 05754638ad 🐛(backend) sanitize slash in template-created filenames
Titles containing '/' (e.g. "30/03/30 - liste à faire") produced
a file_key with spurious path separators, crashing WOPI on open.

Extract `format_template_filename()` to replace '/' with '-' when
building the filename from a template title.

Closes #626
2026-06-04 11:26:58 +02:00
Nathan VasseandNicolas Clerc 4adbe9f2b7 (frontend) wire CTAs into header and standalone file preview
UserProfile now renders AnonymousCTA along with a dropdown menu
(copy link, language picker) when no user is authenticated, so
visitors on a public page can still act on it without the user
menu. CustomFilesPreview gains a CONTEXTUAL mode that swaps in
the right CTA based on auth state, used by the standalone file
preview page which is now wrapped in GlobalLayout to expose the
auth context.
2026-06-04 11:16:40 +02:00
Nicolas Clerc a4105a3432 (backend) allow grist file upload
The .grist extension was already in FILE_EXTENSIONS_ALLOWED but
upload failed at MIME type validation because python-magic detects
grist files as application/vnd.sqlite3.
2026-06-03 18:38:46 +02:00
Nicolas Clerc 4f85801abe ♻️(frontend) generalize duplicating poller to transient items
The same polling loop fits any transient upload state.

Rename the duplicating poller to a transient one driven by
TRANSIENT_UPLOAD_STATES so converting items are picked up without copying
the hook, and the explorer refreshes automatically when background
conversion finishes.
2026-06-03 16:47:38 +02:00
Nicolas Clerc cd7bebfcb8 (frontend) add folder export action
Expose the backend folder ZIP export from explorer folder menus
through the Download action.
2026-05-28 10:43:52 +02:00
Nicolas Clerc ded840a6e1 (backend) add folder export streaming endpoint
Issue #412 asks for a way to download an entire folder. Add a
GET /items/<id>/export/ action that streams a recursive ZIP archive of
the folder, preserving the directory hierarchy and skipping soft-deleted
or not-yet-uploaded descendants.
2026-05-28 10:43:52 +02:00
Nicolas Clerc 9995a2af30 📝(doc) document user account reconciliation
Explain the CSV import flow and the form URL setting so admins can run
account merges.
2026-05-27 17:36:47 +02:00
Nicolas Clerc 06d841c5a1 🔥(backend) drop deprecated numchild columns from item
The _deprecated_numchild and _deprecated_numchild_folder fields were
kept temporarily to preserve the underlying columns during the tree
model transition. The columns are no longer read or written, so the
fields and their columns can now be removed.
2026-05-26 09:25:17 +02:00
RolletQuentinandManuel Raynaud 3293ce5269 🐛(backend) replace VersionId by Etag for WOPI
When we try to get the VersionId from the s3 response
but this one is not send by the s3 storage (garage for example),
we get a 500 error.
To fix this issue we use the ETag sent by the object storage to track
the version id. This ETag is present also when versionning is not
implemented.

Co-authored-by: RolletQuentin <rolletquen@gmail.com>
2026-05-18 14:25:39 +02:00
Nathan Vasse 18d8b22eb7 📝(doc) update changelog
Update the changelog based on the recent commits about
file previewer.
2026-05-11 14:48:22 +02:00
Manuel Raynaud 9add4753d1 🔖(minor) bump release version 0.18.0
Added

- (backend) add organization metrics to usage API
- (backend) add entitlements context and can_upload reason
- (frontend) add entitlement disclaimer modal
- (frontend) render PDF previews at per-page dimensions

Fixed

- 🐛(backend) accept CDFV2 mimetype from newer libmagic
- 🐛(backend) better transaction management on duplicate action

Removed

- 🔥(backend) remove mirroring feature
2026-05-04 16:47:06 +02:00
Nathan Vasse 6569287391 (backend) capture item_duplicate posthog event
Duplication is currently invisible to product analytics because the
event is fired from the API rather than the UI. Emit it from the
viewset right after the duplicate row is created so the duplicated
item context (workspace, mimetype, ...) is attached to the event.
2026-05-04 15:58:32 +02:00
Manuel Raynaud 68abb54dbb 🐛(backend) better transaction management on duplicate action
On the duplicate action we are using the decorator @transaction.atomic
to be sure that the duplicated item and its accesses are correctly
created. The problem with that is that the celery task doing the file
duplication on the object storage can be executed before the transaction
is commited leading to an error saying that the duplicated_item does not
exists.
2026-04-29 22:07:56 +02:00
Nathan Vasse 6049113dfe 🐛(backend) accept CDFV2 mimetype from newer libmagic
Scalingo's Ubuntu runtime ships a newer libmagic that returns
application/CDFV2 for legacy .doc/.xls/.ppt files, where Alpine's
older libmagic (used in our Docker image) returns the older label
application/x-ole-storage. Both describe the same OLE2 / Composite
Document File V2 container.

detect_mimetype() already treats application/x-ole-storage as a
generic content-detection result and falls back to extension-based
detection (yielding application/msword, application/vnd.ms-excel,
etc.). Without the same handling for CDFV2, legacy .doc uploads on
Scalingo are rejected by the mimetype allow-list with
"mimetype not allowed application/CDFV2 for filename ...".
2026-04-29 12:15:02 +02:00
Nathan Vasse 7a95dcf38a 📝(doc) update changelog
Fix the mis-added entries inside the previous release back to
the unreleased one. And add new entry for the pdf mixed pages
size rendering.
2026-04-29 11:37:08 +02:00
Nathan Vasse 59292f6052 📝(doc) update changelog
Record the metrics filter, entitlement payload additions, and the
frontend disclaimer feature shipped on this branch, alongside the
already-landed organization metrics entry.
2026-04-29 10:39:31 +02:00
Manuel Raynaud 805ef77521 🔥(backend) remove mirroring feature
The mirroring feature was hard to maintain and not performant. We should
rely on external tools made for that like RClone.
2026-04-23 17:42:48 +02:00
Manuel Raynaud 3ca5b0e296 🔖(minor) bump release version 0.17.0
Added

- (backend) make invitation validity duration configurable via env var
- (frontend) enhance upload toast with progress, errors and cancel support
- (frontend) add ErrorIcon component and support numeric icon sizes
- (frontend) make file upload abortable in driver layer
- (frontend) files preview v2
- 🔧(project) add DJANGO_EMAIL_URL_APP environment variable

Fixed

- 🐛(frontend) add actions menu on mobile My Files page
- 🐛(frontend) show actual selection count in hard delete modal
- 🐛(frontend) Responsive broken with long filters in search #659
- 🐛(front) set size and variant on trash navigate modal #666
- 🐛(frontend) fix uploads continuing after parent folder deletion
- 🐛(frontend) fix SDK picker link reach promotion
- 🐛(backend) route share invitation link to file view for files
- 🐛(frontend) fix "+ New" menu in read-only folders and virtual tabs
- 🐛(frontend) range selection freezes when there are many items in the list
- 🐛(backend) fix openapi schema for item access endpoints
- 🐛(backend) load jwks url when OIDC_RS_PRIVATE_KEY_STR is set
2026-04-23 15:43:49 +02:00
Nathan Panchout 3731033f5b 🔧(project) add DJANGO_EMAIL_URL_APP environment variable
Share invitation emails embedded `Site.domain` directly, producing
schemeless links that mail clients failed to resolve. Introduce a
`DJANGO_EMAIL_URL_APP` environment variable holding the app's
absolute URL used when building invitation links, with a fallback
on the current Site domain when unset. Wire it in dev env, helm
dev values, the helm example and the env reference.
2026-04-23 12:05:26 +02:00
Nathan Panchout af8ba1031f 🐛(backend) route share invitation link to file view for files
Clicking the invitation link for a shared file opened the folder
explorer page with an empty children listing, because
`Item.send_email` hardcoded `/explorer/items/<uuid>/` regardless of
the item type.

Branch on `item.type` to use the dedicated file route
`/explorer/items/files/<uuid>/` already served by nginx and used by
the in-app share-link copy button.
2026-04-23 12:05:23 +02:00
Nathan Vasse a12771fe08 🐛(frontend) fix SDK picker link reach promotion
Switch to useMutationUpdateLinkConfiguration and preserve the
item's existing link_role. Also add the missing sdk.explorer.cancel
translations for en and nl so the Cancel button label renders
correctly. This should have been done when migration to this new
API route. The existing update did not have any effect.
2026-04-22 16:00:15 +02:00
Manuel Raynaud d120171944 🐛(backend) load jwks url when OIDC_RS_PRIVATE_KEY_STR is set
When the resource server is enabled and the backend used is
JWTResourceServerBackend, then the API should expose a JWKS endpoint
to share the RSA public key to the OIDC provider. Everything is made
in the Django LaSuite library, but the URL is not included in the
Drive URLs. This commit adds it when the setting OIDC_RS_PRIVATE_KEY_STR
is set.
2026-04-22 13:37:30 +02:00
Nathan Vasse 352e19580e (backend) make invitation validity duration configurable via env
The invitation validity duration was hardcoded to 7 days. Expose it as
an INVITATION_VALIDITY_DURATION env var so operators can tune it per
deployment without patching settings. Default remains 7 days.
2026-04-22 10:09:31 +02:00
Nathan Vasse 6655b8fbe8 🐛(backend) fix openapi schema for item access endpoints
`ItemAccessViewSet.get_serializer_class` depends on `self.item`, which
reads `self.kwargs["resource_id"]`. This is unavailable during
drf-spectacular introspection, so spectacular fails to resolve the
serializer and drops the requestBody for POST/PUT/PATCH operations.

Declare the schema statically via `@extend_schema` and
`@extend_schema_view` so the generated OpenAPI exposes the proper
request and response payloads for item access endpoints.
2026-04-21 10:24:18 +02:00
Nathan Panchout 5966e14c46 🐛(frontend) fix range selection freeze on large folders
Drop selectedItems / selectedItemsMap from GlobalExplorerContext and
move every call-site to the selection store introduced in the previous
commit. Rows of the embedded explorer grid are extracted into a memoed
EmbeddedExplorerGridRow that subscribes to its own id via
useIsItemSelected, and the name/actions/mobile cells are memoed and
read their selection status the same way.

High-level consumers that only need a boolean or a count use
useHasSelection / useSelectionCount so they no longer re-render on
every marquee tick:

- AppExplorerInner uses useHasSelection to toggle the selection bar
- ExplorerDndProvider splits the count consumers into dedicated child
  components (drag overlay and move confirmation modal)
- useTableKeyboardNavigation subscribes imperatively through
  selectionStore.subscribe so the focus effect runs without
  invalidating the host component

EmbeddedExplorer creates its own local store so the move modal and the
SDK picker keep their selection scoped and do not leak into the main
explorer selection.

Fixes #124
2026-04-20 17:09:53 +02:00
Nathan Panchout faee0de673 🐛(front) fix "+ New" menu in read-only folders and virtual tabs
The "+ New" dropdown used to hide all its entries when the user lacked
children_create on the current folder, leaving an empty popover. On
virtual tabs (Recent, My Files, Shared with me, Starred) there is no
real current folder either, so the same empty state could be reached.

Always populate the menu and, when the user cannot create in place,
fall back to creating the item in "My Files" (no parent). After a
fallback creation we redirect:
- into the new folder for folder creation
- to the My Files view for file creation, since a file is not a
  navigable route
The new item is pre-selected in both cases.
2026-04-20 15:58:53 +02:00
Nathan Vasse 30cfcc7f46 📝(doc) update changelog
Add entry about the file preview v2 iteration.
2026-04-20 15:01:33 +02:00
Nathan Panchout 4c6e89611e (front) add e2e tests for upload cancellation on deletion
Test two scenarios: deleting the current folder cancels
its uploads, and deleting one folder does not cancel
uploads targeting a different folder.
2026-04-20 14:43:03 +02:00
Nathan Panchout e79c3d1f63 🐛(front) set size and variant on trash navigate modal
A gap had been created because the modal type
was missing.
2026-04-20 14:23:48 +02:00