feat(backend): log file views
deploy / deploy (push) Successful in 1m0s

The activity.file_views table existed but nothing ever wrote to it. Add a
POST /files/{id}/views endpoint: FileRepo.RecordView inserts a history row,
FileService.RecordView enforces view ACL first. The file viewer fires it
(fire-and-forget) when a file is opened, including while paging prev/next.

Documented in openapi.yaml; covered by TestRecordFileView (204 on view,
repeatable, 404 for unknown file).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-11 14:49:14 +03:00
parent 8f213e780c
commit a78fc5ba9a
8 changed files with 93 additions and 0 deletions
@@ -690,6 +690,31 @@ func TestTagAutoRule(t *testing.T) {
assert.ElementsMatch(t, []string{"outdoor", "nature"}, names)
}
// TestRecordFileView verifies that viewing a file is logged (POST .../views),
// is repeatable (view history, not a unique flag), and 404s for unknown files.
func TestRecordFileView(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
h := setupSuite(t)
adminToken := h.login("admin", "admin")
file := h.uploadJPEG(adminToken, "seen.jpg")
fileID := file["id"].(string)
resp := h.doJSON("POST", "/files/"+fileID+"/views", nil, adminToken)
require.Equal(t, http.StatusNoContent, resp.StatusCode, resp.String())
// Viewing again logs another history row, not a conflict.
resp = h.doJSON("POST", "/files/"+fileID+"/views", nil, adminToken)
require.Equal(t, http.StatusNoContent, resp.StatusCode, resp.String())
// Unknown file id → 404.
resp = h.doJSON("POST", "/files/00000000-0000-0000-0000-000000000000/views", nil, adminToken)
require.Equal(t, http.StatusNotFound, resp.StatusCode, resp.String())
}
// ---------------------------------------------------------------------------
// Security regression tests
// ---------------------------------------------------------------------------