Give an API expiry date the same meaning the web gives it

FilesController::expiryInstant exists because a calendar day ends where
the person naming it lives: the web form posts a bare YYYY-MM-DD, and
storing that as it arrives would cut a file off at midnight UTC -- "expires
on the 12th" ending partway through the 11th for anyone in the Americas.

The API takes the same field, validates it as a date, and stores it raw:

  web  → 2026-09-12T23:59:59+00:00   (end of the day, as the docblock means)
  API  → 2026-09-12T00:00:00+00:00   (raw)

Same value, same field, same file, two meanings -- and the earlier of the
two is a file that dies at the start of the day it was promised.

A bare date now means the end of that day in the caller's timezone, as it
does on the web. A value carrying a time is unchanged: it is an instant
the caller named on purpose, the API can express one and a date input
cannot. The endpoint's docblock says both, so the OpenAPI document does
too.

Three tests: the day, the timestamp, and clearing. Without the fix the
first goes red.
This commit is contained in:
denkfabrik-li
2026-08-28 02:56:53 +02:00
parent 06c364d29a
commit e1cd010f9d
3 changed files with 78 additions and 2 deletions
+1 -1
View File
@@ -2076,7 +2076,7 @@
},
"patch": {
"operationId": "files.update",
"description": "Only the fields present in the request are changed; omitting one\nleaves it as it was.\n\nSome fields need a permission of their own \u2014 `expires_at` needs\n`set_file_expiration_date`, `public` needs `upload_public`, and\n`categories` needs `set_file_categories`. Sending one of those\nwithout the matching permission leaves that field untouched rather\nthan failing the whole request, which mirrors the web interface.\n\n`commentable` only has an effect while the installation's comment\nsetting is \"only files marked as commentable\"; under any other\nsetting it is ignored, again rather than failing.\n\nRequires a token with any of these abilities: `edit_files`, `edit_others_files`.",
"description": "Only the fields present in the request are changed; omitting one\nleaves it as it was.\n\nSome fields need a permission of their own \u2014 `expires_at` needs\n`set_file_expiration_date`, `public` needs `upload_public`, and\n`categories` needs `set_file_categories`. Sending one of those\nwithout the matching permission leaves that field untouched rather\nthan failing the whole request, which mirrors the web interface.\n\n`expires_at` accepts either a calendar day (`2026-09-12`) or a full\ntimestamp. A day means the end of that day in the caller's timezone,\nwhich is what the same value means on the web and what the file's\nown `expires_at` reads back as; a timestamp is taken as the instant\nit names.\n\n`commentable` only has an effect while the installation's comment\nsetting is \"only files marked as commentable\"; under any other\nsetting it is ignored, again rather than failing.\n\nRequires a token with any of these abilities: `edit_files`, `edit_others_files`.",
"summary": "Update a file's metadata",
"tags": [
"Files"