mirror of
https://github.com/photoprism/photoprism.git
synced 2025-12-12 00:34:13 +01:00
Index: Set labels based on matching keywords in title or subject #4602
Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
@@ -6,5 +6,7 @@ const (
|
||||
SrcManual = "manual"
|
||||
SrcLocation = "location"
|
||||
SrcImage = "image"
|
||||
SrcTitle = "title"
|
||||
SrcSubject = "subject"
|
||||
SrcKeyword = "keyword"
|
||||
)
|
||||
|
||||
@@ -34,10 +34,13 @@ func (l Labels) AppendLabel(label Label) Labels {
|
||||
return append(l, label)
|
||||
}
|
||||
|
||||
// Keywords returns all keywords contains in Labels and their categories
|
||||
// Keywords returns all keywords contained in Labels and their categories.
|
||||
func (l Labels) Keywords() (result []string) {
|
||||
for _, label := range l {
|
||||
if label.Uncertainty >= 100 || label.Source == SrcKeyword {
|
||||
if label.Uncertainty >= 100 ||
|
||||
label.Source == SrcTitle ||
|
||||
label.Source == SrcSubject ||
|
||||
label.Source == SrcKeyword {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
@@ -138,7 +138,10 @@ func RemovePhotoLabel(router *gin.RouterGroup) {
|
||||
return
|
||||
}
|
||||
|
||||
if label.LabelSrc == classify.SrcManual || label.LabelSrc == classify.SrcKeyword {
|
||||
if label.LabelSrc == classify.SrcManual ||
|
||||
label.LabelSrc == classify.SrcTitle ||
|
||||
label.LabelSrc == classify.SrcSubject ||
|
||||
label.LabelSrc == classify.SrcKeyword {
|
||||
logErr("label", entity.Db().Delete(&label).Error)
|
||||
} else {
|
||||
label.Uncertainty = 100
|
||||
|
||||
@@ -64,13 +64,13 @@ type Album struct {
|
||||
Photos PhotoAlbums `gorm:"foreignkey:AlbumUID;association_foreignkey:AlbumUID;" json:"-" yaml:"Photos,omitempty"`
|
||||
}
|
||||
|
||||
// AfterUpdate flushes the album cache.
|
||||
// AfterUpdate flushes the album cache when an album is updated.
|
||||
func (m *Album) AfterUpdate(tx *gorm.DB) (err error) {
|
||||
FlushAlbumCache()
|
||||
return
|
||||
}
|
||||
|
||||
// AfterDelete flushes the album cache when an album gets deleted.
|
||||
// AfterDelete flushes the album cache when an album is deleted.
|
||||
func (m *Album) AfterDelete(tx *gorm.DB) (err error) {
|
||||
FlushAlbumCache()
|
||||
return
|
||||
|
||||
@@ -17,7 +17,7 @@ func FlushAlbumCache() {
|
||||
albumCache.Flush()
|
||||
}
|
||||
|
||||
// CachedAlbumByUID returns an existing album or nil if not found.
|
||||
// CachedAlbumByUID returns an existing album or an error if not found.
|
||||
func CachedAlbumByUID(uid string) (m Album, err error) {
|
||||
// Valid album UID?
|
||||
if uid == "" || rnd.InvalidUID(uid, AlbumUID) {
|
||||
|
||||
@@ -150,7 +150,7 @@ func TestDetails_Create(t *testing.T) {
|
||||
|
||||
assert.Error(t, details.Create())
|
||||
})
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
details := Details{PhotoID: 1236799955432}
|
||||
|
||||
err := details.Create()
|
||||
@@ -163,7 +163,7 @@ func TestDetails_Create(t *testing.T) {
|
||||
|
||||
// TODO fails on mariadb
|
||||
func TestDetails_Save(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
details := Details{PhotoID: 123678955432, UpdatedAt: time.Date(2020, 2, 1, 0, 0, 0, 0, time.UTC)}
|
||||
initialDate := details.UpdatedAt
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
func TestAddDuplicate(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
if err := AddDuplicate(
|
||||
"foobar.jpg",
|
||||
RootOriginals,
|
||||
@@ -156,7 +156,7 @@ func TestSaveDuplicate(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDuplicate_Purge(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
if err := AddDuplicate(
|
||||
"forpurge.jpg",
|
||||
RootOriginals,
|
||||
|
||||
@@ -131,7 +131,7 @@ func TestFace_ReviseMatches(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNewFace(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
marker := MarkerFixtures.Get("1000003-4")
|
||||
e := marker.Embeddings()
|
||||
|
||||
@@ -165,7 +165,7 @@ func TestFace_Unsuitable(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFace_SetEmbeddings(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
marker := MarkerFixtures.Get("1000003-4")
|
||||
e := marker.Embeddings()
|
||||
m := FaceFixtures.Get("joe-biden")
|
||||
@@ -180,7 +180,7 @@ func TestFace_SetEmbeddings(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFace_Embedding(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
m := FaceFixtures.Get("joe-biden")
|
||||
|
||||
assert.Equal(t, 0.10730543085474682, m.Embedding()[0])
|
||||
|
||||
@@ -57,7 +57,7 @@ func TestFirstOrCreateFileShare(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFileShare_Updates(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
fileShare := NewFileShare(123, 123, "NameBeforeUpdate")
|
||||
|
||||
assert.Equal(t, "NameBeforeUpdate", fileShare.RemoteName)
|
||||
@@ -74,7 +74,7 @@ func TestFileShare_Updates(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFileShare_Update(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
fileShare := NewFileShare(123, 123, "NameBeforeUpdate2")
|
||||
assert.Equal(t, "NameBeforeUpdate2", fileShare.RemoteName)
|
||||
assert.Equal(t, uint(0x7b), fileShare.ServiceID)
|
||||
@@ -90,7 +90,7 @@ func TestFileShare_Update(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFileShare_Save(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
fileShare := NewFileShare(123, 123, "Nameavc")
|
||||
|
||||
initialDate := fileShare.UpdatedAt
|
||||
|
||||
@@ -56,7 +56,7 @@ func TestFirstOrCreateFileSync(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFileSync_Updates(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
fileSync := NewFileSync(123, "NameBeforeUpdate")
|
||||
|
||||
assert.Equal(t, "NameBeforeUpdate", fileSync.RemoteName)
|
||||
@@ -73,7 +73,7 @@ func TestFileSync_Updates(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFileSync_Update(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
fileSync := NewFileSync(123, "NameBeforeUpdate2")
|
||||
assert.Equal(t, "NameBeforeUpdate2", fileSync.RemoteName)
|
||||
assert.Equal(t, uint(0x7b), fileSync.ServiceID)
|
||||
@@ -89,7 +89,7 @@ func TestFileSync_Update(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFileSync_Save(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
fileSync := NewFileSync(123, "Nameavc")
|
||||
|
||||
initialDate := fileSync.UpdatedAt
|
||||
|
||||
@@ -156,7 +156,7 @@ func TestFile_Create(t *testing.T) {
|
||||
assert.Nil(t, file.Create())
|
||||
assert.Error(t, file.Create())
|
||||
})
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
photo := &Photo{TakenAtLocal: time.Date(2019, 01, 15, 0, 0, 0, 0, time.UTC), PhotoTitle: "Berlin / Morning Mood"}
|
||||
|
||||
file := &File{Photo: photo, FileType: "jpg", FileSize: 500, PhotoID: 766, FileName: "testname", FileRoot: "xyz"}
|
||||
@@ -170,14 +170,14 @@ func TestFile_Create(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFile_Purge(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
file := &File{Photo: nil, FileType: "jpg", FileSize: 500}
|
||||
assert.Equal(t, nil, file.Purge())
|
||||
})
|
||||
}
|
||||
|
||||
func TestFile_Found(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
file := &File{Photo: nil, FileType: "jpg", FileSize: 500}
|
||||
assert.Equal(t, nil, file.Purge())
|
||||
assert.Equal(t, true, file.FileMissing)
|
||||
@@ -216,7 +216,7 @@ func TestFile_Save(t *testing.T) {
|
||||
|
||||
assert.Equal(t, "file 123: cannot save file with empty photo id", err.Error())
|
||||
})
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
photo := &Photo{TakenAtLocal: time.Date(2019, 01, 15, 0, 0, 0, 0, time.UTC), PhotoTitle: "Berlin / Morning Mood"}
|
||||
|
||||
file := &File{Photo: photo, FileType: "jpg", FileSize: 500, PhotoID: 766, FileName: "Food", FileRoot: "", UpdatedAt: time.Date(2019, 01, 15, 0, 0, 0, 0, time.UTC)}
|
||||
@@ -230,7 +230,7 @@ func TestFile_Save(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFile_UpdateVideoInfos(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
file := &File{FileType: "jpg", FileWidth: 600, FileName: "VideoUpdate", PhotoID: 1000003}
|
||||
|
||||
assert.Equal(t, "1990/04/bridge2.mp4", FileFixturesExampleBridgeVideo.FileName)
|
||||
@@ -258,7 +258,7 @@ func TestFile_UpdateVideoInfos(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFile_Update(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
file := &File{FileType: "jpg", FileSize: 500, FileName: "ToBeUpdated", FileRoot: "", PhotoID: 5678}
|
||||
|
||||
err := file.Save()
|
||||
@@ -476,7 +476,7 @@ func TestFile_DownloadName(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFile_Undelete(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
file := &File{Photo: nil, FileType: "jpg", FileSize: 500}
|
||||
assert.Equal(t, nil, file.Purge())
|
||||
assert.Equal(t, true, file.FileMissing)
|
||||
@@ -554,7 +554,7 @@ func TestFile_ValidFaceCount(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFile_Rename(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
m := FileFixtures.Get("exampleFileName.jpg")
|
||||
|
||||
assert.Equal(t, "2790/07/27900704_070228_D6D51B6C.jpg", m.FileName)
|
||||
|
||||
@@ -160,7 +160,7 @@ func TestFindFolder(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFolder_Updates(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
folder := NewFolder("oldRoot", "oldPath", time.Now().UTC())
|
||||
|
||||
assert.Equal(t, "oldRoot", folder.Root)
|
||||
@@ -177,7 +177,7 @@ func TestFolder_Updates(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFolder_SetForm(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
formValues := Folder{FolderTitle: "Beautiful beach"}
|
||||
|
||||
folderForm, err := form.NewFolder(formValues)
|
||||
@@ -200,7 +200,7 @@ func TestFolder_SetForm(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFolder_Create(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
folder := Folder{FolderTitle: "Holiday 2020", Root: RootOriginals, Path: "2020/Greece"}
|
||||
err := folder.Create()
|
||||
if err != nil {
|
||||
|
||||
@@ -33,7 +33,7 @@ func TestFirstOrCreateKeyword(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestKeyword_Updates(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
keyword := NewKeyword("KeywordBeforeUpdate")
|
||||
|
||||
assert.Equal(t, "keywordbeforeupdate", keyword.Keyword)
|
||||
@@ -49,7 +49,7 @@ func TestKeyword_Updates(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestKeyword_Update(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
keyword := NewKeyword("KeywordBeforeUpdate2")
|
||||
assert.Equal(t, "keywordbeforeupdate2", keyword.Keyword)
|
||||
|
||||
@@ -64,7 +64,7 @@ func TestKeyword_Update(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestKeyword_Save(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
keyword := NewKeyword("KeywordName")
|
||||
|
||||
err := keyword.Save()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -50,6 +51,18 @@ func (Label) TableName() string {
|
||||
return "labels"
|
||||
}
|
||||
|
||||
// AfterUpdate flushes the label cache when a label is updated.
|
||||
func (m *Label) AfterUpdate(tx *gorm.DB) (err error) {
|
||||
FlushLabelCache()
|
||||
return
|
||||
}
|
||||
|
||||
// AfterDelete flushes the label cache when a label is deleted.
|
||||
func (m *Label) AfterDelete(tx *gorm.DB) (err error) {
|
||||
FlushLabelCache()
|
||||
return
|
||||
}
|
||||
|
||||
// BeforeCreate creates a random UID if needed before inserting a new row to the database.
|
||||
func (m *Label) BeforeCreate(scope *gorm.Scope) error {
|
||||
if rnd.IsUnique(m.LabelUID, LabelUID) {
|
||||
@@ -101,6 +114,7 @@ func (m *Label) Create() error {
|
||||
func (m *Label) Delete() error {
|
||||
Db().Where("label_id = ? OR category_id = ?", m.ID, m.ID).Delete(&Category{})
|
||||
Db().Where("label_id = ?", m.ID).Delete(&PhotoLabel{})
|
||||
FlushLabelCache()
|
||||
return Db().Delete(m).Error
|
||||
}
|
||||
|
||||
@@ -152,17 +166,35 @@ func FirstOrCreateLabel(m *Label) *Label {
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindLabel returns an existing row if exists.
|
||||
func FindLabel(s string) *Label {
|
||||
// FindLabel find the matching label based on the string provided or an error if not found.
|
||||
func FindLabel(s string, cached bool) (m Label, err error) {
|
||||
labelSlug := txt.Slug(s)
|
||||
|
||||
result := Label{}
|
||||
|
||||
if err := Db().Where("label_slug = ? OR custom_slug = ?", labelSlug, labelSlug).First(&result).Error; err == nil {
|
||||
return &result
|
||||
if labelSlug == "" {
|
||||
return m, fmt.Errorf("invalid label slug %s", clean.LogQuote(labelSlug))
|
||||
}
|
||||
|
||||
return nil
|
||||
// Return cached label, if found.
|
||||
if cached {
|
||||
if cacheData, ok := labelCache.Get(labelSlug); ok {
|
||||
log.Tracef("label: cache hit for %s", labelSlug)
|
||||
return cacheData.(Label), nil
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch and cache label from database.
|
||||
m = Label{}
|
||||
|
||||
if r := Db().First(&m, "label_slug = ? OR custom_slug = ?", labelSlug, labelSlug); r.RecordNotFound() {
|
||||
labelCache.Delete(labelSlug)
|
||||
return m, fmt.Errorf("label not found")
|
||||
} else if r.Error != nil {
|
||||
labelCache.Delete(labelSlug)
|
||||
return m, r.Error
|
||||
} else {
|
||||
labelCache.SetDefault(m.LabelSlug, m)
|
||||
return m, nil
|
||||
}
|
||||
}
|
||||
|
||||
// AfterCreate sets the New column used for database callback
|
||||
|
||||
14
internal/entity/label_cache.go
Normal file
14
internal/entity/label_cache.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
gc "github.com/patrickmn/go-cache"
|
||||
)
|
||||
|
||||
var labelCache = gc.New(15*time.Minute, 15*time.Minute)
|
||||
|
||||
// FlushLabelCache resets the label cache.
|
||||
func FlushLabelCache() {
|
||||
labelCache.Flush()
|
||||
}
|
||||
@@ -4,9 +4,9 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/ai/classify"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/ai/classify"
|
||||
)
|
||||
|
||||
func TestNewLabel(t *testing.T) {
|
||||
@@ -24,6 +24,12 @@ func TestNewLabel(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestFlushLabelCache(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
FlushLabelCache()
|
||||
})
|
||||
}
|
||||
|
||||
func TestLabel_SetName(t *testing.T) {
|
||||
t.Run("set name", func(t *testing.T) {
|
||||
entity := LabelFixtures["landscape"]
|
||||
@@ -135,7 +141,7 @@ func TestLabel_UpdateClassify(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLabel_Save(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
label := NewLabel("Unicorn2000", 5)
|
||||
initialDate := label.UpdatedAt
|
||||
err := label.Save()
|
||||
@@ -151,7 +157,7 @@ func TestLabel_Save(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLabel_Delete(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
label := NewLabel("LabelToBeDeleted", 5)
|
||||
err := label.Save()
|
||||
assert.False(t, label.Deleted())
|
||||
@@ -178,7 +184,7 @@ func TestLabel_Delete(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLabel_Restore(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
var deleteTime = time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
|
||||
label := &Label{DeletedAt: &deleteTime, LabelName: "ToBeRestored"}
|
||||
@@ -205,24 +211,31 @@ func TestLabel_Restore(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFindLabel(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("SaveAndFindWithCache", func(t *testing.T) {
|
||||
label := &Label{LabelSlug: "find-me-label", LabelName: "Find Me"}
|
||||
err := label.Save()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
saveErr := label.Save()
|
||||
if saveErr != nil {
|
||||
t.Fatal(saveErr)
|
||||
}
|
||||
r := FindLabel("find-me-label")
|
||||
assert.Equal(t, "Find Me", r.LabelName)
|
||||
uncached, findErr := FindLabel("find-me-label", false)
|
||||
assert.NoError(t, findErr)
|
||||
assert.Equal(t, "Find Me", uncached.LabelName)
|
||||
cached, cacheErr := FindLabel("find-me-label", true)
|
||||
assert.NoError(t, cacheErr)
|
||||
assert.Equal(t, "Find Me", cached.LabelName)
|
||||
assert.Equal(t, uncached.LabelSlug, cached.LabelSlug)
|
||||
assert.Equal(t, uncached.ID, cached.ID)
|
||||
assert.Equal(t, uncached.LabelUID, cached.LabelUID)
|
||||
})
|
||||
t.Run("nil", func(t *testing.T) {
|
||||
r := FindLabel("XXX")
|
||||
assert.Nil(t, r)
|
||||
t.Run("NotFound", func(t *testing.T) {
|
||||
r, err := FindLabel("XXX", true)
|
||||
assert.Error(t, err)
|
||||
assert.NotNil(t, r)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestLabel_Links(t *testing.T) {
|
||||
t.Run("1 result", func(t *testing.T) {
|
||||
t.Run("OneResult", func(t *testing.T) {
|
||||
label := LabelFixtures.Get("flower")
|
||||
links := label.Links()
|
||||
assert.Equal(t, "6jxf3jfn2k", links[0].LinkToken)
|
||||
@@ -230,7 +243,7 @@ func TestLabel_Links(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLabel_Update(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
label := &Label{LabelSlug: "to-be-updated", LabelName: "Update Me Please"}
|
||||
err := label.Save()
|
||||
if err != nil {
|
||||
|
||||
@@ -114,7 +114,7 @@ func TestLink_Save(t *testing.T) {
|
||||
|
||||
assert.Error(t, link.Save())
|
||||
})
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
link := NewLink("ls6sg6bffgtredft", false, false)
|
||||
|
||||
err := link.Save()
|
||||
@@ -126,7 +126,7 @@ func TestLink_Save(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLink_Delete(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
link := NewLink("ls6sg6bffgtreoft", false, false)
|
||||
|
||||
err := link.Delete()
|
||||
@@ -147,7 +147,7 @@ func TestLink_Delete(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFindLink(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
m := NewLink("ls6sg6bffgtrjoft", false, false)
|
||||
|
||||
link := &m
|
||||
@@ -194,14 +194,14 @@ func TestFindLinks(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFindValidLinksLinks(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
r := FindValidLinks("1jxf3jfn2k", "")
|
||||
assert.Equal(t, "as6sg6bxpogaaba8", r[0].ShareUID)
|
||||
})
|
||||
}
|
||||
|
||||
func TestLink_String(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
link := NewLink("jhgko", false, false)
|
||||
uid := link.LinkUID
|
||||
assert.Equal(t, uid, link.String())
|
||||
|
||||
@@ -144,7 +144,7 @@ func TestMarker_SaveForm(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUpdateOrCreateMarker(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
m := NewMarker(FileFixtures.Get("exampleFileName.jpg"), testArea, "ls6sg6b1wowuy3c3", SrcImage, MarkerLabel, 100, 65)
|
||||
assert.IsType(t, &Marker{}, m)
|
||||
assert.Equal(t, "fs6sg6bw45bnlqdw", m.FileUID)
|
||||
@@ -169,7 +169,7 @@ func TestUpdateOrCreateMarker(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMarker_Updates(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
m := NewMarker(FileFixtures.Get("exampleFileName.jpg"), testArea, "ls6sg6b1wowuy3c4", SrcImage, MarkerLabel, 100, 65)
|
||||
m, err := CreateMarkerIfNotExists(m)
|
||||
|
||||
@@ -194,7 +194,7 @@ func TestMarker_Updates(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMarker_Update(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
m := NewMarker(FileFixtures.Get("exampleFileName.jpg"), testArea, "ls6sg6b1wowuy3c4", SrcImage, MarkerLabel, 100, 65)
|
||||
m, err := CreateMarkerIfNotExists(m)
|
||||
|
||||
@@ -248,7 +248,7 @@ func TestMarker_InvalidArea(t *testing.T) {
|
||||
|
||||
// TODO fails on mariadb
|
||||
func TestMarker_Save(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
m := NewMarker(FileFixtures.Get("exampleFileName.jpg"), testArea, "ls6sg6b1wowuy3c4", SrcImage, MarkerLabel, 100, 65)
|
||||
|
||||
m, err := CreateMarkerIfNotExists(m)
|
||||
@@ -428,7 +428,7 @@ func TestMarker_Create(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMarker_Embeddings(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
m := MarkerFixtures.Get("1000003-4")
|
||||
|
||||
assert.Equal(t, 0.013083286379677253, m.Embeddings()[0][0])
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
func TestNewPassword(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
p := NewPassword("urrwaxd19ldtz68x", "passwd", false)
|
||||
assert.Len(t, p.Hash, 60)
|
||||
})
|
||||
@@ -102,7 +102,7 @@ func TestPassword_Invalid(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPassword_Create(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
p := Password{}
|
||||
|
||||
err := p.Create()
|
||||
|
||||
@@ -181,8 +181,8 @@ func SavePhotoForm(model Photo, form form.Photo) error {
|
||||
details.Keywords = strings.Join(txt.UniqueWords(w), ", ")
|
||||
}
|
||||
|
||||
if err := model.SyncKeywordLabels(); err != nil {
|
||||
log.Errorf("photo: %s %s while syncing keywords and labels", model.String(), err)
|
||||
if err := model.UpdateLabels(); err != nil {
|
||||
log.Errorf("photo: %s %s while updating labels", model.String(), err)
|
||||
}
|
||||
|
||||
if err := model.UpdateTitle(model.ClassifyLabels()); err != nil {
|
||||
@@ -446,15 +446,97 @@ func (m *Photo) RemoveKeyword(w string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SyncKeywordLabels maintains the label / photo relationship for existing labels and keywords.
|
||||
func (m *Photo) SyncKeywordLabels() error {
|
||||
// UpdateLabels updates labels that are automatically set based on the photo title, subject, and keywords.
|
||||
func (m *Photo) UpdateLabels() error {
|
||||
if err := m.UpdateTitleLabels(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := m.UpdateSubjectLabels(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := m.UpdateKeywordLabels(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateTitleLabels updates the labels assigned based on the photo title.
|
||||
func (m *Photo) UpdateTitleLabels() error {
|
||||
if m == nil {
|
||||
return nil
|
||||
} else if m.PhotoTitle == "" {
|
||||
return nil
|
||||
} else if SrcPriority[m.TitleSrc] < SrcPriority[SrcName] {
|
||||
return nil
|
||||
}
|
||||
|
||||
keywords := txt.UniqueKeywords(m.PhotoTitle)
|
||||
|
||||
var labelIds []uint
|
||||
|
||||
for _, w := range keywords {
|
||||
if label, err := FindLabel(w, true); err == nil {
|
||||
if label.Deleted() {
|
||||
continue
|
||||
}
|
||||
|
||||
labelIds = append(labelIds, label.ID)
|
||||
FirstOrCreatePhotoLabel(NewPhotoLabel(m.ID, label.ID, 10, classify.SrcTitle))
|
||||
}
|
||||
}
|
||||
|
||||
return Db().Where("label_src = ? AND photo_id = ? AND label_id NOT IN (?)", classify.SrcTitle, m.ID, labelIds).Delete(&PhotoLabel{}).Error
|
||||
}
|
||||
|
||||
// UpdateSubjectLabels updates the labels assigned based on photo subject metadata.
|
||||
func (m *Photo) UpdateSubjectLabels() error {
|
||||
details := m.GetDetails()
|
||||
|
||||
if details == nil {
|
||||
return nil
|
||||
} else if details.Subject == "" {
|
||||
return nil
|
||||
} else if SrcPriority[details.SubjectSrc] < SrcPriority[SrcName] {
|
||||
return nil
|
||||
}
|
||||
|
||||
keywords := txt.UniqueKeywords(details.Subject)
|
||||
|
||||
var labelIds []uint
|
||||
|
||||
for _, w := range keywords {
|
||||
if label, err := FindLabel(w, true); err == nil {
|
||||
if label.Deleted() {
|
||||
continue
|
||||
}
|
||||
|
||||
labelIds = append(labelIds, label.ID)
|
||||
FirstOrCreatePhotoLabel(NewPhotoLabel(m.ID, label.ID, 15, classify.SrcSubject))
|
||||
}
|
||||
}
|
||||
|
||||
return Db().Where("label_src = ? AND photo_id = ? AND label_id NOT IN (?)", classify.SrcSubject, m.ID, labelIds).Delete(&PhotoLabel{}).Error
|
||||
}
|
||||
|
||||
// UpdateKeywordLabels updates the labels assigned based on photo keyword metadata.
|
||||
func (m *Photo) UpdateKeywordLabels() error {
|
||||
details := m.GetDetails()
|
||||
|
||||
if details == nil {
|
||||
return nil
|
||||
} else if details.Keywords == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
keywords := txt.UniqueKeywords(details.Keywords)
|
||||
|
||||
var labelIds []uint
|
||||
|
||||
for _, w := range keywords {
|
||||
if label := FindLabel(w); label != nil {
|
||||
if label, err := FindLabel(w, true); err == nil {
|
||||
if label.Deleted() {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ func TestFirstOrCreatePhotoAlbum(t *testing.T) {
|
||||
|
||||
// TODO fails on mariadb
|
||||
func TestPhotoAlbum_Save(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
p := PhotoAlbum{}
|
||||
|
||||
err := p.Create()
|
||||
|
||||
@@ -41,7 +41,7 @@ func TestFirstOrCreatePhotoLabel(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPhotoLabel_ClassifyLabel(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
pl := LabelFixtures.PhotoLabel(1000000, "flower", 38, "image")
|
||||
r := pl.ClassifyLabel()
|
||||
assert.Equal(t, "Flower", r.Name)
|
||||
@@ -57,7 +57,7 @@ func TestPhotoLabel_ClassifyLabel(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPhotoLabel_Save(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
photoLabel := NewPhotoLabel(13, 1000, 99, "image")
|
||||
err := photoLabel.Save()
|
||||
if err != nil {
|
||||
@@ -78,7 +78,7 @@ func TestPhotoLabel_Save(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPhotoLabel_Update(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
photoLabel := PhotoLabel{LabelID: 555, PhotoID: 888}
|
||||
assert.Equal(t, uint(0x22b), photoLabel.LabelID)
|
||||
|
||||
|
||||
@@ -454,8 +454,8 @@ func (m *Photo) SaveLocation() error {
|
||||
|
||||
m.GetDetails().Keywords = strings.Join(txt.UniqueWords(w), ", ")
|
||||
|
||||
if err := m.SyncKeywordLabels(); err != nil {
|
||||
log.Errorf("photo: %s %s while syncing keywords and labels", m.String(), err)
|
||||
if err := m.UpdateKeywordLabels(); err != nil {
|
||||
log.Errorf("photo: %s %s while updating keyword labels", m.String(), err)
|
||||
}
|
||||
|
||||
if err := m.UpdateTitle(m.ClassifyLabels()); err != nil {
|
||||
|
||||
@@ -35,7 +35,7 @@ func TestPhoto_Stackable(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPhoto_IdenticalIdentical(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
photo := PhotoFixtures.Get("Photo19")
|
||||
|
||||
result, err := photo.Identical(true, true)
|
||||
@@ -58,7 +58,7 @@ func TestPhoto_IdenticalIdentical(t *testing.T) {
|
||||
}
|
||||
assert.Equal(t, 0, len(result))
|
||||
})
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
photo := PhotoFixtures.Get("Photo23")
|
||||
|
||||
result, err := photo.Identical(true, true)
|
||||
@@ -70,7 +70,7 @@ func TestPhoto_IdenticalIdentical(t *testing.T) {
|
||||
t.Logf("result: %#v", result)
|
||||
assert.Equal(t, 2, len(result))
|
||||
})
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
photo := PhotoFixtures.Get("Photo23")
|
||||
result, err := photo.Identical(true, false)
|
||||
|
||||
@@ -84,7 +84,7 @@ func TestPhoto_IdenticalIdentical(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPhoto_Merge(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
photo := PhotoFixtures.Get("Photo23")
|
||||
original, merged, err := photo.Merge(true, false)
|
||||
|
||||
|
||||
@@ -430,24 +430,29 @@ func TestPhoto_RemoveKeyword(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestPhoto_SyncKeywordLabels(t *testing.T) {
|
||||
t.Run("Ok", func(t *testing.T) {
|
||||
labelotter := Label{LabelName: "otter", LabelSlug: "otter"}
|
||||
func TestPhoto_UpdateLabels(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
labelNative := Label{LabelName: "Native", LabelSlug: "native"}
|
||||
var deletedTime = time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
labelsnake := Label{LabelName: "snake", LabelSlug: "snake", DeletedAt: &deletedTime}
|
||||
labelWindow := Label{LabelName: "Window", LabelSlug: "window", DeletedAt: &deletedTime}
|
||||
|
||||
err := labelsnake.Save()
|
||||
err := labelWindow.Save()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = labelotter.Save()
|
||||
err = labelNative.Save()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
details := &Details{Keywords: "cow, flower, snake, otter"}
|
||||
photo := Photo{ID: 34567, Details: details}
|
||||
details := &Details{
|
||||
Subject: "native",
|
||||
SubjectSrc: SrcMeta,
|
||||
Keywords: "cow, flower, snake, otter",
|
||||
KeywordsSrc: SrcMeta,
|
||||
}
|
||||
photo := Photo{ID: 134567, PhotoTitle: "Cat in the House", Details: details}
|
||||
|
||||
err = photo.Save()
|
||||
if err != nil {
|
||||
@@ -458,7 +463,7 @@ func TestPhoto_SyncKeywordLabels(t *testing.T) {
|
||||
|
||||
assert.Equal(t, 0, len(p.Labels))
|
||||
|
||||
err = p.SyncKeywordLabels()
|
||||
err = p.UpdateLabels()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -470,6 +475,133 @@ func TestPhoto_SyncKeywordLabels(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestPhoto_UpdateTitleLabels(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
labelFood := Label{LabelName: "Food", LabelSlug: "food"}
|
||||
labelWine := Label{LabelName: "Wine", LabelSlug: "wine"}
|
||||
labelBar := Label{LabelName: "Bar", LabelSlug: "bar", DeletedAt: TimeStamp()}
|
||||
|
||||
err := labelFood.Save()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = labelWine.Save()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = labelBar.Save()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
details := &Details{Keywords: "snake, otter, food", KeywordsSrc: SrcMeta}
|
||||
photo := Photo{ID: 234567, PhotoTitle: "I was in a nice Wine Bar!", TitleSrc: SrcName, PhotoDescription: "cow, flower, food", DescriptionSrc: SrcMeta, Details: details}
|
||||
|
||||
err = photo.Save()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
p := FindPhoto(photo)
|
||||
|
||||
assert.Equal(t, 0, len(p.Labels))
|
||||
|
||||
err = p.UpdateTitleLabels()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
p = FindPhoto(*p)
|
||||
|
||||
assert.Equal(t, "I was in a nice Wine Bar!", p.PhotoTitle)
|
||||
assert.Equal(t, "cow, flower, food", p.PhotoDescription)
|
||||
assert.Equal(t, "snake, otter, food", p.Details.Keywords)
|
||||
assert.Equal(t, 1, len(p.Labels))
|
||||
})
|
||||
}
|
||||
|
||||
func TestPhoto_UpdateSubjectLabels(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
labelEgg := Label{LabelName: "Egg", LabelSlug: "egg"}
|
||||
var deletedTime = time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
labelBird := Label{LabelName: "Bird", LabelSlug: "bird", DeletedAt: &deletedTime}
|
||||
|
||||
err := labelBird.Save()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = labelEgg.Save()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
details := &Details{Subject: "cow, egg, bird", SubjectSrc: SrcMeta}
|
||||
photo := Photo{ID: 334567, TitleSrc: SrcName, Details: details}
|
||||
|
||||
err = photo.Save()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
p := FindPhoto(photo)
|
||||
|
||||
assert.Equal(t, 0, len(p.Labels))
|
||||
|
||||
err = p.UpdateSubjectLabels()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
p = FindPhoto(*p)
|
||||
|
||||
assert.Equal(t, "cow, egg, bird", p.Details.Subject)
|
||||
assert.Equal(t, 2, len(p.Labels))
|
||||
})
|
||||
}
|
||||
|
||||
func TestPhoto_UpdateKeywordLabels(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
labelOtter := Label{LabelName: "Otter", LabelSlug: "otter"}
|
||||
var deletedTime = time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
labelSnake := Label{LabelName: "Snake", LabelSlug: "snake", DeletedAt: &deletedTime}
|
||||
|
||||
err := labelSnake.Save()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = labelOtter.Save()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
details := &Details{Keywords: "cow, flower, snake, otter", KeywordsSrc: SrcAuto}
|
||||
photo := Photo{ID: 434567, Details: details}
|
||||
|
||||
err = photo.Save()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
p := FindPhoto(photo)
|
||||
|
||||
assert.Equal(t, 0, len(p.Labels))
|
||||
|
||||
err = p.UpdateKeywordLabels()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
p = FindPhoto(*p)
|
||||
|
||||
assert.Equal(t, "cow, flower, snake, otter", p.Details.Keywords)
|
||||
assert.Equal(t, 3, len(p.Labels))
|
||||
})
|
||||
}
|
||||
|
||||
func TestPhoto_LocationLoaded(t *testing.T) {
|
||||
t.Run("Photo", func(t *testing.T) {
|
||||
photo := Photo{PhotoUID: "56798", PhotoName: "Holiday", OriginalName: "holidayOriginal2"}
|
||||
|
||||
@@ -42,7 +42,7 @@ func TestPhoto_SetTitle(t *testing.T) {
|
||||
m.SetTitle("NewTitleSet", SrcAuto)
|
||||
assert.Equal(t, "TitleToBeSet", m.PhotoTitle)
|
||||
})
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
m := PhotoFixtures.Get("Photo15")
|
||||
assert.Equal(t, "TitleToBeSet", m.PhotoTitle)
|
||||
m.SetTitle("NewTitleSet", SrcName)
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
// TODO find duplicates
|
||||
func TestDuplicates(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
if files, err := Duplicates(10, 0, ""); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if files == nil {
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
func TestSetDownloadFileID(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
err := SetDownloadFileID("exampleFileName.jpg", 1000000)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
func TestFileSyncs(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
r, err := FileSyncs(uint(1000001), "downloaded", 10)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -194,7 +194,7 @@ func TestFileByHash(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSetPhotoPrimary(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
assert.Equal(t, false, entity.FileFixturesExampleXMP.FilePrimary)
|
||||
|
||||
err := SetPhotoPrimary("ps6sg6be2lvl0yh7", "fs6sg6bwhhbnlqdn")
|
||||
@@ -244,7 +244,7 @@ func TestRenameFile(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
assert.Equal(t, "2790/02/Photo01.xmp", entity.FileFixturesExampleXMP.FileName)
|
||||
assert.Equal(t, "/", entity.FileFixturesExampleXMP.FileRoot)
|
||||
err := RenameFile("/", "exampleXmpFile.xmp", "test-root", "yyy.jpg")
|
||||
|
||||
@@ -68,7 +68,7 @@ func TestAlbumFolders(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUpdateFolderDates(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
if err := UpdateFolderDates(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ func TestOrphanPhotos(t *testing.T) {
|
||||
|
||||
// TODO How to verify?
|
||||
func TestFixPrimaries(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
err := FixPrimaries()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
)
|
||||
|
||||
func TestCellIDs(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
result, err := CellIDs()
|
||||
|
||||
if err != nil {
|
||||
@@ -16,7 +16,7 @@ func TestCellIDs(t *testing.T) {
|
||||
})
|
||||
}
|
||||
func TestPurgePlaces(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
if err := PurgePlaces(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
func TestRegisteredUsers(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
users := RegisteredUsers()
|
||||
|
||||
for _, user := range users {
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
func TestCreateService(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
account := Service{AccName: "Foo", AccOwner: "bar", AccURL: "test.com", AccType: "webdav", AccKey: "123", AccUser: "testuser", AccPass: "testpass",
|
||||
AccError: "", AccShare: true, AccSync: true, RetryLimit: 4, SharePath: "/home", ShareSize: "500", ShareExpires: 3500, SyncPath: "/sync",
|
||||
SyncInterval: 5, SyncUpload: true, SyncDownload: false, SyncFilenames: true, SyncRaw: false}
|
||||
@@ -50,7 +50,7 @@ func TestCreateService(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestService_SaveForm(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
account := Service{AccName: "Foo", AccOwner: "bar", AccURL: "test.com", AccType: "test", AccKey: "123", AccUser: "testuser", AccPass: "testpass",
|
||||
AccError: "", AccShare: true, AccSync: true, RetryLimit: 4, SharePath: "/home", ShareSize: "500", ShareExpires: 3500, SyncPath: "/sync",
|
||||
SyncInterval: 5, SyncUpload: true, SyncDownload: true, SyncFilenames: true, SyncRaw: false}
|
||||
@@ -94,7 +94,7 @@ func TestService_SaveForm(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestService_Delete(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
account := Service{AccName: "DeleteAccount", AccOwner: "Delete", AccURL: "test.com", AccType: "test", AccKey: "123", AccUser: "testuser", AccPass: "testpass",
|
||||
AccError: "", AccShare: true, AccSync: true, RetryLimit: 4, SharePath: "/home", ShareSize: "500", ShareExpires: 3500, SyncPath: "/sync",
|
||||
SyncInterval: 5, SyncUpload: true, SyncDownload: false, SyncFilenames: true, SyncRaw: false}
|
||||
@@ -121,7 +121,7 @@ func TestService_Delete(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestService_Directories(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
account := Service{AccName: "DirectoriesAccount", AccOwner: "Owner", AccURL: "http://dummy-webdav/", AccType: "webdav", AccKey: "123", AccUser: "admin", AccPass: "photoprism",
|
||||
AccError: "", AccShare: true, AccSync: true, RetryLimit: 4, SharePath: "/home", ShareSize: "500", ShareExpires: 3500, SyncPath: "/sync",
|
||||
SyncInterval: 5, SyncUpload: true, SyncDownload: false, SyncFilenames: true, SyncRaw: false}
|
||||
@@ -173,7 +173,7 @@ func TestService_Directories(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestService_Updates(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
account := Service{AccName: "DeleteAccount", AccOwner: "Delete", AccURL: "test.com", AccType: "test", AccKey: "123", AccUser: "testuser", AccPass: "testpass",
|
||||
AccError: "", AccShare: true, AccSync: true, RetryLimit: 4, SharePath: "/home", ShareSize: "500", ShareExpires: 3500, SyncPath: "/sync",
|
||||
SyncInterval: 5, SyncUpload: true, SyncDownload: false, SyncFilenames: true, SyncRaw: false}
|
||||
@@ -203,7 +203,7 @@ func TestService_Updates(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestService_Update(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
account := Service{AccName: "DeleteAccount", AccOwner: "Delete", AccURL: "test.com", AccType: "test", AccKey: "123", AccUser: "testuser", AccPass: "testpass",
|
||||
AccError: "", AccShare: true, AccSync: true, RetryLimit: 4, SharePath: "/home", ShareSize: "500", ShareExpires: 3500, SyncPath: "/sync",
|
||||
SyncInterval: 5, SyncUpload: true, SyncDownload: false, SyncFilenames: true, SyncRaw: false}
|
||||
@@ -231,7 +231,7 @@ func TestService_Update(t *testing.T) {
|
||||
|
||||
// TODO fails on mariadb
|
||||
func TestService_Save(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
account := Service{AccName: "DeleteAccount", AccOwner: "Delete", AccURL: "test.com", AccType: "test", AccKey: "123", AccUser: "testuser", AccPass: "testpass",
|
||||
AccError: "", AccShare: true, AccSync: true, RetryLimit: 4, SharePath: "/home", ShareSize: "500", ShareExpires: 3500, SyncPath: "/sync",
|
||||
SyncInterval: 5, SyncUpload: true, SyncDownload: false, SyncFilenames: true, SyncRaw: false}
|
||||
@@ -259,7 +259,7 @@ func TestService_Save(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestService_Create(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
account := Service{}
|
||||
|
||||
err := account.Create()
|
||||
|
||||
@@ -16,6 +16,8 @@ const (
|
||||
SrcLocation = classify.SrcLocation // Prio 8
|
||||
SrcMarker = "marker" // Prio 8
|
||||
SrcImage = classify.SrcImage // Prio 8
|
||||
SrcTitle = classify.SrcTitle // Prio 16
|
||||
SrcSubject = classify.SrcSubject // Prio 16
|
||||
SrcKeyword = classify.SrcKeyword // Prio 16
|
||||
SrcMeta = "meta" // Prio 16
|
||||
SrcXmp = "xmp" // Prio 32
|
||||
@@ -44,6 +46,8 @@ var SrcPriority = Priorities{
|
||||
SrcLocation: 8,
|
||||
SrcMarker: 8,
|
||||
SrcImage: 8,
|
||||
SrcTitle: 16,
|
||||
SrcSubject: 16,
|
||||
SrcKeyword: 16,
|
||||
SrcMeta: 16,
|
||||
SrcXmp: 32,
|
||||
|
||||
@@ -911,8 +911,8 @@ func (ind *Index) UserMediaFile(m *MediaFile, o IndexOptions, originalName, phot
|
||||
return result
|
||||
}
|
||||
|
||||
if err = photo.SyncKeywordLabels(); err != nil {
|
||||
log.Errorf("index: %s in %s (sync keywords and labels)", err, logName)
|
||||
if err = photo.UpdateLabels(); err != nil {
|
||||
log.Errorf("index: %s in %s (update labels)", err, logName)
|
||||
}
|
||||
|
||||
if err = photo.IndexKeywords(); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user