Show staff where a file stands, and say the same through the API

Staff keep seeing every file they always saw — withholding is about
recipients, not about the library — so the library now carries the state
on the row: Checking, Quarantined, Released, or Not scanned with the
reason behind it. Nothing at all for a clean file, which is the common
case.

The API says the same in a `scan` object on every file, with an
`available` flag so a caller need not learn which of six states mean
"you can have it", and `scan_status` is a filter, so an integration can
wait for the file it just uploaded or collect what is in quarantine.
The download endpoint answers 423 for a file that is not available,
which it already did through the shared controller.

Re-exported the OpenAPI document.
This commit is contained in:
ignacionelson
2026-09-16 14:45:13 -03:00
parent 0ae3f3d0f0
commit 5493955bea
7 changed files with 194 additions and 0 deletions
+58
View File
@@ -1789,6 +1789,20 @@
"null"
]
}
},
{
"name": "scan_status",
"in": "query",
"schema": {
"anyOf": [
{
"$ref": "#/components/schemas/ScanStatus"
},
{
"type": "null"
}
]
}
}
],
"responses": {
@@ -3983,6 +3997,36 @@
"expired": {
"type": "boolean"
},
"scan": {
"type": "object",
"description": "What the virus scanner made of this file. `pending` and\n`infected` mean the bytes are not available: the download\nendpoint answers 423 for both, and a caller that has just\nuploaded should poll this rather than the download. `note`\ncarries the threat name, or why a file was not scanned.",
"properties": {
"status": {
"type": "string"
},
"available": {
"type": "boolean"
},
"note": {
"type": [
"string",
"null"
]
},
"scanned_at": {
"type": [
"string",
"null"
]
}
},
"required": [
"status",
"available",
"note",
"scanned_at"
]
},
"download_limit": {
"type": [
"integer",
@@ -4166,6 +4210,7 @@
"commentable",
"expires_at",
"expired",
"scan",
"download_limit",
"download_limit_scope",
"downloads_used",
@@ -4247,6 +4292,19 @@
],
"title": "GroupResource"
},
"ScanStatus": {
"type": "string",
"description": "Where a file stands with the virus scanner. Availability is not a case here on purpose: three of these mean the file may be served and three mean it may not, and asking FileAvailability rather than comparing cases is what keeps that rule in one place. See docs/feature-virus-scanning.md.\n| |\n|---|\n| `pending` <br/> Waiting to be scanned, or being scanned right now. |\n| `clean` <br/> Scanned, nothing found. |\n| `infected` <br/> A threat was found. Quarantined; `scan_note` is the threat name. |\n| `released` <br/> Was infected, and an administrator decided to allow it anyway. |\n| `not_scanned` <br/> Not checked, and allowed through. `scan_note` is a NotScannedReason. |\n| `unscannable_blocked` <br/> Could not be checked, and this installation blocks those. Quarantined. |",
"enum": [
"pending",
"clean",
"infected",
"released",
"not_scanned",
"unscannable_blocked"
],
"title": "ScanStatus"
},
"StaffUserResource": {
"type": "object",
"properties": {