Management API: POST/DELETE /materials/{id}/files (attach.Store, 50 MB, 20 files), DELETE /materials/{id} removes files; download keeps the file name

This commit is contained in:
Jakub Zych
2026-10-17 17:53:22 +02:00
parent 584d15257c
commit 996b4d1542
44 changed files with 463 additions and 56 deletions

View File

@@ -465,6 +465,12 @@ func (h *Handlers) ManagedMaterial(w http.ResponseWriter, r *http.Request) {
writeNotFound(w)
return
}
h.writeMaterialDetail(w, db, uint(id), http.StatusOK)
}
// writeMaterialDetail answers with the material id as GET /materials/{id}
// shows it, or 404 when there is none.
func (h *Handlers) writeMaterialDetail(w http.ResponseWriter, db *gorm.DB, id uint, status int) {
var m models.Material
res := preloadMaterial(db).Where("jz_bm_materials.id = ?", id).Limit(1).Find(&m)
if res.Error != nil {
@@ -476,10 +482,7 @@ func (h *Handlers) ManagedMaterial(w http.ResponseWriter, r *http.Request) {
return
}
var files []attach.File
err := db.Where("attachment_type = ? AND attachment_id = ? AND field = ?", m.MorphName(), strconv.FormatUint(uint64(m.ID), 10), models.MaterialFilesField).
Order("sort_order, id").
Find(&files).Error
if err != nil {
if err := materialFiles(db, m).Order("sort_order, id").Find(&files).Error; err != nil {
writeOpaque500(w)
return
}
@@ -491,7 +494,7 @@ func (h *Handlers) ManagedMaterial(w http.ResponseWriter, r *http.Request) {
}
out.Files = append(out.Files, fileJSON{ID: f.ID, URL: f.URL(), Name: f.FileName, Size: f.FileSize, Mime: f.ContentType})
}
writeData(w, out)
wire.WriteJSON(w, status, map[string]any{"data": out})
}
// DeleteMaterial answers DELETE /materials/{id}.
@@ -505,15 +508,33 @@ func (h *Handlers) DeleteMaterial(w http.ResponseWriter, r *http.Request) {
writeNotFound(w)
return
}
res := db.Where("id = ?", id).Delete(&models.Material{})
if res.Error != nil {
var keys []string
found := false
err := lagoon.Transaction(r.Context(), db, func(_ context.Context, tx *gorm.DB) error {
res := tx.Where("id = ?", id).Delete(&models.Material{})
if res.Error != nil || res.RowsAffected == 0 {
return res.Error
}
found = true
return attach.DeleteForOwner(tx, models.Material{}, strconv.FormatInt(id, 10), func(k []string) error {
keys = k
return nil
})
})
switch {
case err != nil:
writeOpaque500(w)
return
}
if res.RowsAffected == 0 {
case !found:
writeNotFound(w)
return
}
// The files go with the material: rows in the transaction, blobs after it.
if b := h.Bucket; b != nil && len(keys) > 0 {
if bucket := b(); bucket != nil {
_ = attach.DeleteKeys(r.Context(), bucket, keys)
}
}
w.WriteHeader(http.StatusNoContent)
}