Repository navigation
Add the media library screen - #2601
Merged
Merged
Conversation
This was referenced Oct 19, 2026
Closed
pournasserian
added a commit
that referenced
this pull request
Oct 19, 2026
… the library (#2651) Closes #2629 ## What Follow-ups from the independent review of #2601 (F-MED, #2427). - **Base version.** The asset page's hidden `BaseVersion` comes from the form being shown. A form refused for its own problems keeps the version it started from, so its next save is refused as a conflict instead of overwriting a change saved meanwhile. - **Refused uploads no longer filter the library.** - The return query uses `upload-error`, `upload-folder`, `upload-tags`, `upload-alt` and `upload-caption`, which no list filter reads. - A field whose escaped text is over 1500 characters isn't carried back. `upload-dropped` names it, and the form says to type it again, so the redirect stays well inside the server's request line limit. - Empty fields are left out of the return query. - **`sub` and `uploaded` are read as text.** `sub` takes `1` or `true`. A value that isn't a flag counts as false instead of failing the page with a 500. `uploaded` has the same bug as `sub`, so it is fixed here too. - **Where-used rows link to the item's audit history.** An entity type's items link as `entity` and other items as `entry`, as the log names them. - **An upload that declares a body over the limit** gets the library's "too large" message instead of a reset connection. - `UseMediaUploadLimit` runs before the anti-forgery check. It reads and discards the declared body, then redirects back to the library. - It applies to a signed-in person, with a body up to 1 GB. - A chunked body that declares no length still meets the server's limit. ## Why - **Discard the body, then answer.** A browser still sending its upload treats an early answer as a failed request. Kestrel aborts a drain over the endpoint's limit, so the limit is lifted for that request only. - **Upload names of its own.** The upload form and the list share the page, so names the list doesn't read can never filter it. ## Tests - The media screen tests run on SQLite and PostgreSQL. - An anonymous upload goes to sign-in. - The #2629 overwrite scenario ends in the conflict message, and the other person's change stays. - After a refused upload, the library lists every asset. - A refused SVG upload says its type can't be uploaded. - A PDF downloads as an attachment, with its file name. - `sub=1` lists subfolders, and `sub=yes` doesn't. - `uploaded=abc` shows the page without the upload note. - An upload declared over the limit comes back with the too-large message and stores nothing. - Where-used rows link to an entry's history, and to an entity's history as `entity`, in bUnit. - bUnit: - The upload's fields never filter the list. - A dropped field is named. - The `sub` flag takes 1 and true. - The return query drops a text too long to carry. `SignedInPageTests` gives each page load a 30-second deadline that names the page. That test hung once on PostgreSQL in CI on v2, and passed on re-run, so the next failure says which page it was. `dotnet build -warnaserror`, the unit and bUnit suite and the media tests on SQLite and PostgreSQL pass locally. No new package and no new project reference. ## Checklist - [x] Linked to an issue a maintainer has confirmed - [x] Targets `v2` - [x] Tests or docs updated where behaviour changed - [x] No tool-generated co-author trailers or footers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2595
What
The media library screen of F-MED (#2427), MED-01's UI: upload, browse, organize and where used. It runs on the merged
IMediaLibrary(#2543) andIWhereUsed.ForMediaAsync(#2494), and uses the desk's layout and conventions (#2422).Media/MediaEndpoints.cs, next to the audit export endpoint):POST /media/uploadtakes a multipart form with the anti-forgery token. It callsUploadAsyncand redirects to the new asset with?uploaded=true./mediawith the error codes and the typed fields, as the audit export does.Media__MaxBytesplus 1 MB for the form, so the library's own limit decides first.GET /media/{id}/file?version=nstreams the bytes to a signed-in person. Images are inline for the previews, and every other type is an attachment. Each response hasX-Content-Type-Options: nosniffandCache-Control: private, no-store. The library already refuses types a browser runs as a document (MediaTypes).MediaUploadForm,MediaMetadataFormand their sharedMediaMetadataFields. Tags are typed comma-separated, and a blank alt text or caption means none./media:/media/{id}:/mediaand an asset page in both directions and themes.Why
UploadAsyncand the page'sUpdateAsyncpass the person's change set target, like the other writes.IMediaLibrary.ListAsyncreturns every match. The table is fine at M1's scale, and paging belongs in the library's query once one is needed.Tests
bUnit (
MediaViewsTests):Integration, host:
nosniff, and an unknown asset's file is 404.Browser: the axe check passes on
/mediaand an asset page.dotnet build -warnaserrorand the full suite with the browser tests pass locally against apostgres:17container as well as SQLite. No new package and no new project reference.Checklist
v2