Commit Graph
95 Commits
Author SHA1 Message Date
Nicolas Clerc 2117f0dbf1 🐛(ci) run crowdin workflows on node 22
The frontend package.json now requires node >= 22, so the crowdin
workflows fail at yarn install with the node 20 they still request.
Align them with drive-frontend.yml and update the reusable job
default so future callers cannot regress silently.
2026-08-07 15:30:19 +02:00
Nicolas Clerc 464cd7ab2f 🔖(minor) bump release version 0.21.0
Added

- (backend) make the upload ACL configurable to support GCS based storages
- (frontend) show the messages widget button on the homepage
- (frontend) open the messages widget from the help menu
- (backend) add an item batch share endpoint gated by ALLOW_SHARE_IMPORT_FILE
- (frontend) share an item with contacts imported from a file
- (backend) add a quota_excluded flag on items
- (backend) apply per-audience attributes to external api items
- (backend) add a grant_unlimited_storage command

Changed

- 🔧(docker) drop the unused pip upgrade and apk caches from the image
- (backend) expose item existence in the malware detection admin
- (backend) show human readable item size in the admin
- 🚚(global) move favorite items API endpoint to `/items/favorites/`

Fixed

- 🐛(docker) pin collabora image and adapt to its new runtime contract
- 🐛(backend) delete malware detection record when purging an item
- 🔒️(backend) reject unsafe filenames requested by WOPI renames
- 🔒️(backend) analyze file content written through WOPI
2026-08-07 15:30:19 +02:00
Nicolas Clerc 9ec728847d 🔒️(backend) scan files written through WOPI
PutFile wrote the content straight to object storage, while malware
detection only ran on the upload endpoint. Editing a document was
therefore a way to store content that was never analysed.

The item stays READY during the analysis: a collaborator cannot open a
file that is not READY, so flipping the state would eject everyone from
the document on every save.
2026-08-07 12:39:16 +02:00
Nicolas Clerc 5a4b36c942 🔒️(backend) reject unsafe WOPI rename targets
The requested name was decoded from UTF-7 and used as is, so a path
separator could reach the storage key and leave the item without an
extension. A second rename then granted it any extension, bypassing the
allowed list that only the upload path enforced.

