Skip to content

Feature/gallery upload routing rsdev 1192#56

Merged
tilorspace merged 4 commits into
masterfrom
feature/gallery-upload-routing-RSDEV-1192
Jul 16, 2026
Merged

Feature/gallery upload routing rsdev 1192#56
tilorspace merged 4 commits into
masterfrom
feature/gallery-upload-routing-RSDEV-1192

Conversation

@tilorspace

@tilorspace tilorspace commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Makes the RSpace Gallery a friendlier upload target for GalleryFilesystem
(PyFilesystem) by handling the Gallery's media-type section rule instead of
failing opaquely. Three separable changes plus a Galaxy-compatibility fix.

Jira: RSDEV-1192

Background

The Gallery is split into media-type sections: Images, Audios, Videos,
Documents, Chemistry, and Miscellaneous. Each specialised section accepts
only its own file types (Documents is a fixed set: doc, docx, rtf, pdf, odt,
ods, odp, txt, ppt, pptx, xls, xlsx, csv, pps, md); Miscellaneous is the
catch-all for anything else. The server (FolderManagerImpl.getApiUploadTargetFolder)
classifies a file from its name and, for a folder-targeted gallery upload,
requires the folder to be the matching section folder or a subfolder of it,
otherwise it rejects the upload.

Previously GalleryFilesystem.upload() passed the folder straight through, so a
section mismatch surfaced as an opaque ApiError and the file was lost.

What changed (four commits, reviewable in order)

  1. Clearer error (8bb9e2a) — when a folder-targeted upload is rejected,
    re-raise a GallerySectionMismatch naming the folder's section (and the
    file's guessed media type), with the original API error preserved. Detection
    is reactive: it only enriches after a real server rejection, so the
    best-effort filename classifier can never block a valid upload.

  2. Opt-in auto-reroute (7e8e07e) — add an on_mismatch policy: "raise"
    (default) or "reroute". On reroute, the file is re-uploaded with no
    folderId so the server places it in the correct section's inbox. The policy
    is set filesystem-wide in the constructor (so it also applies to generic
    PyFilesystem operations that call upload/openbin) and can be overridden
    per upload() call. upload() now returns a Placement describing where the
    file landed (global id, section, human-readable path, rerouted flag).

  3. Galaxy-compatibility fix (6cb1f60) — Galaxy's RSpace file source
    monkeypatches eln_client.upload_file with a wrapper that returns None,
    then calls our upload() via super(). Commit 2 began consuming that return
    value to build the Placement, which crashed on None. _placement now
    tolerates a non-dict/None response and the folder-lookup helpers never
    raise, so a successful upload can never fail during Placement construction.

  4. Correct classifier (0b086a5) — the error-message classifier wrongly
    treated Documents as the catch-all and used invented audio/video/chemistry
    extensions. Rebuilt the extension→section table from the Gallery docs and
    rspace-web (MediaUtils), defaulting unlisted types to Miscellaneous.
    Placement is unaffected (reroute stays server-authoritative); this only
    improves the wording of the raised error.

API / behaviour

# filesystem-wide default (applies to all writes, incl. generic fs ops)
fs = GalleryFilesystem(url, api_key, on_mismatch="reroute")

# or per call
placement = fs.upload("/GF123", file_obj, on_mismatch="reroute")
placement.rerouted   # True if it did not land in the requested folder
placement.section    # e.g. "Documents" or "Miscellaneous"
placement.path       # e.g. "Gallery/Documents/Api Inbox"

Default policy is "raise", so existing behaviour is preserved apart from the
clearer exception type (a subclass of the previous ApiError).

Backwards compatibility

  • Constructor and upload() signatures remain call-compatible (new params are
    keyword/defaulted).
  • GallerySectionMismatch subclasses ApiError, so existing except ApiError
    handlers still catch it.
  • Verified against Galaxy's file source (lib/galaxy/files/sources/rspace.py,
    PR #20167 on dev): the reroute is inert for Galaxy (default policy) and the
    fix in commit 3 keeps its export path working. Recommend re-confirming against
    the specific Galaxy release branch deployed.

Testing

rspace_client/tests/eln_fs_test.py — 19 unit tests pass, covering both
policies (constructor + per-call), the media classifier (including the
Miscellaneous catch-all), policy validation, the no-folder passthrough,
success/mismatch/reroute placements, and a regression reproducing Galaxy's
upload_file-returns-None monkeypatch.

Docs

docs/usage-guide.md documents the section rule, on_mismatch, and Placement.

Follow-ups (not in this PR)

  • Galaxy could drop its upload_file monkeypatch and read Placement.file_global_id
    directly, now that upload() returns it.

tilorspace and others added 3 commits July 13, 2026 18:32
When a file is uploaded to a Gallery folder in the wrong media-type section,
the RSpace API rejects it and the client raised an opaque ApiError. Re-raise
as GallerySectionMismatch naming the folder's section (and the file's guessed
media type) with the original error preserved.

Detection is reactive: the enriched error is only produced after a real
server rejection of a folder-targeted upload, so the best-effort filename
classifier can never block an otherwise-valid upload.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add an on_mismatch policy to GalleryFilesystem: "raise" (default, the clear
error from the previous change) or "reroute", which on a section mismatch
re-uploads with no folderId so the server places the file in the correct
section's inbox. The policy is set filesystem-wide in the constructor (so it
also applies to generic PyFilesystem operations that call upload/openbin) and
can be overridden per upload() call.

upload() now returns a Placement describing where the file landed (global id,
section, human-readable path, and whether it was rerouted). Reroutes are logged
at INFO. Document the behaviour in the usage guide.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…EV-1192)

Galaxy's RSpace file source monkeypatches eln_client.upload_file with a wrapper
that captures the response and returns None, then calls GalleryFilesystem.upload
via super(). Change 2 started consuming upload_file's return value to build a
Placement, which crashed on that None with AttributeError, breaking every
Galaxy->RSpace export.

Make _placement tolerate a non-dict/None response and make the best-effort
folder-lookup helpers never raise, so a successful upload can never fail during
Placement construction. Direct callers still receive a full Placement.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@anuprulez

Copy link
Copy Markdown

The changes look ok to me. Thanks a lot @tilorspace

@tilorspace
tilorspace marked this pull request as ready for review July 15, 2026 15:53
@tilorspace
tilorspace requested a review from nebay-abraha July 15, 2026 15:53
The error-message classifier wrongly treated "Documents" as the catch-all and
used invented audio/video/chemistry extensions. Per the Gallery docs and
rspace-web (FolderManagerImpl.getApiUploadTargetFolder / MediaUtils), the
catch-all is "Miscellaneous"; "Documents" is a fixed extension set. Rebuild the
extension->section table from the documented lists, default unlisted types to
Miscellaneous, and phrase the mismatch message accordingly.

Placement is unaffected: reroute stays server-authoritative (upload with no
folderId), so this only improves the wording of the raised error.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@tilorspace

Copy link
Copy Markdown
Contributor Author

Missed one category; should be fully covered now with the latest commit.

@nebay-abraha nebay-abraha left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good.👍

@tilorspace
tilorspace merged commit 3eb30ac into master Jul 16, 2026
7 checks passed
@tilorspace
tilorspace deleted the feature/gallery-upload-routing-RSDEV-1192 branch July 16, 2026 12:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants