People: Use slug as search filter #22
This commit is contained in:
parent
94b8a6ad65
commit
04d2cfa650
9 changed files with 93 additions and 11 deletions
|
@ -63,8 +63,8 @@ export class Subject extends RestModel {
|
|||
}
|
||||
|
||||
route(view) {
|
||||
if (!this.Type || this.Type === SubjPerson) {
|
||||
return { name: view, query: { q: `people:"${this.Name}"` } };
|
||||
if (this.Slug && (!this.Type || this.Type === SubjPerson)) {
|
||||
return { name: view, query: { q: `person:${this.Slug}` } };
|
||||
}
|
||||
|
||||
return { name: view, query: { q: "subject:" + this.UID } };
|
||||
|
|
|
@ -52,6 +52,7 @@ type PhotoSearch struct {
|
|||
Day int `form:"day"` // Moments
|
||||
Face string `form:"face"` // UIDs
|
||||
Subject string `form:"subject"` // UIDs
|
||||
Person string `form:"person"` // Alias for Subject
|
||||
Subjects string `form:"subjects"` // Text
|
||||
People string `form:"people"` // Alias for Subjects
|
||||
Album string `form:"album"` // UIDs
|
||||
|
@ -85,10 +86,17 @@ func (f *PhotoSearch) ParseQueryString() error {
|
|||
|
||||
if f.Path == "" && f.Folder != "" {
|
||||
f.Path = f.Folder
|
||||
f.Folder = ""
|
||||
}
|
||||
|
||||
if f.Subjects == "" {
|
||||
if f.Subject == "" && f.Person != "" {
|
||||
f.Subject = f.Person
|
||||
f.Person = ""
|
||||
}
|
||||
|
||||
if f.Subjects == "" && f.People != "" {
|
||||
f.Subjects = f.People
|
||||
f.People = ""
|
||||
}
|
||||
|
||||
if f.Filter != "" {
|
||||
|
|
|
@ -27,6 +27,7 @@ type PhotoSearchGeo struct {
|
|||
Dist uint `form:"dist"`
|
||||
Face string `form:"face"` // UIDs
|
||||
Subject string `form:"subject"` // UIDs
|
||||
Person string `form:"person"` // Alias for Subject
|
||||
Subjects string `form:"subjects"` // Text
|
||||
People string `form:"people"` // Alias for Subjects
|
||||
Keywords string `form:"keywords"`
|
||||
|
@ -57,10 +58,17 @@ func (f *PhotoSearchGeo) ParseQueryString() error {
|
|||
|
||||
if f.Path == "" && f.Folder != "" {
|
||||
f.Path = f.Folder
|
||||
f.Folder = ""
|
||||
}
|
||||
|
||||
if f.Subjects == "" {
|
||||
if f.Subject == "" && f.Person != "" {
|
||||
f.Subject = f.Person
|
||||
f.Person = ""
|
||||
}
|
||||
|
||||
if f.Subjects == "" && f.People != "" {
|
||||
f.Subjects = f.People
|
||||
f.People = ""
|
||||
}
|
||||
|
||||
return err
|
||||
|
|
|
@ -19,6 +19,21 @@ func TestGeoSearch(t *testing.T) {
|
|||
|
||||
assert.Equal(t, "Jens Mander", form.Subjects)
|
||||
})
|
||||
t.Run("aliases", func(t *testing.T) {
|
||||
form := &PhotoSearchGeo{Query: "people:\"Jens & Mander\" folder:Foo person:Bar"}
|
||||
|
||||
err := form.ParseQueryString()
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, "", form.Folder)
|
||||
assert.Equal(t, "", form.Person)
|
||||
assert.Equal(t, "", form.People)
|
||||
assert.Equal(t, "Foo", form.Path)
|
||||
assert.Equal(t, "Bar", form.Subject)
|
||||
assert.Equal(t, "Jens & Mander", form.Subjects)
|
||||
})
|
||||
t.Run("keywords", func(t *testing.T) {
|
||||
form := &PhotoSearchGeo{Query: "keywords:\"Foo Bar\""}
|
||||
|
||||
|
@ -59,7 +74,7 @@ func TestGeoSearch(t *testing.T) {
|
|||
|
||||
assert.Equal(t, "fooBar baz", form.Query)
|
||||
assert.Equal(t, "test", form.Path)
|
||||
assert.Equal(t, "test", form.Folder)
|
||||
assert.Equal(t, "", form.Folder)
|
||||
assert.Equal(t, time.Date(2019, 01, 15, 0, 0, 0, 0, time.UTC), form.Before)
|
||||
assert.Equal(t, uint(0x61a8), form.Dist)
|
||||
assert.Equal(t, float32(33.45343), form.Lat)
|
||||
|
|
|
@ -25,6 +25,21 @@ func TestParseQueryString(t *testing.T) {
|
|||
|
||||
assert.Equal(t, "Jens & Mander", form.Subjects)
|
||||
})
|
||||
t.Run("aliases", func(t *testing.T) {
|
||||
form := &PhotoSearch{Query: "people:\"Jens & Mander\" folder:Foo person:Bar"}
|
||||
|
||||
err := form.ParseQueryString()
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, "", form.Folder)
|
||||
assert.Equal(t, "", form.Person)
|
||||
assert.Equal(t, "", form.People)
|
||||
assert.Equal(t, "Foo", form.Path)
|
||||
assert.Equal(t, "Bar", form.Subject)
|
||||
assert.Equal(t, "Jens & Mander", form.Subjects)
|
||||
})
|
||||
t.Run("keywords", func(t *testing.T) {
|
||||
form := &PhotoSearch{Query: "keywords:\"Foo Bar\""}
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/photoprism/photoprism/pkg/rnd"
|
||||
|
||||
"github.com/photoprism/photoprism/pkg/fs"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
|
@ -22,7 +24,7 @@ func Photos(f form.PhotoSearch) (results PhotoResults, count int, err error) {
|
|||
}
|
||||
|
||||
s := UnscopedDb()
|
||||
// s.LogMode(true)
|
||||
// s = s.LogMode(true)
|
||||
|
||||
// Base query.
|
||||
s = s.Table("photos").
|
||||
|
@ -233,8 +235,13 @@ func Photos(f form.PhotoSearch) (results PhotoResults, count int, err error) {
|
|||
// Filter for one or more subjects?
|
||||
if f.Subject != "" {
|
||||
for _, subj := range strings.Split(strings.ToLower(f.Subject), txt.And) {
|
||||
s = s.Where(fmt.Sprintf("photos.id IN (SELECT photo_id FROM files f JOIN %s m ON f.file_uid = m.file_uid AND m.marker_invalid = 0 WHERE subj_uid IN (?))",
|
||||
entity.Marker{}.TableName()), strings.Split(subj, txt.Or))
|
||||
if subjects := strings.Split(subj, txt.Or); rnd.ContainsUIDs(subjects, 'j') {
|
||||
s = s.Where(fmt.Sprintf("photos.id IN (SELECT photo_id FROM files f JOIN %s m ON f.file_uid = m.file_uid AND m.marker_invalid = 0 WHERE subj_uid IN (?))",
|
||||
entity.Marker{}.TableName()), subjects)
|
||||
} else {
|
||||
s = s.Where(fmt.Sprintf("photos.id IN (SELECT photo_id FROM files f JOIN %s m ON f.file_uid = m.file_uid AND m.marker_invalid = 0 JOIN %s s ON s.subj_uid = m.subj_uid WHERE (?))",
|
||||
entity.Marker{}.TableName(), entity.Subject{}.TableName()), gorm.Expr(AnySlug("s.subj_slug", subj, txt.Or)))
|
||||
}
|
||||
}
|
||||
} else if f.Subjects != "" {
|
||||
for _, where := range LikeAllNames(Cols{"subj_name", "subj_alias"}, f.Subjects) {
|
||||
|
|
|
@ -5,6 +5,8 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/photoprism/photoprism/pkg/rnd"
|
||||
|
||||
"github.com/photoprism/photoprism/pkg/fs"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
|
@ -123,11 +125,16 @@ func PhotosGeo(f form.PhotoSearchGeo) (results GeoResults, err error) {
|
|||
// Filter for one or more subjects?
|
||||
if f.Subject != "" {
|
||||
for _, subj := range strings.Split(strings.ToLower(f.Subject), txt.And) {
|
||||
s = s.Where(fmt.Sprintf("photos.id IN (SELECT photo_id FROM files f JOIN %s m ON f.file_uid = m.file_uid AND m.marker_invalid = 0 WHERE subj_uid IN (?))",
|
||||
entity.Marker{}.TableName()), strings.Split(subj, txt.Or))
|
||||
if subjects := strings.Split(subj, txt.Or); rnd.ContainsUIDs(subjects, 'j') {
|
||||
s = s.Where(fmt.Sprintf("photos.id IN (SELECT photo_id FROM files f JOIN %s m ON f.file_uid = m.file_uid AND m.marker_invalid = 0 WHERE subj_uid IN (?))",
|
||||
entity.Marker{}.TableName()), subjects)
|
||||
} else {
|
||||
s = s.Where(fmt.Sprintf("photos.id IN (SELECT photo_id FROM files f JOIN %s m ON f.file_uid = m.file_uid AND m.marker_invalid = 0 JOIN %s s ON s.subj_uid = m.subj_uid WHERE (?))",
|
||||
entity.Marker{}.TableName(), entity.Subject{}.TableName()), gorm.Expr(AnySlug("s.subj_slug", subj, txt.Or)))
|
||||
}
|
||||
}
|
||||
} else if f.Subjects != "" {
|
||||
for _, where := range LikeAnyWord("s.subj_name", f.Subjects) {
|
||||
for _, where := range LikeAllNames(Cols{"subj_name", "subj_alias"}, f.Subjects) {
|
||||
s = s.Where(fmt.Sprintf("photos.id IN (SELECT photo_id FROM files f JOIN %s m ON f.file_uid = m.file_uid AND m.marker_invalid = 0 JOIN %s s ON s.subj_uid = m.subj_uid WHERE (?))",
|
||||
entity.Marker{}.TableName(), entity.Subject{}.TableName()), gorm.Expr(where))
|
||||
}
|
||||
|
|
|
@ -72,3 +72,18 @@ func IsUID(s string, prefix byte) bool {
|
|||
|
||||
return IsPPID(s, prefix)
|
||||
}
|
||||
|
||||
// ContainsUIDs tests if a slice of strings contains UIDs only.
|
||||
func ContainsUIDs(s []string, prefix byte) bool {
|
||||
if len(s) < 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, id := range s {
|
||||
if !IsUID(id, prefix) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -57,6 +57,13 @@ func TestIsUID(t *testing.T) {
|
|||
assert.False(t, IsUID("", '_'))
|
||||
}
|
||||
|
||||
func TestContainsUIDs(t *testing.T) {
|
||||
assert.True(t, ContainsUIDs([]string{"lt9k3pw1wowuy3c2", "ltxk3pwawowuy0c0"}, 'l'))
|
||||
assert.True(t, ContainsUIDs([]string{"dafbfeb8-a129-4e7c-9cf0-e7996a701cdb"}, 'l'))
|
||||
assert.False(t, ContainsUIDs([]string{"_"}, '_'))
|
||||
assert.False(t, ContainsUIDs([]string{""}, '_'))
|
||||
}
|
||||
|
||||
func TestIsLowerAlnum(t *testing.T) {
|
||||
assert.False(t, IsLowerAlnum("dafbfeb8-a129-4e7c-9cf0-e7996a701cdb"))
|
||||
assert.True(t, IsLowerAlnum("dafbe7996a701cdb"))
|
||||
|
|
Loading…
Reference in a new issue