Extensions are now compared case insensitively on both sides, so entries
declared with capitals are no longer dead.
2026-08-07 12:39:16 +02:00
Nicolas Clerc 2a5bbfcfea ⬆️(mail) bump @html-to/text-cli to 0.6.0
Close the Snyk upgrade PR #722 and refresh the html-to-text chain
used to derive the plain text mail templates.
2026-08-06 16:19:15 +02:00
Nicolas Clerc 60f7e3760c 🔒️(backend) resolve template files through a static allowlist
Snyk Code flags the f-string path built from the request extension as
a path traversal. The DRF ChoiceField already restricts the value but
static analysis cannot follow it. Selecting the file name from a
static mapping makes the sink independent from user input, and the
serializer choices now derive from that single mapping.
2026-08-06 16:19:15 +02:00
Nicolas Clerc 5947ecdc95 ⬆️(docker) bump the frontend image to alpine 3.24
The alpine 3.22 base of nginx-unprivileged carries 69 known CVEs
including a critical one in openssl (CVE-2026-31789). Renovate does
not manage Dockerfile images on this repo, so the bump is manual.
2026-08-06 16:19:15 +02:00
Nicolas Clerc 867527042d ⬆️(dependencies) bump nanoid to 3.3.17
Fix CVE-2026-67213 (infinite loop in customRandom), a transitive
dependency flagged by the Snyk check on both yarn lockfiles.
2026-08-06 16:19:15 +02:00
Nicolas Clerc f2fc2acf65 ⬆️(ci) bump the build-mails job to node 22
mjml v5 pulls commander@15 which requires node >= 22.12. Include the
yarn.lock and build scripts in the mail templates cache key so
dependency bumps regenerate the templates.
2026-08-06 16:19:15 +02:00
Nicolas Clerc 6827ff633a 🐛(mail) allow mjml includes when building templates
mjml v5 ignores mj-include by default, silently dropping the whole
mail head (Django load tag, title, fonts and styles) from the
generated templates. Opt back in.
2026-08-06 14:17:17 +02:00
Nicolas Clerc d22851554b ⬆️(docker) bump mail-builder to node 22
mjml v5 pulls commander@15 which requires node >= 22.12, the
backend image mail stage was still building with node 20.
2026-08-06 14:17:17 +02:00
Nicolas Clerc b761d1dc7d ⬆️(backend) bump cryptography to 50.0.0
Fix CVE-2026-69247 (High) reported by trivy. cryptography is a
transitive dependency pinned in uv.lock, no direct requirement
to update.
2026-08-06 10:02:11 +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 722823cbad ♻️(settings) replace empty upload ACL with a "default" sentinel
An empty AWS_S3_UPLOAD_ACL in an env file is easy to mistake for
an unset variable, and unset must keep meaning "private". The
explicit "default" value states the intent: let the bucket's
default object ACL apply. The frontend translates it where the
config is read, so the drivers keep sending exactly the ACL they
are given.
2026-07-22 17:10:22 +02:00
Nicolas Clerc 3e9a0dd883 (frontend) send the upload ACL from the backend config
The upload ACL is now configurable and may be empty for storages that
do not support ACLs, so the PUT request must send exactly the ACL
signed in the upload policy. Read the value from the config endpoint
and pass it down to the S3 upload request.
2026-07-22 16:02:04 +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 d2c1e47b5d ⬆️(dependencies) update pillow
Raise the transitive pillow constraint to 12.3.0 to fix
CVE-2026-54058 (GHSA-pg7v-jwj7-p798), flagged by the trivy
scan on the backend image.
2026-07-22 15:45:12 +02:00
Nicolas Clerc ab2855ac0b ⬆️(dependencies) update django
Bump django to 5.2.15 to fix GHSA-mm6v-q8q9-pgcf.
2026-07-22 15:45:12 +02:00
Nicolas Clerc 20e5d6fec9 ⬆️(dependencies) update idna
Bump the transitive idna to 3.18 to fix GHSA-65pc-fj4g-8rjx, where
crafted input to idna.encode() bypasses the CVE-2024-3651 mitigation.
2026-07-22 15:45:12 +02:00
Nicolas Clerc 75dcb214eb ⬆️(dependencies) update python base image
Rebase the backend image on python:3.13.14-alpine (Alpine 3.24) to
pull the patched openssl fixing CVE-2026-31789. Stays within the
pinned 3.13 runtime, so no dependency re-resolution is needed.
2026-07-22 15:45:12 +02:00
Nicolas Clerc 756203e708 ⬆️(dependencies) update next, vite and turbo
Next 15.5.18, Vite 6.4.3 and Turbo 2.9.14 patch several advisories:
Next.js server components denial of service (GHSA-26hh-7cqf-hhc6),
Vite server.fs.deny bypass (GHSA-fx2h-pf6j-xcff) and Turbo local
code execution on untrusted repositories (GHSA-3qcw-2rhx-2726).
2026-07-22 15:45:12 +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 25e693b1d8 🔒️(backend) constrain joserfc >=1.6.8 for CVE-2026-49852
joserfc <1.6.8 accepts an empty HMAC key when verifying a JWT,
allowing token forgery if the secret is misconfigured (empty).
The dependency is pulled transitively via django-lasuite, which
does not enforce a minimum bound.
2026-07-08 09:31:31 +02:00
Nicolas Clerc 2a55efe93d (e2e) cover the search location filter
Add a "Quarterly" keyword spanning a my-files, a shared and a starred
item to the search fixture, and assert the location filter narrows the
search results accordingly.
2026-06-29 16:49:52 +02:00
Nicolas Clerc 8ef9fe8e8d 🐛(e2e) ignore the make pseudo-target error regardless of locale
runTarget only ignored "make: *** No rule to make target", missing the
"make[N]:" prefix and non-English locales. Force LC_ALL=C and match the
message loosely.
2026-06-29 16:49:52 +02:00
Nicolas Clerc d04e2d3657 🔥(frontend) drop the unused search modal filters
Remove the type, workspace and scope filter components, superseded by the
location filter in the search modal.
2026-06-29 16:49:52 +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 77b3156805 (frontend) add "more than a year" modification date preset
Filter items last modified over a year ago, available wherever the
modification date filter is used.
2026-06-29 15:42:59 +02:00
Nicolas Clerc ae60204f14 ♻️(frontend) make explorer filters controlled and split them out
Move the explorer filters into a dedicated filters/ folder, one file per
filter. Make the modification date filter controlled so it resets when the
active filters are cleared from outside, and share the date-range merge
logic between the topbar and the search modal.
2026-06-29 15:42:59 +02:00
Nicolas Clerc cc947d44f7 (frontend) test explorer filters
Cover the category, contact and modification date filters, and check
that an anonymous visitor on a public folder does not get the contact
filter, whose endpoints require authentication.
2026-06-29 15:42:58 +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 66692b3264 (frontend) filter items by shared contact
Add a "Shared with" filter to the topbar, listing frequent contacts
and searching people by name, wired to the contacts endpoint and the
backend contact filter.
2026-06-29 15:42:58 +02:00
Nicolas Clerc 650a29a5ed (frontend) add file type category filter
Replace the folder/file toggle in the topbar with a file type category
filter (text document, slides, spreadsheet, pdf, image, video, audio,
archive, other), wired to the backend category filter.
2026-06-29 15:42:58 +02:00
Nicolas Clerc b88bd752aa (backend) filter search results by location
Add a single location query parameter to the search endpoint, exposing
the My files, Shared with me, Starred and Trashbin views. Trashbin
overrides the scope filter as it implies a deleted scope.
2026-06-29 15:42:58 +02:00
Nicolas Clerc 21284be5d2 ♻️(backend) extract item location querysets
Centralize creator, favorite and owner filtering as ItemQuerySet
methods, so the list filters, the trashbin endpoint and the upcoming
search location filter share a single definition.
2026-06-29 15:42:58 +02:00
Nicolas Clerc c22e7b2f13 (backend) list a user's frequent contacts
Add a contacts endpoint on the user viewset returning the people who
share items with the current user, ranked by the number of shared
items. It mirrors the contact filter perimeter (direct and team
access, live items only) so every suggestion yields a result.
2026-06-29 15:42:58 +02:00
Nicolas Clerc 7acec3fb56 (backend) filter items list by modification date
Add an updated_at date range filter on the items list so results can
be narrowed to a modification period. Bounds match on the date part,
so a date-only bound covers the whole day rather than stopping at
midnight.
2026-06-29 15:42:57 +02:00
Nicolas Clerc 4b70839ce6 (backend) filter items list by shared contact
Add a contact filter on the items list returning the items in which
the given user is involved through a sharing access, in either
direction, so users can find files they share with a given person.
2026-06-29 15:42:36 +02:00
Nicolas Clerc 2d86437c0e (backend) add file type category filter
Add a `category` filter on the items list to narrow results by file
type (text document, slides, spreadsheet, pdf, image, video, audio,
archive, other). Categories are matched on the filename extension,
since several listed formats share ambiguous mime types.
2026-06-29 15:42:11 +02:00
Nicolas Clerc 7279d09a8e (backend) improve demo users for sharing fixtures
The sharing filter needs a realistic contact picker with user names.
Switching from anonymous emails to a fixed list of named users gives
the demo database the full_name and short_name fields required for
that UI.
2026-06-29 15:41:30 +02:00
Nicolas Clerc 0a0199fc21 (backend) add file type fixtures to create_demo
The --file-types flag creates one fixture per category (docx, xlsx,
pptx, pdf, image, video, zip, mp3, binary) so developers can populate
a local demo database covering all filter-relevant types, without
having to upload real files manually.
2026-06-29 15:32:36 +02:00
Nicolas Clerc f53d80dc98 📝(readme) improve clarity and consistency in README
Update README to enhance clarity and consistency throughout the document.
2026-06-24 09:07:11 +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 3587826e1e (backend) accept conversion requests during analysis
Let a conversion be queued while the source is still analyzed; the real
conversion stays gated on READY in perform_conversion.
2026-06-23 17:22:52 +02:00
Nicolas Clerc 1dbcf31039 (backend) expose convert ability during analysis
A file uploaded by a user must stay usable during malware analysis,
including conversion. Flag the convert ability while the source is being
analyzed so the frontend offers it.
2026-06-23 17:22:52 +02:00
Nicolas Clerc c7699d7324 🔧(backend) delay dummy malware analysis in dev
The inline dummy backend reported files safe before the upload response
returned, so the analyzing upload state was never observable. Delay the
safe result off the request thread to expose it for frontend testing.
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 630209ff53 ⬆️(backend) bump PyJWT and cryptography for security fixes
PyJWT 2.13.0 fixes CVE-2026-48526 (auth bypass via forged JWT).
cryptography 49.0.0 ships a patched OpenSSL (GHSA-537c-gmf6-5ccf).
2026-06-22 18:09:24 +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
Nicolas Clerc b5e8538744 🌐(frontend) update conversion modal content wording
Remove app name from the sentence to keep it generic.
2026-06-09 10:29:10 +02:00
Nicolas Clerc caa1dbc0e5 🐛(frontend) poll items in "analyzing" upload state
After upload, malware detection runs asynchronously. The frontend
was not polling the item so abilities like "convert" stayed stale
until page reload.
2026-06-08 17:15:47 +02:00
Nicolas Clerc 533606bbf0 🩹(backend) add suffix to converted filename
The converted file was missing '(converted)' suffix.
2026-06-08 16:17:02 +02:00
Nicolas Clerc 2d1636106b 🐛(docker) fix Collabora healthcheck without curl
Recent Collabora images no longer ship curl, breaking the
healthcheck. Use bash /dev/tcp as a fallback.

