2020-01-05 14:18:40 +01:00
|
|
|
package query
|
2019-12-11 07:37:39 +01:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
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"
|
2020-01-13 11:07:09 +01:00
|
|
|
"github.com/photoprism/photoprism/pkg/capture"
|
2019-12-11 07:37:39 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
// AlbumResult contains found albums
|
|
|
|
type AlbumResult struct {
|
2020-05-26 09:02:19 +02:00
|
|
|
ID uint `json:"-"`
|
|
|
|
AlbumUID string `json:"UID"`
|
|
|
|
CoverUID string `json:"CoverUID"`
|
|
|
|
FolderUID string `json:"FolderUID"`
|
|
|
|
AlbumSlug string `json:"Slug"`
|
|
|
|
AlbumType string `json:"Type"`
|
|
|
|
AlbumTitle string `json:"Title"`
|
|
|
|
AlbumCategory string `json:"Category"`
|
|
|
|
AlbumCaption string `json:"Caption"`
|
|
|
|
AlbumDescription string `json:"Description"`
|
|
|
|
AlbumNotes string `json:"Notes"`
|
|
|
|
AlbumFilter string `json:"Filter"`
|
|
|
|
AlbumOrder string `json:"Order"`
|
|
|
|
AlbumTemplate string `json:"Template"`
|
|
|
|
AlbumCountry string `json:"Country"`
|
|
|
|
AlbumYear int `json:"Year"`
|
|
|
|
AlbumMonth int `json:"Month"`
|
|
|
|
AlbumFavorite bool `json:"Favorite"`
|
|
|
|
AlbumPrivate bool `json:"Private"`
|
|
|
|
PhotoCount int `json:"PhotoCount"`
|
|
|
|
LinkCount int `json:"LinkCount"`
|
|
|
|
CreatedAt time.Time `json:"CreatedAt"`
|
|
|
|
UpdatedAt time.Time `json:"UpdatedAt"`
|
|
|
|
DeletedAt time.Time `json:"DeletedAt,omitempty"`
|
2019-12-11 07:37:39 +01:00
|
|
|
}
|
|
|
|
|
2020-05-23 20:58:58 +02:00
|
|
|
// AlbumByUID returns a Album based on the UID.
|
|
|
|
func AlbumByUID(albumUID string) (album entity.Album, err error) {
|
|
|
|
if err := Db().Where("album_uid = ?", albumUID).Preload("Links").First(&album).Error; err != nil {
|
2019-12-11 07:37:39 +01:00
|
|
|
return album, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return album, nil
|
|
|
|
}
|
|
|
|
|
2020-05-30 01:41:47 +02:00
|
|
|
// AlbumCoverByUID returns a album preview file based on the uid.
|
|
|
|
func AlbumCoverByUID(albumUID string) (file entity.File, err error) {
|
|
|
|
a := entity.Album{}
|
|
|
|
|
|
|
|
if err := Db().Where("album_uid = ?", albumUID).First(&a).Error; err != nil {
|
|
|
|
return file, err
|
2020-06-08 18:32:51 +02:00
|
|
|
} else if a.AlbumType != entity.AlbumDefault { // TODO: Optimize
|
2020-05-30 14:52:47 +02:00
|
|
|
f := form.PhotoSearch{Album: a.AlbumUID, Filter: a.AlbumFilter, Order: entity.SortOrderRelevance, Count: 1, Offset: 0, Merged: false}
|
2020-05-30 01:41:47 +02:00
|
|
|
|
|
|
|
if photos, _, err := PhotoSearch(f); err != nil {
|
|
|
|
return file, err
|
|
|
|
} else if len(photos) > 0 {
|
|
|
|
for _, photo := range photos {
|
2020-05-30 14:52:47 +02:00
|
|
|
if err := Db().Where("photo_uid = ? AND file_primary = 1", photo.PhotoUID).First(&file).Error; err != nil {
|
|
|
|
return file, err
|
|
|
|
} else {
|
|
|
|
return file, nil
|
|
|
|
}
|
2020-05-30 01:41:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return file, fmt.Errorf("found no cover for moment")
|
|
|
|
}
|
|
|
|
|
2020-05-30 14:52:47 +02:00
|
|
|
if err := Db().Where("files.file_primary = 1 AND files.file_missing = 0 AND files.file_type = 'jpg' AND files.deleted_at IS NULL").
|
2020-05-23 20:58:58 +02:00
|
|
|
Joins("JOIN albums ON albums.album_uid = ?", albumUID).
|
|
|
|
Joins("JOIN photos_albums pa ON pa.album_uid = albums.album_uid AND pa.photo_uid = files.photo_uid").
|
2020-04-27 17:06:36 +02:00
|
|
|
Joins("JOIN photos ON photos.id = files.photo_id AND photos.photo_private = 0 AND photos.deleted_at IS NULL").
|
2020-04-27 14:25:04 +02:00
|
|
|
Order("photos.photo_quality DESC, photos.taken_at DESC").
|
2019-12-11 07:37:39 +01:00
|
|
|
First(&file).Error; err != nil {
|
|
|
|
return file, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return file, nil
|
|
|
|
}
|
|
|
|
|
2020-05-30 21:31:32 +02:00
|
|
|
// AlbumPhotos returns up to count photos from an album.
|
|
|
|
func AlbumPhotos(a entity.Album, count int) (results PhotoResults, err error) {
|
|
|
|
results, _, err = PhotoSearch(form.PhotoSearch{
|
|
|
|
Album: a.AlbumUID,
|
|
|
|
Filter: a.AlbumFilter,
|
|
|
|
Count: count,
|
|
|
|
Offset: 0,
|
|
|
|
})
|
|
|
|
|
|
|
|
return results, err
|
|
|
|
}
|
|
|
|
|
2020-05-25 19:10:44 +02:00
|
|
|
// AlbumSearch searches albums based on their name.
|
|
|
|
func AlbumSearch(f form.AlbumSearch) (results []AlbumResult, err error) {
|
2019-12-11 07:37:39 +01:00
|
|
|
if err := f.ParseQueryString(); err != nil {
|
|
|
|
return results, err
|
|
|
|
}
|
|
|
|
|
2020-05-23 20:58:58 +02:00
|
|
|
defer log.Debug(capture.Time(time.Now(), fmt.Sprintf("albums: search %s", form.Serialize(f, true))))
|
2019-12-11 07:37:39 +01:00
|
|
|
|
2020-05-08 15:41:01 +02:00
|
|
|
s := Db().NewScope(nil).DB()
|
2019-12-11 07:37:39 +01:00
|
|
|
|
2020-03-28 17:17:41 +01:00
|
|
|
s = s.Table("albums").
|
2020-04-08 13:24:06 +02:00
|
|
|
Select(`albums.*,
|
2020-05-23 20:58:58 +02:00
|
|
|
COUNT(photos_albums.album_uid) AS photo_count,
|
2020-04-08 13:24:06 +02:00
|
|
|
COUNT(links.link_token) AS link_count`).
|
2020-05-23 20:58:58 +02:00
|
|
|
Joins("LEFT JOIN photos_albums ON photos_albums.album_uid = albums.album_uid").
|
|
|
|
Joins("LEFT JOIN links ON links.share_uid = albums.album_uid").
|
2019-12-11 07:37:39 +01:00
|
|
|
Where("albums.deleted_at IS NULL").
|
|
|
|
Group("albums.id")
|
|
|
|
|
2020-01-30 18:19:26 +01:00
|
|
|
if f.ID != "" {
|
2020-05-29 12:21:17 +02:00
|
|
|
s = s.Where("albums.album_uid IN (?)", strings.Split(f.ID, ","))
|
2020-01-30 18:19:26 +01:00
|
|
|
|
2020-03-28 17:17:41 +01:00
|
|
|
if result := s.Scan(&results); result.Error != nil {
|
2020-01-30 18:19:26 +01:00
|
|
|
return results, result.Error
|
|
|
|
}
|
|
|
|
|
|
|
|
return results, nil
|
|
|
|
}
|
|
|
|
|
2019-12-11 07:37:39 +01:00
|
|
|
if f.Query != "" {
|
|
|
|
likeString := "%" + strings.ToLower(f.Query) + "%"
|
2020-05-26 09:02:19 +02:00
|
|
|
s = s.Where("LOWER(albums.album_title) LIKE ?", likeString)
|
2019-12-11 07:37:39 +01:00
|
|
|
}
|
|
|
|
|
2020-05-29 12:21:17 +02:00
|
|
|
if f.Type != "" {
|
|
|
|
s = s.Where("albums.album_type IN (?)", strings.Split(f.Type, ","))
|
|
|
|
}
|
|
|
|
|
|
|
|
if f.Category != "" {
|
|
|
|
s = s.Where("albums.album_category IN (?)", strings.Split(f.Category, ","))
|
|
|
|
}
|
|
|
|
|
2020-05-14 19:03:12 +02:00
|
|
|
if f.Favorite {
|
2020-03-28 17:17:41 +01:00
|
|
|
s = s.Where("albums.album_favorite = 1")
|
2019-12-11 07:37:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
switch f.Order {
|
|
|
|
case "slug":
|
2020-03-28 17:17:41 +01:00
|
|
|
s = s.Order("albums.album_favorite DESC, album_slug ASC")
|
2019-12-11 07:37:39 +01:00
|
|
|
default:
|
2020-05-30 01:41:47 +02:00
|
|
|
s = s.Order("albums.album_favorite DESC, albums.album_year DESC, albums.album_month DESC, albums.album_title, albums.created_at DESC")
|
2019-12-11 07:37:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if f.Count > 0 && f.Count <= 1000 {
|
2020-03-28 17:17:41 +01:00
|
|
|
s = s.Limit(f.Count).Offset(f.Offset)
|
2019-12-11 07:37:39 +01:00
|
|
|
} else {
|
2020-03-28 17:17:41 +01:00
|
|
|
s = s.Limit(100).Offset(0)
|
2019-12-11 07:37:39 +01:00
|
|
|
}
|
|
|
|
|
2020-03-28 17:17:41 +01:00
|
|
|
if result := s.Scan(&results); result.Error != nil {
|
2019-12-11 07:37:39 +01:00
|
|
|
return results, result.Error
|
|
|
|
}
|
|
|
|
|
|
|
|
return results, nil
|
|
|
|
}
|