Add last modified tracking: show 'Last modified: date by username' in document viewer
- Added modified_by column to files table - Updated WOPI PutFile to track who modified the file - Updated view handlers to return file metadata (name, size, lastModified, modifiedByName) - Updated Flutter models and UI to display last modified info
This commit is contained in:
@@ -126,15 +126,17 @@ type Activity struct {
|
||||
}
|
||||
|
||||
type File struct {
|
||||
ID uuid.UUID
|
||||
OrgID *uuid.UUID
|
||||
UserID *uuid.UUID
|
||||
Name string
|
||||
Path string
|
||||
Type string
|
||||
Size int64
|
||||
LastModified time.Time
|
||||
CreatedAt time.Time
|
||||
ID uuid.UUID
|
||||
OrgID *uuid.UUID
|
||||
UserID *uuid.UUID
|
||||
Name string
|
||||
Path string
|
||||
Type string
|
||||
Size int64
|
||||
LastModified time.Time
|
||||
CreatedAt time.Time
|
||||
ModifiedBy *uuid.UUID
|
||||
ModifiedByName string
|
||||
}
|
||||
|
||||
func (db *DB) GetOrCreateUser(ctx context.Context, sub, email, name string) (*User, error) {
|
||||
@@ -465,12 +467,17 @@ func (db *DB) GetFileByID(ctx context.Context, fileID uuid.UUID) (*File, error)
|
||||
var f File
|
||||
var orgNull sql.NullString
|
||||
var userNull sql.NullString
|
||||
var modifiedByNull sql.NullString
|
||||
var modifiedByNameNull sql.NullString
|
||||
|
||||
err := db.QueryRowContext(ctx, `
|
||||
SELECT id, org_id::text, user_id::text, name, path, type, size, last_modified, created_at
|
||||
FROM files
|
||||
WHERE id = $1
|
||||
`, fileID).Scan(&f.ID, &orgNull, &userNull, &f.Name, &f.Path, &f.Type, &f.Size, &f.LastModified, &f.CreatedAt)
|
||||
SELECT f.id, f.org_id::text, f.user_id::text, f.name, f.path, f.type, f.size, f.last_modified, f.created_at,
|
||||
f.modified_by::text, u.display_name
|
||||
FROM files f
|
||||
LEFT JOIN users u ON f.modified_by = u.id
|
||||
WHERE f.id = $1
|
||||
`, fileID).Scan(&f.ID, &orgNull, &userNull, &f.Name, &f.Path, &f.Type, &f.Size, &f.LastModified, &f.CreatedAt,
|
||||
&modifiedByNull, &modifiedByNameNull)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -484,17 +491,24 @@ func (db *DB) GetFileByID(ctx context.Context, fileID uuid.UUID) (*File, error)
|
||||
uid, _ := uuid.Parse(userNull.String)
|
||||
f.UserID = &uid
|
||||
}
|
||||
if modifiedByNull.Valid {
|
||||
mid, _ := uuid.Parse(modifiedByNull.String)
|
||||
f.ModifiedBy = &mid
|
||||
}
|
||||
if modifiedByNameNull.Valid {
|
||||
f.ModifiedByName = modifiedByNameNull.String
|
||||
}
|
||||
|
||||
return &f, nil
|
||||
}
|
||||
|
||||
// UpdateFileSize updates the size and modification time of a file
|
||||
func (db *DB) UpdateFileSize(ctx context.Context, fileID uuid.UUID, size int64) error {
|
||||
// UpdateFileSize updates the size, modification time, and modifier of a file
|
||||
func (db *DB) UpdateFileSize(ctx context.Context, fileID uuid.UUID, size int64, modifiedBy *uuid.UUID) error {
|
||||
_, err := db.ExecContext(ctx, `
|
||||
UPDATE files
|
||||
SET size = $1, last_modified = NOW()
|
||||
SET size = $1, last_modified = NOW(), modified_by = $3
|
||||
WHERE id = $2
|
||||
`, size, fileID)
|
||||
`, size, fileID, modifiedBy)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -520,6 +520,12 @@ func viewerHandler(w http.ResponseWriter, r *http.Request, db *database.DB, jwtM
|
||||
IsPdf bool `json:"isPdf"`
|
||||
MimeType string `json:"mimeType"`
|
||||
} `json:"capabilities"`
|
||||
FileInfo struct {
|
||||
Name string `json:"name"`
|
||||
Size int64 `json:"size"`
|
||||
LastModified string `json:"lastModified"`
|
||||
ModifiedByName string `json:"modifiedByName"`
|
||||
} `json:"fileInfo"`
|
||||
ExpiresAt string `json:"expiresAt"`
|
||||
}{
|
||||
ViewUrl: downloadPath,
|
||||
@@ -530,6 +536,17 @@ func viewerHandler(w http.ResponseWriter, r *http.Request, db *database.DB, jwtM
|
||||
IsPdf bool `json:"isPdf"`
|
||||
MimeType string `json:"mimeType"`
|
||||
}{CanEdit: false, CanAnnotate: isPdf, IsPdf: isPdf, MimeType: mimeType},
|
||||
FileInfo: struct {
|
||||
Name string `json:"name"`
|
||||
Size int64 `json:"size"`
|
||||
LastModified string `json:"lastModified"`
|
||||
ModifiedByName string `json:"modifiedByName"`
|
||||
}{
|
||||
Name: file.Name,
|
||||
Size: file.Size,
|
||||
LastModified: file.LastModified.UTC().Format(time.RFC3339),
|
||||
ModifiedByName: file.ModifiedByName,
|
||||
},
|
||||
ExpiresAt: time.Now().Add(24 * time.Hour).UTC().Format(time.RFC3339),
|
||||
}
|
||||
|
||||
@@ -606,6 +623,12 @@ func userViewerHandler(w http.ResponseWriter, r *http.Request, db *database.DB,
|
||||
IsPdf bool `json:"isPdf"`
|
||||
MimeType string `json:"mimeType"`
|
||||
} `json:"capabilities"`
|
||||
FileInfo struct {
|
||||
Name string `json:"name"`
|
||||
Size int64 `json:"size"`
|
||||
LastModified string `json:"lastModified"`
|
||||
ModifiedByName string `json:"modifiedByName"`
|
||||
} `json:"fileInfo"`
|
||||
ExpiresAt string `json:"expiresAt"`
|
||||
}{
|
||||
ViewUrl: downloadPath,
|
||||
@@ -621,6 +644,17 @@ func userViewerHandler(w http.ResponseWriter, r *http.Request, db *database.DB,
|
||||
IsPdf: isPdf,
|
||||
MimeType: mimeType,
|
||||
},
|
||||
FileInfo: struct {
|
||||
Name string `json:"name"`
|
||||
Size int64 `json:"size"`
|
||||
LastModified string `json:"lastModified"`
|
||||
ModifiedByName string `json:"modifiedByName"`
|
||||
}{
|
||||
Name: file.Name,
|
||||
Size: file.Size,
|
||||
LastModified: file.LastModified.UTC().Format(time.RFC3339),
|
||||
ModifiedByName: file.ModifiedByName,
|
||||
},
|
||||
ExpiresAt: time.Now().Add(24 * time.Hour).UTC().Format(time.RFC3339),
|
||||
}
|
||||
|
||||
|
||||
@@ -512,7 +512,7 @@ func wopiPutFileHandler(w http.ResponseWriter, r *http.Request, db *database.DB,
|
||||
|
||||
// Update file size and modification time in database
|
||||
newSize := int64(len(content))
|
||||
err = db.UpdateFileSize(r.Context(), fileUUID, newSize)
|
||||
err = db.UpdateFileSize(r.Context(), fileUUID, newSize, &userID)
|
||||
if err != nil {
|
||||
fmt.Printf("[WOPI-STORAGE] Failed to update file size: file=%s error=%v\n", fileID, err)
|
||||
// Don't fail the upload, just log the warning
|
||||
|
||||
Reference in New Issue
Block a user