Backend: Fix handling of deleted labels
Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
parent
c2adaa5752
commit
15113afaa6
5 changed files with 60 additions and 10 deletions
|
@ -215,7 +215,17 @@ func BatchLabelsDelete(router *gin.RouterGroup, conf *config.Config) {
|
|||
|
||||
log.Infof("labels: deleting %#v", f.Labels)
|
||||
|
||||
entity.Db().Where("label_uid IN (?)", f.Labels).Delete(&entity.Label{})
|
||||
var labels entity.Labels
|
||||
|
||||
if err := entity.Db().Where("label_uid IN (?)", f.Labels).Find(&labels).Error; err != nil {
|
||||
logError("labels", err)
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, ErrDeleteFailed)
|
||||
return
|
||||
}
|
||||
|
||||
for _, label := range labels {
|
||||
logError("labels", label.Delete())
|
||||
}
|
||||
|
||||
UpdateClientConfig(conf)
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ var (
|
|||
ErrFileNotFound = gin.H{"code": http.StatusNotFound, "error": "File not found"}
|
||||
ErrUnexpectedError = gin.H{"code": http.StatusInternalServerError, "error": "Unexpected error"}
|
||||
ErrSaveFailed = gin.H{"code": http.StatusInternalServerError, "error": "Changes could not be saved"}
|
||||
ErrDeleteFailed = gin.H{"code": http.StatusInternalServerError, "error": "Changes could not be saved"}
|
||||
ErrFormInvalid = gin.H{"code": http.StatusBadRequest, "error": "Changes could not be saved"}
|
||||
ErrFeatureDisabled = gin.H{"code": http.StatusForbidden, "error": "Feature disabled"}
|
||||
)
|
||||
|
|
|
@ -46,6 +46,10 @@ func AddPhotoLabel(router *gin.RouterGroup, conf *config.Config) {
|
|||
return
|
||||
}
|
||||
|
||||
if err := labelEntity.Restore(); err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "could not restore label"})
|
||||
}
|
||||
|
||||
photoLabel := entity.FirstOrCreatePhotoLabel(entity.NewPhotoLabel(m.ID, labelEntity.ID, f.Uncertainty, "manual"))
|
||||
|
||||
if photoLabel == nil {
|
||||
|
|
|
@ -11,6 +11,8 @@ import (
|
|||
"github.com/photoprism/photoprism/pkg/txt"
|
||||
)
|
||||
|
||||
type Labels []Label
|
||||
|
||||
// Label is used for photo, album and location categorization
|
||||
type Label struct {
|
||||
ID uint `gorm:"primary_key" json:"ID" yaml:"-"`
|
||||
|
@ -40,7 +42,7 @@ func (m *Label) BeforeCreate(scope *gorm.Scope) error {
|
|||
return scope.SetColumn("LabelUID", rnd.PPID('l'))
|
||||
}
|
||||
|
||||
// NewLabel creates a label in database with a given name and priority
|
||||
// NewLabel returns a new label.
|
||||
func NewLabel(name string, priority int) *Label {
|
||||
labelName := txt.Clip(name, txt.ClipDefault)
|
||||
|
||||
|
@ -62,26 +64,47 @@ func NewLabel(name string, priority int) *Label {
|
|||
return result
|
||||
}
|
||||
|
||||
// Save updates the existing or inserts a new row.
|
||||
// Save updates the existing or inserts a new label.
|
||||
func (m *Label) Save() error {
|
||||
return Db().Save(m).Error
|
||||
}
|
||||
|
||||
// Create inserts a new row to the database.
|
||||
// Create inserts the label to the database.
|
||||
func (m *Label) Create() error {
|
||||
return Db().Create(m).Error
|
||||
}
|
||||
|
||||
// Updates a column in the database.
|
||||
// Delete removes the label from the database.
|
||||
func (m *Label) Delete() error {
|
||||
Db().Where("label_id = ? OR category_id = ?", m.ID, m.ID).Delete(&Category{})
|
||||
Db().Where("label_id = ?", m.ID).Delete(&PhotoLabel{})
|
||||
return Db().Delete(m).Error
|
||||
}
|
||||
|
||||
// Deleted returns true if the label is deleted.
|
||||
func (m *Label) Deleted() bool {
|
||||
return m.DeletedAt != nil
|
||||
}
|
||||
|
||||
// Delete removes the label from the database.
|
||||
func (m *Label) Restore() error {
|
||||
if m.Deleted() {
|
||||
return UnscopedDb().Model(m).Update("DeletedAt", nil).Error
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Updates a label property in the database.
|
||||
func (m *Label) Update(attr string, value interface{}) error {
|
||||
return UnscopedDb().Model(m).UpdateColumn(attr, value).Error
|
||||
}
|
||||
|
||||
// FirstOrCreateLabel returns the existing row, inserts a new row or nil in case of errors.
|
||||
// FirstOrCreateLabel returns the existing label, inserts a new label or nil in case of errors.
|
||||
func FirstOrCreateLabel(m *Label) *Label {
|
||||
result := Label{}
|
||||
|
||||
if err := Db().Where("label_slug = ? OR custom_slug = ?", m.LabelSlug, m.CustomSlug).First(&result).Error; err == nil {
|
||||
if err := UnscopedDb().Where("label_slug = ? OR custom_slug = ?", m.LabelSlug, m.CustomSlug).First(&result).Error; err == nil {
|
||||
return &result
|
||||
} else if err := m.Create(); err != nil {
|
||||
log.Errorf("label: %s", err)
|
||||
|
@ -167,6 +190,10 @@ func (m *Label) UpdateClassify(label classify.Label) error {
|
|||
continue
|
||||
}
|
||||
|
||||
if sn.Deleted() {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := db.Model(m).Association("LabelCategories").Append(sn).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ import (
|
|||
"github.com/ulule/deepcopier"
|
||||
)
|
||||
|
||||
// Default photo result slice for simple use cases.
|
||||
type Photos []Photo
|
||||
|
||||
// UIDs returns a slice of unique photo IDs.
|
||||
|
@ -273,6 +272,10 @@ func (m *Photo) SyncKeywordLabels() error {
|
|||
|
||||
for _, w := range keywords {
|
||||
if label := FindLabel(w); label != nil {
|
||||
if label.Deleted() {
|
||||
continue
|
||||
}
|
||||
|
||||
labelIds = append(labelIds, label.ID)
|
||||
FirstOrCreatePhotoLabel(NewPhotoLabel(m.ID, label.ID, 25, classify.SrcKeyword))
|
||||
}
|
||||
|
@ -585,7 +588,12 @@ func (m *Photo) AddLabels(labels classify.Labels) {
|
|||
labelEntity := FirstOrCreateLabel(NewLabel(classifyLabel.Title(), classifyLabel.Priority))
|
||||
|
||||
if labelEntity == nil {
|
||||
log.Errorf("index: label %s for photo %d should not be nil - bug?", txt.Quote(classifyLabel.Title()), m.ID)
|
||||
log.Errorf("index: label %s should not be nil - bug? (%s)", txt.Quote(classifyLabel.Title()), m)
|
||||
continue
|
||||
}
|
||||
|
||||
if labelEntity.Deleted() {
|
||||
log.Debugf("index: skipping deleted label %s (%s)", txt.Quote(classifyLabel.Title()), m)
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -596,7 +604,7 @@ func (m *Photo) AddLabels(labels classify.Labels) {
|
|||
photoLabel := FirstOrCreatePhotoLabel(NewPhotoLabel(m.ID, labelEntity.ID, classifyLabel.Uncertainty, classifyLabel.Source))
|
||||
|
||||
if photoLabel == nil {
|
||||
log.Errorf("index: label %d for photo %d should not be nil - bug?", labelEntity.ID, m.ID)
|
||||
log.Errorf("index: photo-label %d should not be nil - bug? (%s)", labelEntity.ID, m)
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue