2019-12-11 07:37:39 +01:00
|
|
|
package repo
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
2019-12-16 23:33:52 +01:00
|
|
|
"github.com/gosimple/slug"
|
2019-12-11 16:55:18 +01:00
|
|
|
"github.com/photoprism/photoprism/internal/entity"
|
2019-12-11 07:37:39 +01:00
|
|
|
"github.com/photoprism/photoprism/internal/form"
|
|
|
|
"github.com/photoprism/photoprism/internal/util"
|
|
|
|
)
|
|
|
|
|
|
|
|
// LabelResult contains found labels
|
|
|
|
type LabelResult struct {
|
|
|
|
// Label
|
|
|
|
ID uint
|
|
|
|
CreatedAt time.Time
|
|
|
|
UpdatedAt time.Time
|
|
|
|
DeletedAt time.Time
|
2019-12-16 23:33:52 +01:00
|
|
|
LabelUUID string
|
2019-12-11 07:37:39 +01:00
|
|
|
LabelSlug string
|
|
|
|
LabelName string
|
|
|
|
LabelPriority int
|
|
|
|
LabelCount int
|
|
|
|
LabelFavorite bool
|
|
|
|
LabelDescription string
|
|
|
|
LabelNotes string
|
|
|
|
}
|
|
|
|
|
|
|
|
// FindLabelBySlug returns a Label based on the slug name.
|
2019-12-11 16:55:18 +01:00
|
|
|
func (s *Repo) FindLabelBySlug(labelSlug string) (label entity.Label, err error) {
|
2019-12-11 07:37:39 +01:00
|
|
|
if err := s.db.Where("label_slug = ?", labelSlug).First(&label).Error; err != nil {
|
|
|
|
return label, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return label, nil
|
|
|
|
}
|
|
|
|
|
2019-12-16 23:33:52 +01:00
|
|
|
// FindLabelByUUID returns a Label based on the label UUID.
|
|
|
|
func (s *Repo) FindLabelByUUID(labelUUID string) (label entity.Label, err error) {
|
|
|
|
if err := s.db.Where("label_uuid = ?", labelUUID).First(&label).Error; err != nil {
|
|
|
|
return label, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return label, nil
|
|
|
|
}
|
|
|
|
|
2019-12-11 07:37:39 +01:00
|
|
|
// FindLabelThumbBySlug returns a label preview file based on the slug name.
|
2019-12-11 16:55:18 +01:00
|
|
|
func (s *Repo) FindLabelThumbBySlug(labelSlug string) (file entity.File, err error) {
|
2019-12-11 07:37:39 +01:00
|
|
|
// s.db.LogMode(true)
|
|
|
|
|
|
|
|
if err := s.db.Where("files.file_primary AND files.deleted_at IS NULL").
|
|
|
|
Joins("JOIN labels ON labels.label_slug = ?", labelSlug).
|
|
|
|
Joins("JOIN photos_labels ON photos_labels.label_id = labels.id AND photos_labels.photo_id = files.photo_id").
|
|
|
|
Order("photos_labels.label_uncertainty ASC").
|
|
|
|
First(&file).Error; err != nil {
|
|
|
|
return file, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return file, nil
|
|
|
|
}
|
|
|
|
|
2019-12-16 23:33:52 +01:00
|
|
|
// FindLabelThumbByUUID returns a label preview file based on the label UUID.
|
|
|
|
func (s *Repo) FindLabelThumbByUUID(labelUUID string) (file entity.File, err error) {
|
2019-12-17 04:39:23 +01:00
|
|
|
// Search matching label
|
|
|
|
err = s.db.Where("files.file_primary AND files.deleted_at IS NULL").
|
2019-12-16 23:33:52 +01:00
|
|
|
Joins("JOIN labels ON labels.label_uuid = ?", labelUUID).
|
|
|
|
Joins("JOIN photos_labels ON photos_labels.label_id = labels.id AND photos_labels.photo_id = files.photo_id").
|
|
|
|
Order("photos_labels.label_uncertainty ASC").
|
2019-12-17 04:39:23 +01:00
|
|
|
First(&file).Error
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
return file, nil
|
2019-12-16 23:33:52 +01:00
|
|
|
}
|
|
|
|
|
2019-12-17 04:39:23 +01:00
|
|
|
// If failed, search for category instead
|
|
|
|
err = s.db.Where("files.file_primary AND files.deleted_at IS NULL").
|
|
|
|
Joins("JOIN photos_labels ON photos_labels.photo_id = files.photo_id").
|
|
|
|
Joins("JOIN categories c ON photos_labels.label_id = c.label_id").
|
|
|
|
Joins("JOIN labels ON c.category_id = labels.id AND labels.label_uuid= ?", labelUUID).
|
|
|
|
Order("photos_labels.label_uncertainty ASC").
|
|
|
|
First(&file).Error
|
|
|
|
|
|
|
|
return file, err
|
2019-12-16 23:33:52 +01:00
|
|
|
}
|
|
|
|
|
2019-12-11 07:37:39 +01:00
|
|
|
// Labels searches labels based on their name.
|
|
|
|
func (s *Repo) Labels(f form.LabelSearch) (results []LabelResult, err error) {
|
|
|
|
if err := f.ParseQueryString(); err != nil {
|
|
|
|
return results, err
|
|
|
|
}
|
|
|
|
|
|
|
|
defer util.ProfileTime(time.Now(), fmt.Sprintf("search: %+v", f))
|
|
|
|
|
|
|
|
q := s.db.NewScope(nil).DB()
|
|
|
|
|
|
|
|
// q.LogMode(true)
|
|
|
|
|
|
|
|
q = q.Table("labels").
|
2019-12-16 23:33:52 +01:00
|
|
|
Select(`labels.*`).
|
2019-12-11 07:37:39 +01:00
|
|
|
Where("labels.deleted_at IS NULL").
|
|
|
|
Group("labels.id")
|
|
|
|
|
|
|
|
if f.Query != "" {
|
|
|
|
var labelIds []uint
|
2019-12-11 16:55:18 +01:00
|
|
|
var categories []entity.Category
|
|
|
|
var label entity.Label
|
2019-12-11 07:37:39 +01:00
|
|
|
|
2019-12-16 23:33:52 +01:00
|
|
|
slugString := slug.Make(f.Query)
|
2019-12-11 07:37:39 +01:00
|
|
|
likeString := "%" + strings.ToLower(f.Query) + "%"
|
|
|
|
|
2019-12-16 23:33:52 +01:00
|
|
|
if result := s.db.First(&label, "label_slug = ?", slugString); result.Error != nil {
|
2019-12-11 07:37:39 +01:00
|
|
|
log.Infof("search: label \"%s\" not found", f.Query)
|
|
|
|
|
|
|
|
q = q.Where("LOWER(labels.label_name) LIKE ?", likeString)
|
|
|
|
} else {
|
|
|
|
labelIds = append(labelIds, label.ID)
|
|
|
|
|
|
|
|
s.db.Where("category_id = ?", label.ID).Find(&categories)
|
|
|
|
|
|
|
|
for _, category := range categories {
|
|
|
|
labelIds = append(labelIds, category.LabelID)
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Infof("search: label \"%s\" includes %d categories", label.LabelName, len(labelIds))
|
|
|
|
|
2019-12-16 23:33:52 +01:00
|
|
|
q = q.Where("labels.id IN (?)", labelIds)
|
2019-12-11 07:37:39 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if f.Favorites {
|
|
|
|
q = q.Where("labels.label_favorite = 1")
|
|
|
|
}
|
|
|
|
|
2019-12-17 07:13:09 +01:00
|
|
|
if !f.All {
|
2019-12-16 23:33:52 +01:00
|
|
|
q = q.Where("labels.label_priority >= 0 OR labels.label_favorite = 1")
|
2019-12-11 07:37:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
switch f.Order {
|
|
|
|
case "slug":
|
|
|
|
q = q.Order("labels.label_favorite DESC, label_slug ASC")
|
|
|
|
default:
|
2019-12-15 22:49:37 +01:00
|
|
|
q = q.Order("labels.label_favorite DESC, label_slug ASC")
|
2019-12-11 07:37:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if f.Count > 0 && f.Count <= 1000 {
|
|
|
|
q = q.Limit(f.Count).Offset(f.Offset)
|
|
|
|
} else {
|
|
|
|
q = q.Limit(100).Offset(0)
|
|
|
|
}
|
|
|
|
|
|
|
|
if result := q.Scan(&results); result.Error != nil {
|
|
|
|
return results, result.Error
|
|
|
|
}
|
|
|
|
|
|
|
|
return results, nil
|
|
|
|
}
|