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
+19
View File
@@ -300,6 +300,25 @@ func (h *FileHandler) GetMeta(c *gin.Context) {
respondJSON(c, http.StatusOK, toFileJSON(*f))
}
// ---------------------------------------------------------------------------
// POST /files/:id/views
// ---------------------------------------------------------------------------
// RecordView logs that the current user viewed the file (activity.file_views).
func (h *FileHandler) RecordView(c *gin.Context) {
id, ok := parseFileID(c)
if !ok {
return
}
if err := h.fileSvc.RecordView(c.Request.Context(), id); err != nil {
respondError(c, err)
return
}
c.Status(http.StatusNoContent)
}
// ---------------------------------------------------------------------------
// PATCH /files/:id
// ---------------------------------------------------------------------------
+1
View File
@@ -84,6 +84,7 @@ func NewRouter(
files.PUT("/:id/content", fileHandler.ReplaceContent)
files.GET("/:id/thumbnail", fileHandler.GetThumbnail)
files.GET("/:id/preview", fileHandler.GetPreview)
files.POST("/:id/views", fileHandler.RecordView)
files.POST("/:id/restore", fileHandler.Restore)
files.DELETE("/:id/permanent", fileHandler.PermanentDelete)