See CollaboraOnline/online#15919
2026-06-08 15:05:47 +02:00
Nicolas Clerc 350a4828f8 📝(backend) document OnlyOffice conversion environment variables
The conversion feature added in PR #719 introduced several settings
that were missing from the environment reference.
2026-06-08 11:59:32 +02:00
Nicolas Clerc 212f4f1b19 🐛(backend) reject conversion when JWT secret is not configured
Without the secret the request reaches OnlyOffice unsigned and fails
with a cryptic error code -8. Validate in the synchronous path before
creating the placeholder so the API returns an error immediately, and
hide the convert ability from the API so the frontend does not offer
the action.

The backend now reads the secret directly from settings, like it
already does for timeouts.
2026-06-08 11:59:32 +02:00
Nicolas Clerc c67cb28d65 🐛(backend) prefer WOPI query param over Authorization header
When OnlyOffice has JWT enabled it adds its own Authorization header to
outgoing file-download requests. The WOPI access token in the query
param must take precedence so the opaque token lookup succeeds.
2026-06-08 11:59:32 +02:00
Nicolas Clerc 5149283688 (backend) sign OnlyOffice conversion requests with JWT
The OnlyOffice server rejects unsigned /converter requests with error
code -8 when JWT is enabled.

Add a dedicated WOPI_ONLYOFFICE_CONVERT_JWT_SECRET setting and fix the
JWT body token format to match the OnlyOffice conversion API: encode
parameters directly instead of wrapping them in {"payload": …}, and
send only {"token": "…"} in the request body.

