2019-12-11 16:55:18 +01:00
|
|
|
package entity
|
2019-06-04 18:26:35 +02:00
|
|
|
|
|
|
|
import (
|
2019-12-27 05:18:52 +01:00
|
|
|
"time"
|
2019-06-04 18:26:35 +02:00
|
|
|
|
|
|
|
"github.com/gosimple/slug"
|
|
|
|
"github.com/jinzhu/gorm"
|
2020-04-17 21:20:38 +02:00
|
|
|
"github.com/photoprism/photoprism/internal/classify"
|
2020-01-12 14:00:56 +01:00
|
|
|
"github.com/photoprism/photoprism/pkg/rnd"
|
2020-02-02 02:00:47 +01:00
|
|
|
"github.com/photoprism/photoprism/pkg/txt"
|
2019-06-04 18:26:35 +02:00
|
|
|
)
|
|
|
|
|
2020-02-21 01:14:45 +01:00
|
|
|
// Label is used for photo, album and location categorization
|
2019-06-04 18:26:35 +02:00
|
|
|
type Label struct {
|
2019-12-27 05:18:52 +01:00
|
|
|
ID uint `gorm:"primary_key"`
|
|
|
|
LabelUUID string `gorm:"type:varbinary(36);unique_index;"`
|
2020-04-26 14:31:33 +02:00
|
|
|
LabelSlug string `gorm:"type:varbinary(255);unique_index;"`
|
|
|
|
CustomSlug string `gorm:"type:varbinary(255);index;"`
|
|
|
|
LabelName string `gorm:"type:varchar(255);"`
|
2019-06-04 18:26:35 +02:00
|
|
|
LabelPriority int
|
2019-06-09 04:37:02 +02:00
|
|
|
LabelFavorite bool
|
2019-06-04 18:26:35 +02:00
|
|
|
LabelDescription string `gorm:"type:text;"`
|
|
|
|
LabelNotes string `gorm:"type:text;"`
|
2019-06-09 04:37:02 +02:00
|
|
|
LabelCategories []*Label `gorm:"many2many:categories;association_jointable_foreignkey:category_id"`
|
2020-04-08 13:24:06 +02:00
|
|
|
Links []Link `gorm:"foreignkey:ShareUUID;association_foreignkey:LabelUUID"`
|
2020-05-10 19:43:49 +02:00
|
|
|
PhotoCount int `gorm:"default:1"`
|
2019-12-27 05:18:52 +01:00
|
|
|
CreatedAt time.Time
|
|
|
|
UpdatedAt time.Time
|
|
|
|
DeletedAt *time.Time `sql:"index"`
|
|
|
|
New bool `gorm:"-"`
|
2019-06-04 18:26:35 +02:00
|
|
|
}
|
|
|
|
|
2020-02-21 01:14:45 +01:00
|
|
|
// BeforeCreate computes a random UUID when a new label is created in database
|
2019-12-16 23:33:52 +01:00
|
|
|
func (m *Label) BeforeCreate(scope *gorm.Scope) error {
|
2020-05-01 12:57:26 +02:00
|
|
|
if rnd.IsPPID(m.LabelUUID, 'l') {
|
|
|
|
return nil
|
2019-12-16 23:33:52 +01:00
|
|
|
}
|
|
|
|
|
2020-05-01 12:57:26 +02:00
|
|
|
return scope.SetColumn("LabelUUID", rnd.PPID('l'))
|
2019-12-16 23:33:52 +01:00
|
|
|
}
|
|
|
|
|
2020-02-21 01:14:45 +01:00
|
|
|
// NewLabel creates a label in database with a given name and priority
|
2020-04-26 14:31:33 +02:00
|
|
|
func NewLabel(name string, priority int) *Label {
|
|
|
|
labelName := txt.Clip(name, txt.ClipDefault)
|
2019-06-04 18:26:35 +02:00
|
|
|
|
|
|
|
if labelName == "" {
|
|
|
|
labelName = "Unknown"
|
|
|
|
}
|
|
|
|
|
2020-04-26 14:31:33 +02:00
|
|
|
labelName = txt.Title(labelName)
|
|
|
|
labelSlug := slug.Make(txt.Clip(labelName, txt.ClipSlug))
|
2019-06-04 18:26:35 +02:00
|
|
|
|
|
|
|
result := &Label{
|
2019-06-09 04:37:02 +02:00
|
|
|
LabelSlug: labelSlug,
|
2020-04-17 21:20:38 +02:00
|
|
|
CustomSlug: labelSlug,
|
|
|
|
LabelName: labelName,
|
2020-04-26 14:31:33 +02:00
|
|
|
LabelPriority: priority,
|
2020-05-10 19:43:49 +02:00
|
|
|
PhotoCount: 1,
|
2019-06-04 18:26:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2020-04-17 21:20:38 +02:00
|
|
|
// FirstOrCreate checks if the label already exists in the database
|
2020-04-30 20:07:03 +02:00
|
|
|
func (m *Label) FirstOrCreate() *Label {
|
|
|
|
if err := Db().FirstOrCreate(m, "label_slug = ? OR custom_slug = ?", m.LabelSlug, m.CustomSlug).Error; err != nil {
|
2019-12-19 09:37:10 +01:00
|
|
|
log.Errorf("label: %s", err)
|
|
|
|
}
|
2019-06-04 18:26:35 +02:00
|
|
|
|
|
|
|
return m
|
|
|
|
}
|
2019-12-11 04:12:54 +01:00
|
|
|
|
2020-02-21 01:14:45 +01:00
|
|
|
// AfterCreate sets the New column used for database callback
|
2019-12-11 04:12:54 +01:00
|
|
|
func (m *Label) AfterCreate(scope *gorm.Scope) error {
|
2020-05-19 12:30:26 +02:00
|
|
|
m.New = true
|
|
|
|
return nil
|
2019-12-11 04:12:54 +01:00
|
|
|
}
|
2020-02-02 02:00:47 +01:00
|
|
|
|
2020-04-26 14:31:33 +02:00
|
|
|
// SetName changes the label name.
|
|
|
|
func (m *Label) SetName(name string) {
|
|
|
|
newName := txt.Clip(name, txt.ClipDefault)
|
2020-02-02 02:00:47 +01:00
|
|
|
|
2020-04-26 14:31:33 +02:00
|
|
|
if newName == "" {
|
2020-04-17 21:20:38 +02:00
|
|
|
return
|
2020-02-02 02:00:47 +01:00
|
|
|
}
|
|
|
|
|
2020-04-26 14:31:33 +02:00
|
|
|
m.LabelName = txt.Title(newName)
|
|
|
|
m.CustomSlug = slug.Make(txt.Clip(name, txt.ClipSlug))
|
2020-04-17 21:20:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Updates a label if necessary
|
2020-04-30 20:07:03 +02:00
|
|
|
func (m *Label) Update(label classify.Label) error {
|
2020-04-17 21:20:38 +02:00
|
|
|
save := false
|
2020-04-30 20:07:03 +02:00
|
|
|
db := Db()
|
2020-04-17 21:20:38 +02:00
|
|
|
|
|
|
|
if m.LabelPriority != label.Priority {
|
|
|
|
m.LabelPriority = label.Priority
|
|
|
|
save = true
|
|
|
|
}
|
|
|
|
|
|
|
|
if m.CustomSlug == "" {
|
|
|
|
m.CustomSlug = m.LabelSlug
|
|
|
|
save = true
|
|
|
|
} else if m.LabelSlug == "" {
|
|
|
|
m.LabelSlug = m.CustomSlug
|
|
|
|
save = true
|
|
|
|
}
|
|
|
|
|
|
|
|
if m.CustomSlug == m.LabelSlug && label.Title() != m.LabelName {
|
2020-04-26 14:31:33 +02:00
|
|
|
m.SetName(label.Title())
|
2020-04-17 21:20:38 +02:00
|
|
|
save = true
|
|
|
|
}
|
|
|
|
|
2020-04-18 23:20:54 +02:00
|
|
|
if save {
|
|
|
|
if err := db.Save(m).Error; err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-04-17 21:20:38 +02:00
|
|
|
}
|
|
|
|
|
2020-04-18 23:20:54 +02:00
|
|
|
// Add categories
|
|
|
|
for _, category := range label.Categories {
|
2020-04-30 20:07:03 +02:00
|
|
|
sn := NewLabel(txt.Title(category), -3).FirstOrCreate()
|
2020-04-18 23:20:54 +02:00
|
|
|
if err := db.Model(m).Association("LabelCategories").Append(sn).Error; err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2020-02-02 02:00:47 +01:00
|
|
|
}
|