mirror of
https://github.com/photoprism/photoprism.git
synced 2026-01-23 02:24:24 +00:00
Backend: Sanitize metadata titles and descriptions
Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
parent
e7fecd3b27
commit
2b2cd8ed23
10 changed files with 108 additions and 14 deletions
3
Makefile
3
Makefile
|
|
@ -109,6 +109,9 @@ acceptance:
|
|||
acceptance-firefox:
|
||||
$(info Running JS acceptance tests in Firefox...)
|
||||
(cd frontend && npm run acceptance-firefox && cd ..)
|
||||
reset-photoprism-db:
|
||||
$(info Purging photoprism database...)
|
||||
mysql < scripts/reset-photoprism-db.sql
|
||||
reset-test-db:
|
||||
$(info Purging test databases...)
|
||||
mysql < scripts/reset-test-db.sql
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package entity
|
|||
import (
|
||||
"time"
|
||||
|
||||
"github.com/photoprism/photoprism/pkg/txt"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
|
|
@ -17,14 +18,14 @@ type Password struct {
|
|||
// NewPassword creates a new password instance.
|
||||
func NewPassword(uid, password string) Password {
|
||||
if uid == "" {
|
||||
panic("password: uid must not be empty")
|
||||
panic("auth: can't set password without uid")
|
||||
}
|
||||
|
||||
m := Password{UID: uid}
|
||||
|
||||
if password != "" {
|
||||
if err := m.SetPassword(password); err != nil {
|
||||
log.Errorf("password: %s (set password)", err)
|
||||
log.Errorf("auth: failed setting password for %s", uid)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -68,7 +69,7 @@ func FindPassword(uid string) *Password {
|
|||
if err := Db().Where("uid = ?", uid).First(&result).Error; err == nil {
|
||||
return &result
|
||||
} else {
|
||||
log.Errorf("password: %s (not found)", err)
|
||||
log.Errorf("auth: no password for %s", txt.Quote(uid))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/jinzhu/gorm"
|
||||
"github.com/photoprism/photoprism/internal/acl"
|
||||
"github.com/photoprism/photoprism/pkg/rnd"
|
||||
"github.com/photoprism/photoprism/pkg/txt"
|
||||
)
|
||||
|
||||
type People []Person
|
||||
|
|
@ -133,7 +134,7 @@ func FindPersonByUserName(userName string) *Person {
|
|||
if err := Db().Where("user_name = ?", userName).First(&result).Error; err == nil {
|
||||
return &result
|
||||
} else {
|
||||
log.Errorf("user: %s", err)
|
||||
log.Errorf("auth: user %s not found", txt.Quote(userName))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
@ -149,7 +150,7 @@ func FindPersonByUID(uid string) *Person {
|
|||
if err := Db().Where("person_uid = ?", uid).First(&result).Error; err == nil {
|
||||
return &result
|
||||
} else {
|
||||
log.Errorf("user: %s", err)
|
||||
log.Errorf("auth: user %s not found", txt.Quote(uid))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ type Data struct {
|
|||
Duration time.Duration `meta:"Duration,MediaDuration,TrackDuration"`
|
||||
Codec string `meta:"CompressorID,Compression,FileType"`
|
||||
Title string `meta:"Title"`
|
||||
Subject string `meta:"Subject,PersonInImage"`
|
||||
Subject string `meta:"Subject,PersonInImage,ObjectName"`
|
||||
Keywords string `meta:"Keywords"`
|
||||
Comment string `meta:"-"`
|
||||
Artist string `meta:"Artist,Creator"`
|
||||
|
|
|
|||
|
|
@ -342,7 +342,7 @@ func (data *Data) Exif(fileName string) (err error) {
|
|||
}
|
||||
|
||||
if value, ok := tags["ImageDescription"]; ok {
|
||||
data.Description = SanitizeString(value)
|
||||
data.Description = SanitizeDescription(value)
|
||||
}
|
||||
|
||||
data.All = tags
|
||||
|
|
|
|||
|
|
@ -187,5 +187,8 @@ func (data *Data) JSON(jsonName, originalName string) (err error) {
|
|||
data.InstanceID = SanitizeUID(data.InstanceID)
|
||||
}
|
||||
|
||||
data.Title = SanitizeTitle(data.Title)
|
||||
data.Description = SanitizeDescription(data.Description)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,16 @@
|
|||
package meta
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var DscTitleRegexp = regexp.MustCompile("\\D{3}[\\d_]\\d{4}(.JPG)?")
|
||||
|
||||
var UnwantedDescriptions = map[string]bool{
|
||||
"OLYMPUS DIGITAL CAMERA": true,
|
||||
}
|
||||
|
||||
// SanitizeString removes unwanted character from an exif value string.
|
||||
func SanitizeString(value string) string {
|
||||
value = strings.TrimSpace(value)
|
||||
|
|
@ -25,3 +32,25 @@ func SanitizeUID(value string) string {
|
|||
|
||||
return strings.ToLower(value)
|
||||
}
|
||||
|
||||
// SanitizeTitle normalizes titles and removes unwanted information.
|
||||
func SanitizeTitle(value string) string {
|
||||
value = SanitizeString(value)
|
||||
|
||||
if dsc := DscTitleRegexp.FindString(value); dsc == value {
|
||||
value = ""
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
// SanitizeDescription normalizes descriptions and removes unwanted information.
|
||||
func SanitizeDescription(value string) string {
|
||||
value = SanitizeString(value)
|
||||
|
||||
if remove := UnwantedDescriptions[value]; remove {
|
||||
value = ""
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
|
|
|||
55
internal/meta/sanitize_test.go
Normal file
55
internal/meta/sanitize_test.go
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
package meta
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestSanitizeTitle(t *testing.T) {
|
||||
t.Run("IMG_0599", func(t *testing.T) {
|
||||
result := SanitizeTitle("IMG_0599")
|
||||
|
||||
if result != "" {
|
||||
t.Fatal("result should be empty")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("IMG_0599.JPG", func(t *testing.T) {
|
||||
result := SanitizeTitle("IMG_0599.JPG")
|
||||
|
||||
if result != "" {
|
||||
t.Fatal("result should be empty")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("IMG_0599 ABC", func(t *testing.T) {
|
||||
result := SanitizeTitle("IMG_0599 ABC")
|
||||
|
||||
if result != "IMG_0599 ABC" {
|
||||
t.Fatal("result should be IMG_0599 ABC")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("DSC10599", func(t *testing.T) {
|
||||
result := SanitizeTitle("DSC10599")
|
||||
|
||||
if result != "" {
|
||||
t.Fatal("result should be empty")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestSanitizeDescription(t *testing.T) {
|
||||
t.Run("IMG_0599", func(t *testing.T) {
|
||||
result := SanitizeDescription("IMG_0599")
|
||||
|
||||
if result == "" {
|
||||
t.Fatal("result should not be empty")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("OLYMPUS DIGITAL CAMERA", func(t *testing.T) {
|
||||
result := SanitizeDescription("OLYMPUS DIGITAL CAMERA")
|
||||
|
||||
if result != "" {
|
||||
t.Fatal("result should be empty")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -203,29 +203,29 @@ func (doc *XmpDocument) Load(filename string) error {
|
|||
}
|
||||
|
||||
func (doc *XmpDocument) Title() string {
|
||||
return doc.RDF.Description.Title.Alt.Li.Text
|
||||
return SanitizeTitle(doc.RDF.Description.Title.Alt.Li.Text)
|
||||
}
|
||||
|
||||
func (doc *XmpDocument) Artist() string {
|
||||
return doc.RDF.Description.Creator.Seq.Li
|
||||
return SanitizeString(doc.RDF.Description.Creator.Seq.Li)
|
||||
}
|
||||
|
||||
func (doc *XmpDocument) Description() string {
|
||||
return doc.RDF.Description.Description.Alt.Li.Text
|
||||
return SanitizeDescription(doc.RDF.Description.Description.Alt.Li.Text)
|
||||
}
|
||||
|
||||
func (doc *XmpDocument) Copyright() string {
|
||||
return doc.RDF.Description.Rights.Alt.Li.Text
|
||||
return SanitizeString(doc.RDF.Description.Rights.Alt.Li.Text)
|
||||
}
|
||||
|
||||
func (doc *XmpDocument) CameraMake() string {
|
||||
return doc.RDF.Description.Make
|
||||
return SanitizeString(doc.RDF.Description.Make)
|
||||
}
|
||||
|
||||
func (doc *XmpDocument) CameraModel() string {
|
||||
return doc.RDF.Description.Model
|
||||
return SanitizeString(doc.RDF.Description.Model)
|
||||
}
|
||||
|
||||
func (doc *XmpDocument) LensModel() string {
|
||||
return doc.RDF.Description.LensModel
|
||||
return SanitizeString(doc.RDF.Description.LensModel)
|
||||
}
|
||||
|
|
|
|||
2
scripts/reset-photoprism-db.sql
Normal file
2
scripts/reset-photoprism-db.sql
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
DROP DATABASE IF EXISTS photoprism;
|
||||
CREATE DATABASE IF NOT EXISTS photoprism;
|
||||
Loading…
Add table
Add a link
Reference in a new issue