Enable JWT on the development OnlyOffice container so the issue is
caught locally.
2026-06-08 11:59:32 +02:00
Nicolas Clerc 3e89881cca 🔥(backend) remove unused OnlyOffice conversion JWT options
ConvertJwtSecret, ConvertJwtRequired and the jwt_required constructor
guard were never configured in any environment.
2026-06-08 11:59:32 +02:00
Nicolas Clerc cbec3ba077 🌐(frontend) reuse download label for folder export action
As we want to use the same label for file download and folder export,
the same key is used, and the unused one is removed.
2026-06-08 10:48: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 7ac7dd5ef5 🐛(frontend) add missing export action translations
The folder export button added in cd7bebfc used
the translation key explorer.item.actions.export
without adding the corresponding entries.
2026-06-03 18:23:07 +02:00
Nicolas Clerc 302bff1605 (e2e) cover conversion explorer flow
The conversion flow crosses modal state, API calls, and explorer refreshes.

Cover the expected user path with a mocked conversion ability and placeholder
response.
2026-06-03 16:47:38 +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 aeb6c9b5c7 (frontend) render converting items as transient rows
A converting file is visible but not ready for normal file actions.

Show the transient state consistently and prevent opening or acting on the item
until conversion completes.
2026-06-03 16:47:38 +02:00
Nicolas Clerc af6ab74e42 (frontend) add conversion modal
Users should understand that opening a legacy file creates an editable copy.

Keep the modal focused on confirmation and let the folder show the ongoing
conversion state.
2026-06-03 16:47:38 +02:00
Nicolas Clerc 462c3e5e7a (frontend) wire conversion API client
The frontend needs to treat conversion as item creation rather than job polling.

