Add reinstate feature for deleted files
- Add MarkNotDeleted method to repository - Add ReinstateFile method to service - Add AdminReinstate handler - Add /reinstate/:id route - Add Reinstate button in admin menu for deleted files
This commit is contained in:
@@ -213,6 +213,23 @@ func (h *Handler) AdminForceDelete(c *gin.Context) {
|
|||||||
c.Redirect(301, "/admin")
|
c.Redirect(301, "/admin")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Handler) AdminReinstate(c *gin.Context) {
|
||||||
|
id := c.Param("id")
|
||||||
|
|
||||||
|
_, err := h.service.GetFileByID(id)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusNotFound, gin.H{"error": "file not found"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := h.service.ReinstateFile(id); err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Redirect(301, "/admin")
|
||||||
|
}
|
||||||
|
|
||||||
func (h *Handler) Import(c *gin.Context) {
|
func (h *Handler) Import(c *gin.Context) {
|
||||||
var records []ImportFileRecord
|
var records []ImportFileRecord
|
||||||
|
|
||||||
|
|||||||
@@ -95,6 +95,12 @@ func (r *Repository) MarkDeleted(f *FileRecord) error {
|
|||||||
return r.db.Save(f).Error
|
return r.db.Save(f).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkNotDeleted Restore a deleted record by setting Deleted to false
|
||||||
|
func (r *Repository) MarkNotDeleted(f *FileRecord) error {
|
||||||
|
f.Deleted = false
|
||||||
|
return r.db.Save(f).Error
|
||||||
|
}
|
||||||
|
|
||||||
// Delete Permanently delete the record from the database
|
// Delete Permanently delete the record from the database
|
||||||
func (r *Repository) Delete(f *FileRecord) error {
|
func (r *Repository) Delete(f *FileRecord) error {
|
||||||
return r.db.Delete(f).Error
|
return r.db.Delete(f).Error
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ func RegisterRoutes(r *gin.RouterGroup, h *Handler) {
|
|||||||
|
|
||||||
adminRoutes.GET("/delete/:id", h.AdminDelete)
|
adminRoutes.GET("/delete/:id", h.AdminDelete)
|
||||||
adminRoutes.GET("/delete/fr/:id", h.AdminForceDelete)
|
adminRoutes.GET("/delete/fr/:id", h.AdminForceDelete)
|
||||||
|
adminRoutes.GET("/reinstate/:id", h.AdminReinstate)
|
||||||
|
|
||||||
adminRoutes.POST("/import", h.Import)
|
adminRoutes.POST("/import", h.Import)
|
||||||
adminRoutes.GET("/export", h.Export)
|
adminRoutes.GET("/export", h.Export)
|
||||||
|
|||||||
@@ -134,6 +134,29 @@ func (s *Service) ForceDelete(id string) (*FileRecord, error) {
|
|||||||
return f, nil
|
return f, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) ReinstateFile(id string) (*FileRecord, error) {
|
||||||
|
f, err := s.repo.GetByID(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !f.Deleted {
|
||||||
|
return nil, ErrFileNotFound // or just return f, nil maybe?
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if file actually exists on disk
|
||||||
|
path := s.storageDir + "/" + f.ID
|
||||||
|
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||||
|
return nil, ErrFileNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.repo.MarkNotDeleted(f); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) GetPaginatedFiles(limit, offset int) ([]FileRecord, int, error) {
|
func (s *Service) GetPaginatedFiles(limit, offset int) ([]FileRecord, int, error) {
|
||||||
return s.repo.GetPaginated(limit, offset)
|
return s.repo.GetPaginated(limit, offset)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -183,6 +183,10 @@
|
|||||||
<form action="/api/files/admin/delete/{{.ID}}" method="GET" onsubmit="return openConfirm(event, 'TERMINATE', 'Kill this file? It will be removed from active storage.')">
|
<form action="/api/files/admin/delete/{{.ID}}" method="GET" onsubmit="return openConfirm(event, 'TERMINATE', 'Kill this file? It will be removed from active storage.')">
|
||||||
<button type="submit" style="background: #ffcccc;">Terminate</button>
|
<button type="submit" style="background: #ffcccc;">Terminate</button>
|
||||||
</form>
|
</form>
|
||||||
|
{{else}}
|
||||||
|
<form action="/api/files/admin/reinstate/{{.ID}}" method="GET" onsubmit="return openConfirm(event, 'REINSTATE', 'Restore this file to active status?')">
|
||||||
|
<button type="submit" style="background: #ccffcc;">Reinstate</button>
|
||||||
|
</form>
|
||||||
{{end}}
|
{{end}}
|
||||||
<form action="/api/files/admin/delete/fr/{{.ID}}" method="GET" onsubmit="return openConfirm(event, 'FULL_WIPE', 'Wiping file and purging record? This is a permanent database scrub.')">
|
<form action="/api/files/admin/delete/fr/{{.ID}}" method="GET" onsubmit="return openConfirm(event, 'FULL_WIPE', 'Wiping file and purging record? This is a permanent database scrub.')">
|
||||||
<button type="submit">Full_Wipe</button>
|
<button type="submit">Full_Wipe</button>
|
||||||
|
|||||||
Reference in New Issue
Block a user