2020-01-15 04:04:33 +01:00
|
|
|
package query
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/photoprism/photoprism/internal/form"
|
|
|
|
"github.com/photoprism/photoprism/pkg/capture"
|
|
|
|
"github.com/photoprism/photoprism/pkg/pluscode"
|
|
|
|
"github.com/photoprism/photoprism/pkg/s2"
|
2020-04-26 14:31:33 +02:00
|
|
|
"github.com/photoprism/photoprism/pkg/txt"
|
2020-01-15 04:04:33 +01:00
|
|
|
)
|
|
|
|
|
2020-05-11 14:49:00 +02:00
|
|
|
// Geo searches for photos based on a Form and returns GeoResults ([]GeoResult).
|
|
|
|
func Geo(f form.GeoSearch) (results GeoResults, err error) {
|
2020-01-15 04:04:33 +01:00
|
|
|
if err := f.ParseQueryString(); err != nil {
|
|
|
|
return results, err
|
|
|
|
}
|
|
|
|
|
|
|
|
defer log.Debug(capture.Time(time.Now(), fmt.Sprintf("search: %+v", f)))
|
|
|
|
|
2020-05-08 15:41:01 +02:00
|
|
|
s := UnscopedDb()
|
2020-01-15 04:04:33 +01:00
|
|
|
|
2020-03-28 17:17:41 +01:00
|
|
|
s = s.Table("photos").
|
2020-04-24 10:07:13 +02:00
|
|
|
Select(`photos.id, photos.photo_uuid, photos.photo_lat, photos.photo_lng, photos.photo_title,
|
|
|
|
photos.photo_favorite, photos.taken_at, files.file_hash, files.file_width, files.file_height`).
|
2020-01-15 04:04:33 +01:00
|
|
|
Joins(`JOIN files ON files.photo_id = photos.id
|
|
|
|
AND files.file_missing = 0 AND files.file_primary AND files.deleted_at IS NULL`).
|
2020-01-21 13:23:24 +01:00
|
|
|
Where("photos.deleted_at IS NULL").
|
2020-01-15 04:04:33 +01:00
|
|
|
Where("photos.photo_lat <> 0").
|
|
|
|
Group("photos.id, files.id")
|
|
|
|
|
2020-04-26 14:31:33 +02:00
|
|
|
f.Query = txt.Clip(f.Query, txt.ClipKeyword)
|
|
|
|
|
2020-01-15 04:04:33 +01:00
|
|
|
if f.Query != "" {
|
2020-03-28 17:17:41 +01:00
|
|
|
s = s.Joins("LEFT JOIN photos_keywords ON photos_keywords.photo_id = photos.id").
|
2020-01-15 04:04:33 +01:00
|
|
|
Joins("LEFT JOIN keywords ON photos_keywords.keyword_id = keywords.id").
|
|
|
|
Where("keywords.keyword LIKE ?", strings.ToLower(f.Query)+"%")
|
|
|
|
}
|
|
|
|
|
2020-04-24 13:25:04 +02:00
|
|
|
if f.Review {
|
|
|
|
s = s.Where("photos.photo_quality < 3")
|
|
|
|
} else if f.Quality != 0 {
|
|
|
|
s = s.Where("photos.photo_quality >= ?", f.Quality)
|
|
|
|
}
|
|
|
|
|
2020-04-24 10:07:13 +02:00
|
|
|
if f.Favorite {
|
|
|
|
s = s.Where("photos.photo_favorite = 1")
|
|
|
|
}
|
|
|
|
|
2020-01-15 04:04:33 +01:00
|
|
|
if f.S2 != "" {
|
2020-01-17 02:41:35 +01:00
|
|
|
s2Min, s2Max := s2.Range(f.S2, 7)
|
2020-03-28 17:17:41 +01:00
|
|
|
s = s.Where("photos.location_id BETWEEN ? AND ?", s2Min, s2Max)
|
2020-01-15 04:04:33 +01:00
|
|
|
} else if f.Olc != "" {
|
2020-01-17 02:41:35 +01:00
|
|
|
s2Min, s2Max := s2.Range(pluscode.S2(f.Olc), 7)
|
2020-03-28 17:17:41 +01:00
|
|
|
s = s.Where("photos.location_id BETWEEN ? AND ?", s2Min, s2Max)
|
2020-01-15 04:04:33 +01:00
|
|
|
} else {
|
|
|
|
// Inaccurate distance search, but probably 'good enough' for now
|
|
|
|
if f.Lat > 0 {
|
2020-04-26 11:41:54 +02:00
|
|
|
latMin := f.Lat - SearchRadius*float32(f.Dist)
|
|
|
|
latMax := f.Lat + SearchRadius*float32(f.Dist)
|
2020-03-28 17:17:41 +01:00
|
|
|
s = s.Where("photos.photo_lat BETWEEN ? AND ?", latMin, latMax)
|
2020-01-15 04:04:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if f.Lng > 0 {
|
2020-04-26 11:41:54 +02:00
|
|
|
lngMin := f.Lng - SearchRadius*float32(f.Dist)
|
|
|
|
lngMax := f.Lng + SearchRadius*float32(f.Dist)
|
2020-03-28 17:17:41 +01:00
|
|
|
s = s.Where("photos.photo_lng BETWEEN ? AND ?", lngMin, lngMax)
|
2020-01-15 04:04:33 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !f.Before.IsZero() {
|
2020-03-28 17:17:41 +01:00
|
|
|
s = s.Where("photos.taken_at <= ?", f.Before.Format("2006-01-02"))
|
2020-01-15 04:04:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if !f.After.IsZero() {
|
2020-03-28 17:17:41 +01:00
|
|
|
s = s.Where("photos.taken_at >= ?", f.After.Format("2006-01-02"))
|
2020-01-15 04:04:33 +01:00
|
|
|
}
|
|
|
|
|
2020-03-28 17:17:41 +01:00
|
|
|
s = s.Order("taken_at, photos.photo_uuid")
|
2020-01-15 04:04:33 +01:00
|
|
|
|
2020-03-28 17:17:41 +01:00
|
|
|
if result := s.Scan(&results); result.Error != nil {
|
2020-01-15 04:04:33 +01:00
|
|
|
return results, result.Error
|
|
|
|
}
|
|
|
|
|
|
|
|
return results, nil
|
|
|
|
}
|