Return the placeholder item from the driver so UI state stays aligned with the
explorer list.
2026-06-03 09:28:56 +02:00
Nicolas Clerc 6a07e183ce 🐛(backend) normalize WOPI extension lookup
Uploaded filenames preserve extension case, while WOPI discovery stores
extension keys in lowercase.

Normalize the lookup so legacy files like REPORT.DOC follow the same conversion
path.
2026-06-03 09:28:56 +02:00
Nicolas Clerc 10f5724951 (backend) queue legacy file conversion
Starting a conversion should be quick for the API caller and continue in the
background.

Queue the placeholder-backed conversion task from the item endpoint.
2026-06-03 09:28:56 +02:00
Nicolas Clerc acfd09be8f (backend) expose legacy conversion ability
The explorer needs to know when opening a legacy Office file should start
conversion instead of WOPI editing.

Expose the decision on item abilities so the frontend can keep the flow item-
based.
2026-06-02 15:23:42 +02:00
Nicolas Clerc 20596fa98a (backend) add placeholder-backed conversion service
Users need immediate feedback in the current folder while conversion continues
in the background.

Create the target item up front and complete it once converted bytes are
available.
2026-06-02 15:23:42 +02:00
Nicolas Clerc a67efc234b (backend) add converting upload state
Converted files should appear in the folder immediately while Celery is still
working.

Add a dedicated transient state instead of overloading upload or duplication
states.
2026-06-02 15:23:42 +02:00
Nicolas Clerc a997fa826f (backend) build short-lived WOPI source URLs
OnlyOffice must fetch the source bytes from Drive during server-side conversion.

Use short-lived WOPI access URLs so conversion does not depend on direct object
storage reachability.
2026-06-02 15:23:42 +02:00
Nicolas Clerc b4fc5ec2a3 (backend) add legacy conversion policy helpers
Legacy Office formats need an explicit conversion policy before they can be
opened for editing.

Keep the mapping small and configuration-driven so the backend only converts
formats intentionally forced by the WOPI client.
2026-06-02 15:23:42 +02:00
Nicolas Clerc 88e2693704 (backend) add OnlyOffice conversion backend
Drive needs a server-side path to convert legacy Office files without opening an
interactive editor session.

Use OnlyOffice's conversion API as the first supported provider for the POC.
2026-06-02 15:23:42 +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 7b12fdb92a (backend) add zipstream-ng dependency
Used to stream a zip archive of a folder's content over HTTP without
buffering the whole archive in memory.
2026-05-28 10:42:53 +02:00
Nicolas Clerc c610e1bb28 (backend) add export ability on folders
Introduce a new "export" entry in Item.get_abilities, true only for
folders the user can read. Will be the gate for the upcoming recursive
folder export endpoint.
2026-05-28 10:42:53 +02:00
Nicolas Clerc afc78fb77f 🧑‍💻(backend) add reconciliation demo command
Seed two accounts and a CSV to exercise the reconciliation flow end to end
through the admin and the frontend.
2026-05-27 17:36:47 +02:00
Nicolas Clerc 6f926c61b4 (frontend) add user reconciliation confirmation pages
Let users confirm by email that they control both accounts, closing the
reconciliation flow on the frontend.
2026-05-27 17:36:47 +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 ff184e1336 (backend) add reconciliation email confirmation endpoint
Let users confirm by email that they control both accounts before the
merge is allowed to run.
2026-05-27 17:36:47 +02:00
Nicolas Clerc e2538680de (backend) add user reconciliation admin
Give admins a UI to import reconciliation CSVs and trigger the actual
merge once both addresses are confirmed.
2026-05-27 17:36:47 +02:00
Nicolas Clerc 0ce6c56bd4 (backend) add user reconciliation csv import task
Let an admin bulk-create reconciliation requests from an external CSV
export instead of entering each pair by hand.
2026-05-27 17:36:47 +02:00
Nicolas Clerc df47d3ccf9 (backend) add user reconciliation models
Merge an inactive account's content into the active one once both email
addresses are confirmed, so users keep a single account.
2026-05-27 17:36:47 +02:00
Nicolas Clerc fcf459d536 (backend) add generic send_email method on user model
The user reconciliation flow needs to send templated emails to users.
2026-05-27 08:02:08 +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