Fix gorm relations; make most SQL more generic

This commit is contained in:
Florian Albrecht
2024-06-28 20:14:29 +02:00
parent 5f1c69348e
commit 05dc86d11f
76 changed files with 624 additions and 508 deletions

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-03-22 14:48+0000\n" "POT-Creation-Date: 2024-06-23 17:25+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"

7
go.mod
View File

@@ -79,7 +79,7 @@ require (
github.com/pquerna/otp v1.4.0 github.com/pquerna/otp v1.4.0
gorm.io/driver/mysql v1.5.6 gorm.io/driver/mysql v1.5.6
gorm.io/driver/sqlite v1.5.5 gorm.io/driver/sqlite v1.5.5
gorm.io/gorm v1.25.9 gorm.io/gorm v1.25.10
) )
require ( require (
@@ -98,6 +98,10 @@ require (
github.com/go-sql-driver/mysql v1.7.1 // indirect github.com/go-sql-driver/mysql v1.7.1 // indirect
github.com/goccy/go-json v0.10.2 // indirect github.com/goccy/go-json v0.10.2 // indirect
github.com/gosimple/unidecode v1.0.1 // indirect github.com/gosimple/unidecode v1.0.1 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.5.5 // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/jinzhu/now v1.1.5 // indirect github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/leodido/go-urn v1.4.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect
@@ -117,6 +121,7 @@ require (
golang.org/x/sys v0.19.0 // indirect golang.org/x/sys v0.19.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
gorm.io/driver/postgres v1.5.9 // indirect
) )
require ( require (

12
go.sum
View File

@@ -188,6 +188,14 @@ github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOn
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jdeng/goheif v0.0.0-20200323230657-a0d6a8b3e68f/go.mod h1:G7IyA3/eR9IFmUIPdyP3c0l4ZaqEvXAk876WfaQ8plc= github.com/jdeng/goheif v0.0.0-20200323230657-a0d6a8b3e68f/go.mod h1:G7IyA3/eR9IFmUIPdyP3c0l4ZaqEvXAk876WfaQ8plc=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
@@ -550,11 +558,15 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.5.6 h1:Ld4mkIickM+EliaQZQx3uOJDJHtrd70MxAUqWqlx3Y8= gorm.io/driver/mysql v1.5.6 h1:Ld4mkIickM+EliaQZQx3uOJDJHtrd70MxAUqWqlx3Y8=
gorm.io/driver/mysql v1.5.6/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= gorm.io/driver/mysql v1.5.6/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
gorm.io/driver/postgres v1.5.9 h1:DkegyItji119OlcaLjqN11kHoUgZ/j13E0jkJZgD6A8=
gorm.io/driver/postgres v1.5.9/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI=
gorm.io/driver/sqlite v1.5.5 h1:7MDMtUZhV065SilG62E0MquljeArQZNfJnjd9i9gx3E= gorm.io/driver/sqlite v1.5.5 h1:7MDMtUZhV065SilG62E0MquljeArQZNfJnjd9i9gx3E=
gorm.io/driver/sqlite v1.5.5/go.mod h1:6NgQ7sQWAIFsPrJJl1lSNSu2TABh0ZZ/zm5fosATavE= gorm.io/driver/sqlite v1.5.5/go.mod h1:6NgQ7sQWAIFsPrJJl1lSNSu2TABh0ZZ/zm5fosATavE=
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
gorm.io/gorm v1.25.9 h1:wct0gxZIELDk8+ZqF/MVnHLkA1rvYlBWUMv2EdsK1g8= gorm.io/gorm v1.25.9 h1:wct0gxZIELDk8+ZqF/MVnHLkA1rvYlBWUMv2EdsK1g8=
gorm.io/gorm v1.25.9/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= gorm.io/gorm v1.25.9/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s=
gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@@ -146,7 +146,7 @@ func PhotoUnstack(router *gin.RouterGroup) {
} }
if err := entity.UnscopedDb().Exec(`UPDATE files if err := entity.UnscopedDb().Exec(`UPDATE files
SET photo_id = ?, photo_uid = ?, file_name = ?, file_missing = 0 SET photo_id = ?, photo_uid = ?, file_name = ?, file_missing = FALSE
WHERE file_name = ? AND file_root = ?`, WHERE file_name = ? AND file_root = ?`,
newPhoto.ID, newPhoto.PhotoUID, r.RootRelName(), newPhoto.ID, newPhoto.PhotoUID, r.RootRelName(),
relName, relRoot).Error; err != nil { relName, relRoot).Error; err != nil {

View File

@@ -523,27 +523,27 @@ func (c *Config) ClientUser(withSettings bool) ClientConfig {
if hidePrivate { if hidePrivate {
c.Db(). c.Db().
Table("photos"). Table("photos").
Select("SUM(photo_type = 'video' AND photo_quality > -1 AND photo_private = 0) AS videos, " + Select("COUNT(CASE WHEN photo_type = 'video' AND photo_quality > -1 AND photo_private = FALSE THEN 1 END) AS videos, " +
"SUM(photo_type = 'live' AND photo_quality > -1 AND photo_private = 0) AS live, " + "COUNT(CASE WHEN photo_type = 'live' AND photo_quality > -1 AND photo_private = FALSE THEN 1 END) AS live, " +
"SUM(photo_quality = -1) AS hidden, " + "COUNT(CASE WHEN photo_quality = -1 THEN 1 END) AS hidden, " +
"SUM(photo_type NOT IN ('live', 'video') AND photo_quality > -1 AND photo_private = 0) AS photos, " + "COUNT(CASE WHEN photo_type NOT IN ('live', 'video') AND photo_quality > -1 AND photo_private = FALSE THEN 1 END) AS photos, " +
"SUM(photo_quality BETWEEN 0 AND 2) AS review, " + "COUNT(CASE WHEN photo_quality BETWEEN 0 AND 2 THEN 1 END) AS review, " +
"SUM(photo_favorite = 1 AND photo_private = 0 AND photo_quality > -1) AS favorites, " + "COUNT(CASE WHEN photo_favorite = TRUE AND photo_private = FALSE AND photo_quality > -1 THEN 1 END) AS favorites, " +
"SUM(photo_private = 1 AND photo_quality > -1) AS private"). "COUNT(CASE WHEN photo_private = TRUE AND photo_quality > -1 THEN 1 END) AS private").
Where("photos.id NOT IN (SELECT photo_id FROM files WHERE file_primary = 1 AND (file_missing = 1 OR file_error <> ''))"). Where("photos.id NOT IN (SELECT photo_id FROM files WHERE file_primary = TRUE AND (file_missing = TRUE OR file_error <> ''))").
Where("deleted_at IS NULL"). Where("deleted_at IS NULL").
Take(&cfg.Count) Take(&cfg.Count)
} else { } else {
c.Db(). c.Db().
Table("photos"). Table("photos").
Select("SUM(photo_type = 'video' AND photo_quality > -1) AS videos, " + Select("COUNT(CASE WHEN photo_type = 'video' AND photo_quality > -1 THEN 1 END) AS videos, " +
"SUM(photo_type = 'live' AND photo_quality > -1) AS live, " + "COUNT(CASE WHEN photo_type = 'live' AND photo_quality > -1 THEN 1 END) AS live, " +
"SUM(photo_quality = -1) AS hidden, " + "COUNT(CASE WHEN photo_quality = -1 THEN 1 END) AS hidden, " +
"SUM(photo_type NOT IN ('live', 'video') AND photo_quality > -1) AS photos, " + "COUNT(CASE WHEN photo_type NOT IN ('live', 'video') AND photo_quality > -1 THEN 1 END) AS photos, " +
"SUM(photo_quality BETWEEN 0 AND 2) AS review, " + "COUNT(CASE WHEN photo_quality BETWEEN 0 AND 2 THEN 1 END) AS review, " +
"SUM(photo_favorite = 1 AND photo_quality > -1) AS favorites, " + "COUNT(CASE WHEN photo_favorite = TRUE AND photo_quality > -1 THEN 1 END) AS favorites, " +
"0 AS private"). "0 AS private").
Where("photos.id NOT IN (SELECT photo_id FROM files WHERE file_primary = 1 AND (file_missing = 1 OR file_error <> ''))"). Where("photos.id NOT IN (SELECT photo_id FROM files WHERE file_primary = TRUE AND (file_missing = TRUE OR file_error <> ''))").
Where("deleted_at IS NULL"). Where("deleted_at IS NULL").
Take(&cfg.Count) Take(&cfg.Count)
} }
@@ -552,7 +552,7 @@ func (c *Config) ClientUser(withSettings bool) ClientConfig {
if c.Settings().Features.Archive { if c.Settings().Features.Archive {
c.Db(). c.Db().
Table("photos"). Table("photos").
Select("SUM(photo_quality > -1) AS archived"). Select("COUNT(CASE WHEN photo_quality > -1 THEN 1 END) AS archived").
Where("deleted_at IS NOT NULL"). Where("deleted_at IS NOT NULL").
Take(&cfg.Count) Take(&cfg.Count)
} }
@@ -570,34 +570,34 @@ func (c *Config) ClientUser(withSettings bool) ClientConfig {
Select("MAX(photo_count) AS label_max_photos, COUNT(*) AS labels"). Select("MAX(photo_count) AS label_max_photos, COUNT(*) AS labels").
Where("photo_count > 0"). Where("photo_count > 0").
Where("deleted_at IS NULL"). Where("deleted_at IS NULL").
Where("(label_priority >= 0 OR label_favorite = 1)"). Where("(label_priority >= 0 OR label_favorite = TRUE)").
Take(&cfg.Count) Take(&cfg.Count)
if hidePrivate { if hidePrivate {
c.Db(). c.Db().
Table("albums"). Table("albums").
Select("SUM(album_type = ?) AS albums, "+ Select("COUNT(CASE WHEN album_type = ? THEN 1 END) AS albums, "+
"SUM(album_type = ?) AS moments, "+ "COUNT(CASE WHEN album_type = ? THEN 1 END) AS moments, "+
"SUM(album_type = ?) AS months, "+ "COUNT(CASE WHEN album_type = ? THEN 1 END) AS months, "+
"SUM(album_type = ?) AS states, "+ "COUNT(CASE WHEN album_type = ? THEN 1 END) AS states, "+
"SUM(album_type = ?) AS folders, "+ "COUNT(CASE WHEN album_type = ? THEN 1 END) AS folders, "+
"SUM(album_type = ? AND album_private = 1) AS private_albums, "+ "COUNT(CASE WHEN album_type = ? AND album_private = TRUE THEN 1 END) AS private_albums, "+
"SUM(album_type = ? AND album_private = 1) AS private_moments, "+ "COUNT(CASE WHEN album_type = ? AND album_private = TRUE THEN 1 END) AS private_moments, "+
"SUM(album_type = ? AND album_private = 1) AS private_months, "+ "COUNT(CASE WHEN album_type = ? AND album_private = TRUE THEN 1 END) AS private_months, "+
"SUM(album_type = ? AND album_private = 1) AS private_states, "+ "COUNT(CASE WHEN album_type = ? AND album_private = TRUE THEN 1 END) AS private_states, "+
"SUM(album_type = ? AND album_private = 1) AS private_folders", "COUNT(CASE WHEN album_type = ? AND album_private = TRUE THEN 1 END) AS private_folders",
entity.AlbumManual, entity.AlbumMoment, entity.AlbumMonth, entity.AlbumState, entity.AlbumFolder, entity.AlbumManual, entity.AlbumMoment, entity.AlbumMonth, entity.AlbumState, entity.AlbumFolder,
entity.AlbumManual, entity.AlbumMoment, entity.AlbumMonth, entity.AlbumState, entity.AlbumFolder). entity.AlbumManual, entity.AlbumMoment, entity.AlbumMonth, entity.AlbumState, entity.AlbumFolder).
Where("deleted_at IS NULL AND (albums.album_type <> 'folder' OR albums.album_path IN (SELECT photos.photo_path FROM photos WHERE photos.photo_private = 0 AND photos.deleted_at IS NULL))"). Where("deleted_at IS NULL AND (albums.album_type <> 'folder' OR albums.album_path IN (SELECT photos.photo_path FROM photos WHERE photos.photo_private = FALSE AND photos.deleted_at IS NULL))").
Take(&cfg.Count) Take(&cfg.Count)
} else { } else {
c.Db(). c.Db().
Table("albums"). Table("albums").
Select("SUM(album_type = ?) AS albums, "+ Select("COUNT(CASE WHEN album_type = ? THEN 1 END) AS albums, "+
"SUM(album_type = ?) AS moments, "+ "COUNT(CASE WHEN album_type = ? THEN 1 END) AS moments, "+
"SUM(album_type = ?) AS months, "+ "COUNT(CASE WHEN album_type = ? THEN 1 END) AS months, "+
"SUM(album_type = ?) AS states, "+ "COUNT(CASE WHEN album_type = ? THEN 1 END) AS states, "+
"SUM(album_type = ?) AS folders", "COUNT(CASE WHEN album_type = ? THEN 1 END) AS folders",
entity.AlbumManual, entity.AlbumMoment, entity.AlbumMonth, entity.AlbumState, entity.AlbumFolder). entity.AlbumManual, entity.AlbumMoment, entity.AlbumMonth, entity.AlbumState, entity.AlbumFolder).
Where("deleted_at IS NULL AND (albums.album_type <> 'folder' OR albums.album_path IN (SELECT photos.photo_path FROM photos WHERE photos.deleted_at IS NULL))"). Where("deleted_at IS NULL AND (albums.album_type <> 'folder' OR albums.album_path IN (SELECT photos.photo_path FROM photos WHERE photos.deleted_at IS NULL))").
Take(&cfg.Count) Take(&cfg.Count)
@@ -606,7 +606,7 @@ func (c *Config) ClientUser(withSettings bool) ClientConfig {
c.Db(). c.Db().
Table("files"). Table("files").
Select("COUNT(*) AS files"). Select("COUNT(*) AS files").
Where("file_missing = 0 AND file_root = ? AND deleted_at IS NULL", entity.RootOriginals). Where("file_missing = FALSE AND file_root = ? AND deleted_at IS NULL", entity.RootOriginals).
Take(&cfg.Count) Take(&cfg.Count)
c.Db(). c.Db().
@@ -616,7 +616,7 @@ func (c *Config) ClientUser(withSettings bool) ClientConfig {
c.Db(). c.Db().
Table("places"). Table("places").
Select("SUM(photo_count > 0) AS places"). Select("COUNT(CASE WHEN photo_count > 0 THEN 1 END) AS places").
Where("id <> 'zz'"). Where("id <> 'zz'").
Take(&cfg.Count) Take(&cfg.Count)
@@ -640,7 +640,7 @@ func (c *Config) ClientUser(withSettings bool) ClientConfig {
Find(&cfg.Lenses) Find(&cfg.Lenses)
c.Db(). c.Db().
Where("deleted_at IS NULL AND album_favorite = 1"). Where("deleted_at IS NULL AND album_favorite = TRUE").
Limit(20).Order("album_title"). Limit(20).Order("album_title").
Find(&cfg.Albums) Find(&cfg.Albums)

View File

@@ -11,6 +11,7 @@ import (
"time" "time"
"gorm.io/driver/mysql" "gorm.io/driver/mysql"
"gorm.io/driver/postgres"
"gorm.io/driver/sqlite" "gorm.io/driver/sqlite"
"gorm.io/gorm" "gorm.io/gorm"
"gorm.io/gorm/logger" "gorm.io/gorm/logger"
@@ -41,6 +42,7 @@ const (
var drivers = map[string]func(string) gorm.Dialector{ var drivers = map[string]func(string) gorm.Dialector{
MySQL: mysql.Open, MySQL: mysql.Open,
SQLite3: sqlite.Open, SQLite3: sqlite.Open,
Postgres: postgres.Open,
} }
// DatabaseDriver returns the database driver name. // DatabaseDriver returns the database driver name.
@@ -50,6 +52,8 @@ func (c *Config) DatabaseDriver() string {
c.options.DatabaseDriver = MySQL c.options.DatabaseDriver = MySQL
case SQLite3, "sqllite", "test", "file", "": case SQLite3, "sqllite", "test", "file", "":
c.options.DatabaseDriver = SQLite3 c.options.DatabaseDriver = SQLite3
case Postgres:
c.options.DatabaseDriver = Postgres
case "tidb": case "tidb":
log.Warnf("config: database driver 'tidb' is deprecated, using sqlite") log.Warnf("config: database driver 'tidb' is deprecated, using sqlite")
c.options.DatabaseDriver = SQLite3 c.options.DatabaseDriver = SQLite3
@@ -153,9 +157,16 @@ func (c *Config) DatabaseHost() string {
return c.options.DatabaseServer return c.options.DatabaseServer
} }
func (c *Config) _DefaultDatabasePort() int {
if c.DatabaseDriver() == Postgres {
return 5432
}
return 3306
}
// DatabasePort the database server port. // DatabasePort the database server port.
func (c *Config) DatabasePort() int { func (c *Config) DatabasePort() int {
const defaultPort = 3306 defaultPort := c._DefaultDatabasePort()
if server := c.DatabaseServer(); server == "" { if server := c.DatabaseServer(); server == "" {
return 0 return 0

View File

@@ -33,35 +33,35 @@ type Albums []Album
// Album represents a photo album // Album represents a photo album
type Album struct { type Album struct {
ID uint `gorm:"primaryKey;" json:"ID" yaml:"-"` ID uint `gorm:"primaryKey;" json:"ID" yaml:"-"`
AlbumUID string `gorm:"type:VARBINARY(42);uniqueIndex;" json:"UID" yaml:"UID"` AlbumUID string `gorm:"size:42;uniqueIndex;" json:"UID" yaml:"UID"`
ParentUID string `gorm:"type:VARBINARY(42);default:'';" json:"ParentUID,omitempty" yaml:"ParentUID,omitempty"` ParentUID string `gorm:"size:42;default:'';" json:"ParentUID,omitempty" yaml:"ParentUID,omitempty"`
AlbumSlug string `gorm:"type:VARBINARY(160);index;" json:"Slug" yaml:"Slug"` AlbumSlug string `gorm:"size:160;index;" json:"Slug" yaml:"Slug"`
AlbumPath string `gorm:"type:VARCHAR(1024);index;" json:"Path,omitempty" yaml:"Path,omitempty"` AlbumPath string `gorm:"size:1024;index;" json:"Path,omitempty" yaml:"Path,omitempty"`
AlbumType string `gorm:"type:VARBINARY(8);default:'album';" json:"Type" yaml:"Type,omitempty"` AlbumType string `gorm:"size:8;default:'album';" json:"Type" yaml:"Type,omitempty"`
AlbumTitle string `gorm:"type:VARCHAR(160);index;" json:"Title" yaml:"Title"` AlbumTitle string `gorm:"type:VARCHAR(160);index;" json:"Title" yaml:"Title"`
AlbumLocation string `gorm:"type:VARCHAR(160);" json:"Location" yaml:"Location,omitempty"` AlbumLocation string `gorm:"type:VARCHAR(160);" json:"Location" yaml:"Location,omitempty"`
AlbumCategory string `gorm:"type:VARCHAR(100);index;" json:"Category" yaml:"Category,omitempty"` AlbumCategory string `gorm:"type:VARCHAR(100);index;" json:"Category" yaml:"Category,omitempty"`
AlbumCaption string `gorm:"type:VARCHAR(1024);" json:"Caption" yaml:"Caption,omitempty"` AlbumCaption string `gorm:"type:VARCHAR(1024);" json:"Caption" yaml:"Caption,omitempty"`
AlbumDescription string `gorm:"type:VARCHAR(2048);" json:"Description" yaml:"Description,omitempty"` AlbumDescription string `gorm:"type:VARCHAR(2048);" json:"Description" yaml:"Description,omitempty"`
AlbumNotes string `gorm:"type:VARCHAR(1024);" json:"Notes" yaml:"Notes,omitempty"` AlbumNotes string `gorm:"type:VARCHAR(1024);" json:"Notes" yaml:"Notes,omitempty"`
AlbumFilter string `gorm:"type:VARBINARY(2048);" json:"Filter" yaml:"Filter,omitempty"` AlbumFilter string `gorm:"size:2048;" json:"Filter" yaml:"Filter,omitempty"`
AlbumOrder string `gorm:"type:VARBINARY(32);" json:"Order" yaml:"Order,omitempty"` AlbumOrder string `gorm:"size:32;" json:"Order" yaml:"Order,omitempty"`
AlbumTemplate string `gorm:"type:VARBINARY(255);" json:"Template" yaml:"Template,omitempty"` AlbumTemplate string `gorm:"size:255;" json:"Template" yaml:"Template,omitempty"`
AlbumState string `gorm:"type:VARCHAR(100);index;" json:"State" yaml:"State,omitempty"` AlbumState string `gorm:"type:VARCHAR(100);index;" json:"State" yaml:"State,omitempty"`
AlbumCountry string `gorm:"type:VARBINARY(2);index:idx_albums_country_year_month;default:'zz';" json:"Country" yaml:"Country,omitempty"` AlbumCountry string `gorm:"size:2;index:idx_albums_country_year_month;default:'zz';" json:"Country" yaml:"Country,omitempty"`
AlbumYear int `gorm:"index:idx_albums_ymd;index:idx_albums_country_year_month;" json:"Year" yaml:"Year,omitempty"` AlbumYear int `gorm:"index:idx_albums_ymd;index:idx_albums_country_year_month;" json:"Year" yaml:"Year,omitempty"`
AlbumMonth int `gorm:"index:idx_albums_ymd;index:idx_albums_country_year_month;" json:"Month" yaml:"Month,omitempty"` AlbumMonth int `gorm:"index:idx_albums_ymd;index:idx_albums_country_year_month;" json:"Month" yaml:"Month,omitempty"`
AlbumDay int `gorm:"index:idx_albums_ymd;" json:"Day" yaml:"Day,omitempty"` AlbumDay int `gorm:"index:idx_albums_ymd;" json:"Day" yaml:"Day,omitempty"`
AlbumFavorite bool `json:"Favorite" yaml:"Favorite,omitempty"` AlbumFavorite bool `json:"Favorite" yaml:"Favorite,omitempty"`
AlbumPrivate bool `json:"Private" yaml:"Private,omitempty"` AlbumPrivate bool `json:"Private" yaml:"Private,omitempty"`
Thumb string `gorm:"type:VARBINARY(128);index;default:'';" json:"Thumb" yaml:"Thumb,omitempty"` Thumb string `gorm:"size:128;index;default:'';" json:"Thumb" yaml:"Thumb,omitempty"`
ThumbSrc string `gorm:"type:VARBINARY(8);default:'';" json:"ThumbSrc,omitempty" yaml:"ThumbSrc,omitempty"` ThumbSrc string `gorm:"size:8;default:'';" json:"ThumbSrc,omitempty" yaml:"ThumbSrc,omitempty"`
CreatedBy string `gorm:"type:VARBINARY(42);index" json:"CreatedBy,omitempty" yaml:"CreatedBy,omitempty"` CreatedBy string `gorm:"size:42;index" json:"CreatedBy,omitempty" yaml:"CreatedBy,omitempty"`
CreatedAt time.Time `json:"CreatedAt" yaml:"CreatedAt,omitempty"` CreatedAt time.Time `json:"CreatedAt" yaml:"CreatedAt,omitempty"`
UpdatedAt time.Time `json:"UpdatedAt" yaml:"UpdatedAt,omitempty"` UpdatedAt time.Time `json:"UpdatedAt" yaml:"UpdatedAt,omitempty"`
PublishedAt *time.Time `sql:"index" json:"PublishedAt,omitempty" yaml:"PublishedAt,omitempty"` PublishedAt *time.Time `sql:"index" json:"PublishedAt,omitempty" yaml:"PublishedAt,omitempty"`
DeletedAt *time.Time `sql:"index" json:"DeletedAt" yaml:"DeletedAt,omitempty"` DeletedAt *time.Time `sql:"index" json:"DeletedAt" yaml:"DeletedAt,omitempty"`
Photos PhotoAlbums `gorm:"foreignKey:AlbumUID" json:"-" yaml:"Photos,omitempty"` Photos []PhotoAlbum `gorm:"foreignKey:AlbumUID;references:AlbumUID" json:"-" yaml:"Photos,omitempty"`
} }
// AfterUpdate flushes the album cache. // AfterUpdate flushes the album cache.

View File

@@ -4,9 +4,9 @@ import "github.com/photoprism/photoprism/internal/event"
// AlbumUser represents the user and group ownership of an Album and the corresponding permissions. // AlbumUser represents the user and group ownership of an Album and the corresponding permissions.
type AlbumUser struct { type AlbumUser struct {
UID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false" json:"UID" yaml:"UID"` UID string `gorm:"primaryKey;autoIncrement:false" json:"UID" yaml:"UID"`
UserUID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false;index" json:"UserUID,omitempty" yaml:"UserUID,omitempty"` UserUID string `gorm:"primaryKey;autoIncrement:false;index" json:"UserUID,omitempty" yaml:"UserUID,omitempty"`
TeamUID string `gorm:"type:VARBINARY(42);index" json:"TeamUID,omitempty" yaml:"TeamUID,omitempty"` TeamUID string `gorm:"index" json:"TeamUID,omitempty" yaml:"TeamUID,omitempty"`
Perm uint `json:"Perm,omitempty" yaml:"Perm,omitempty"` Perm uint `json:"Perm,omitempty" yaml:"Perm,omitempty"`
} }

View File

@@ -29,17 +29,17 @@ type Clients []Client
// Client represents a client application. // Client represents a client application.
type Client struct { type Client struct {
ClientUID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false;" json:"-" yaml:"ClientUID"` ClientUID string `gorm:"size:42;primaryKey;autoIncrement:false;" json:"-" yaml:"ClientUID"`
UserUID string `gorm:"type:VARBINARY(42);index;default:'';" json:"UserUID" yaml:"UserUID,omitempty"` UserUID string `gorm:"size:42;index;default:'';" json:"UserUID" yaml:"UserUID,omitempty"`
UserName string `gorm:"size:200;index;" json:"UserName" yaml:"UserName,omitempty"` UserName string `gorm:"size:200;index;" json:"UserName" yaml:"UserName,omitempty"`
user *User `gorm:"-" yaml:"-"` user *User `gorm:"foreignKey:UserUID;references:UserUID" yaml:"-"`
ClientName string `gorm:"size:200;" json:"ClientName" yaml:"ClientName,omitempty"` ClientName string `gorm:"size:200;" json:"ClientName" yaml:"ClientName,omitempty"`
ClientRole string `gorm:"size:64;default:'';" json:"ClientRole" yaml:"ClientRole,omitempty"` ClientRole string `gorm:"size:64;default:'';" json:"ClientRole" yaml:"ClientRole,omitempty"`
ClientType string `gorm:"type:VARBINARY(16)" json:"ClientType" yaml:"ClientType,omitempty"` ClientType string `gorm:"size:16" json:"ClientType" yaml:"ClientType,omitempty"`
ClientURL string `gorm:"type:VARBINARY(255);default:'';column:client_url;" json:"ClientURL" yaml:"ClientURL,omitempty"` ClientURL string `gorm:"size:255;default:'';column:client_url;" json:"ClientURL" yaml:"ClientURL,omitempty"`
CallbackURL string `gorm:"type:VARBINARY(255);default:'';column:callback_url;" json:"CallbackURL" yaml:"CallbackURL,omitempty"` CallbackURL string `gorm:"size:255;default:'';column:callback_url;" json:"CallbackURL" yaml:"CallbackURL,omitempty"`
AuthProvider string `gorm:"type:VARBINARY(128);default:'';" json:"AuthProvider" yaml:"AuthProvider,omitempty"` AuthProvider string `gorm:"size:128;default:'';" json:"AuthProvider" yaml:"AuthProvider,omitempty"`
AuthMethod string `gorm:"type:VARBINARY(128);default:'';" json:"AuthMethod" yaml:"AuthMethod,omitempty"` AuthMethod string `gorm:"size:128;default:'';" json:"AuthMethod" yaml:"AuthMethod,omitempty"`
AuthScope string `gorm:"size:1024;default:'';" json:"AuthScope" yaml:"AuthScope,omitempty"` AuthScope string `gorm:"size:1024;default:'';" json:"AuthScope" yaml:"AuthScope,omitempty"`
AuthExpires int64 `json:"AuthExpires" yaml:"AuthExpires,omitempty"` AuthExpires int64 `json:"AuthExpires" yaml:"AuthExpires,omitempty"`
AuthTokens int64 `json:"AuthTokens" yaml:"AuthTokens,omitempty"` AuthTokens int64 `json:"AuthTokens" yaml:"AuthTokens,omitempty"`

View File

@@ -36,33 +36,33 @@ type Sessions []Session
// Session represents a User session. // Session represents a User session.
type Session struct { type Session struct {
ID string `gorm:"type:VARBINARY(2048);primaryKey;autoIncrement:false;" json:"-" yaml:"ID"` ID string `gorm:"size:2048;primaryKey;autoIncrement:false;" json:"-" yaml:"ID"`
authToken string `gorm:"-" yaml:"-"` authToken string `gorm:"-" yaml:"-"`
UserUID string `gorm:"type:VARBINARY(42);index;default:'';" json:"UserUID" yaml:"UserUID,omitempty"` UserUID string `gorm:"size:42;index;default:'';" json:"UserUID" yaml:"UserUID,omitempty"`
UserName string `gorm:"size:200;index;" json:"UserName" yaml:"UserName,omitempty"` UserName string `gorm:"size:200;index;" json:"UserName" yaml:"UserName,omitempty"`
user *User `gorm:"-" yaml:"-"` user *User `gorm:"-" yaml:"-"`
ClientUID string `gorm:"type:VARBINARY(42);index;default:'';" json:"ClientUID" yaml:"ClientUID,omitempty"` ClientUID string `gorm:"size:42;index;default:'';" json:"ClientUID" yaml:"ClientUID,omitempty"`
ClientName string `gorm:"size:200;default:'';" json:"ClientName" yaml:"ClientName,omitempty"` ClientName string `gorm:"size:200;default:'';" json:"ClientName" yaml:"ClientName,omitempty"`
ClientIP string `gorm:"size:64;column:client_ip;index" json:"ClientIP" yaml:"ClientIP,omitempty"` ClientIP string `gorm:"size:64;column:client_ip;index" json:"ClientIP" yaml:"ClientIP,omitempty"`
client *Client `gorm:"-" yaml:"-"` client *Client `gorm:"-" yaml:"-"`
AuthProvider string `gorm:"type:VARBINARY(128);default:'';" json:"AuthProvider" yaml:"AuthProvider,omitempty"` AuthProvider string `gorm:"size:128;default:'';" json:"AuthProvider" yaml:"AuthProvider,omitempty"`
AuthMethod string `gorm:"type:VARBINARY(128);default:'';" json:"AuthMethod" yaml:"AuthMethod,omitempty"` AuthMethod string `gorm:"size:128;default:'';" json:"AuthMethod" yaml:"AuthMethod,omitempty"`
AuthDomain string `gorm:"type:VARBINARY(255);default:'';" json:"AuthDomain" yaml:"AuthDomain,omitempty"` AuthDomain string `gorm:"size:255;default:'';" json:"AuthDomain" yaml:"AuthDomain,omitempty"`
AuthID string `gorm:"type:VARBINARY(255);index;default:'';" json:"-" yaml:"AuthID,omitempty"` AuthID string `gorm:"size:255;index;default:'';" json:"-" yaml:"AuthID,omitempty"`
AuthScope string `gorm:"size:1024;default:'';" json:"AuthScope" yaml:"AuthScope,omitempty"` AuthScope string `gorm:"size:1024;default:'';" json:"AuthScope" yaml:"AuthScope,omitempty"`
GrantType string `gorm:"type:VARBINARY(64);default:'';" json:"GrantType" yaml:"GrantType,omitempty"` GrantType string `gorm:"size:64;default:'';" json:"GrantType" yaml:"GrantType,omitempty"`
LastActive int64 `json:"LastActive" yaml:"LastActive,omitempty"` LastActive int64 `json:"LastActive" yaml:"LastActive,omitempty"`
SessExpires int64 `gorm:"index" json:"Expires" yaml:"Expires,omitempty"` SessExpires int64 `gorm:"index" json:"Expires" yaml:"Expires,omitempty"`
SessTimeout int64 `json:"Timeout" yaml:"Timeout,omitempty"` SessTimeout int64 `json:"Timeout" yaml:"Timeout,omitempty"`
PreviewToken string `gorm:"type:VARBINARY(64);column:preview_token;default:'';" json:"-" yaml:"-"` PreviewToken string `gorm:"size:64;column:preview_token;default:'';" json:"-" yaml:"-"`
DownloadToken string `gorm:"type:VARBINARY(64);column:download_token;default:'';" json:"-" yaml:"-"` DownloadToken string `gorm:"size:64;column:download_token;default:'';" json:"-" yaml:"-"`
AccessToken string `gorm:"type:VARBINARY(4096);column:access_token;default:'';" json:"-" yaml:"-"` AccessToken string `gorm:"size:4096;column:access_token;default:'';" json:"-" yaml:"-"`
RefreshToken string `gorm:"type:VARBINARY(512);column:refresh_token;default:'';" json:"-" yaml:"-"` RefreshToken string `gorm:"size:512;column:refresh_token;default:'';" json:"-" yaml:"-"`
IdToken string `gorm:"type:VARBINARY(1024);column:id_token;default:'';" json:"IdToken,omitempty" yaml:"IdToken,omitempty"` IdToken string `gorm:"size:1024;column:id_token;default:'';" json:"IdToken,omitempty" yaml:"IdToken,omitempty"`
UserAgent string `gorm:"size:512;" json:"UserAgent" yaml:"UserAgent,omitempty"` UserAgent string `gorm:"size:512;" json:"UserAgent" yaml:"UserAgent,omitempty"`
DataJSON json.RawMessage `gorm:"type:VARBINARY(4096);" json:"-" yaml:"Data,omitempty"` DataJSON json.RawMessage `json:"-" yaml:"Data,omitempty"`
data *SessionData `gorm:"-" yaml:"-"` data *SessionData `gorm:"-" yaml:"-"`
RefID string `gorm:"type:VARBINARY(16);default:'';" json:"ID" yaml:"-"` RefID string `gorm:"size:16;default:'';" json:"ID" yaml:"-"`
LoginIP string `gorm:"size:64;column:login_ip" json:"LoginIP" yaml:"-"` LoginIP string `gorm:"size:64;column:login_ip" json:"LoginIP" yaml:"-"`
LoginAt time.Time `json:"LoginAt" yaml:"-"` LoginAt time.Time `json:"LoginAt" yaml:"-"`
CreatedAt time.Time `json:"CreatedAt" yaml:"CreatedAt"` CreatedAt time.Time `json:"CreatedAt" yaml:"CreatedAt"`

View File

@@ -45,11 +45,11 @@ type Users []User
// User represents a person that may optionally log in as user. // User represents a person that may optionally log in as user.
type User struct { type User struct {
ID int `gorm:"primaryKey" json:"ID" yaml:"-"` ID int `gorm:"primaryKey" json:"ID" yaml:"-"`
UUID string `gorm:"type:VARBINARY(64);column:user_uuid;index;" json:"UUID,omitempty" yaml:"UUID,omitempty"` UUID string `gorm:"size:64;column:user_uuid;index;" json:"UUID,omitempty" yaml:"UUID,omitempty"`
UserUID string `gorm:"type:VARBINARY(42);column:user_uid;uniqueIndex;" json:"UID" yaml:"UID"` UserUID string `gorm:"size:42;column:user_uid;uniqueIndex;" json:"UID" yaml:"UID"`
AuthProvider string `gorm:"type:VARBINARY(128);default:'';" json:"AuthProvider" yaml:"AuthProvider,omitempty"` AuthProvider string `gorm:"size:128;default:'';" json:"AuthProvider" yaml:"AuthProvider,omitempty"`
AuthMethod string `gorm:"type:VARBINARY(128);default:'';" json:"AuthMethod" yaml:"AuthMethod,omitempty"` AuthMethod string `gorm:"size:128;default:'';" json:"AuthMethod" yaml:"AuthMethod,omitempty"`
AuthID string `gorm:"type:VARBINARY(255);index;default:'';" json:"AuthID" yaml:"AuthID,omitempty"` AuthID string `gorm:"size:255;index;default:'';" json:"AuthID" yaml:"AuthID,omitempty"`
UserName string `gorm:"size:200;index;" json:"Name" yaml:"Name,omitempty"` UserName string `gorm:"size:200;index;" json:"Name" yaml:"Name,omitempty"`
DisplayName string `gorm:"size:200;" json:"DisplayName" yaml:"DisplayName,omitempty"` DisplayName string `gorm:"size:200;" json:"DisplayName" yaml:"DisplayName,omitempty"`
UserEmail string `gorm:"size:255;index;" json:"Email" yaml:"Email,omitempty"` UserEmail string `gorm:"size:255;index;" json:"Email" yaml:"Email,omitempty"`
@@ -61,24 +61,24 @@ type User struct {
LoginAt *time.Time `json:"LoginAt" yaml:"LoginAt,omitempty"` LoginAt *time.Time `json:"LoginAt" yaml:"LoginAt,omitempty"`
ExpiresAt *time.Time `sql:"index" json:"ExpiresAt,omitempty" yaml:"ExpiresAt,omitempty"` ExpiresAt *time.Time `sql:"index" json:"ExpiresAt,omitempty" yaml:"ExpiresAt,omitempty"`
WebDAV bool `gorm:"column:webdav;" json:"WebDAV" yaml:"WebDAV,omitempty"` WebDAV bool `gorm:"column:webdav;" json:"WebDAV" yaml:"WebDAV,omitempty"`
BasePath string `gorm:"type:VARBINARY(1024);" json:"BasePath" yaml:"BasePath,omitempty"` BasePath string `gorm:"size:1024;" json:"BasePath" yaml:"BasePath,omitempty"`
UploadPath string `gorm:"type:VARBINARY(1024);" json:"UploadPath" yaml:"UploadPath,omitempty"` UploadPath string `gorm:"size:1024;" json:"UploadPath" yaml:"UploadPath,omitempty"`
CanInvite bool `json:"CanInvite" yaml:"CanInvite,omitempty"` CanInvite bool `json:"CanInvite" yaml:"CanInvite,omitempty"`
InviteToken string `gorm:"type:VARBINARY(64);index;" json:"-" yaml:"-"` InviteToken string `gorm:"size:64;index;" json:"-" yaml:"-"`
InvitedBy string `gorm:"size:64;" json:"-" yaml:"-"` InvitedBy string `gorm:"size:64;" json:"-" yaml:"-"`
VerifyToken string `gorm:"type:VARBINARY(64);" json:"-" yaml:"-"` VerifyToken string `gorm:"size:64;" json:"-" yaml:"-"`
VerifiedAt *time.Time `json:"VerifiedAt,omitempty" yaml:"VerifiedAt,omitempty"` VerifiedAt *time.Time `json:"VerifiedAt,omitempty" yaml:"VerifiedAt,omitempty"`
ConsentAt *time.Time `json:"ConsentAt,omitempty" yaml:"ConsentAt,omitempty"` ConsentAt *time.Time `json:"ConsentAt,omitempty" yaml:"ConsentAt,omitempty"`
BornAt *time.Time `sql:"index" json:"BornAt,omitempty" yaml:"BornAt,omitempty"` BornAt *time.Time `sql:"index" json:"BornAt,omitempty" yaml:"BornAt,omitempty"`
UserDetails *UserDetails `gorm:"foreignKey:UserUID;references:UserUID;" json:"Details,omitempty" yaml:"Details,omitempty"` UserDetails *UserDetails `gorm:"foreignKey:UserUID;references:UserUID;constraint:OnDelete:CASCADE" json:"Details,omitempty" yaml:"Details,omitempty"`
UserSettings *UserSettings `gorm:"foreignKey:UserUID;references:UserUID" json:"Settings,omitempty" yaml:"Settings,omitempty"` UserSettings *UserSettings `gorm:"foreignKey:UserUID;references:UserUID;constraint:OnDelete:CASCADE" json:"Settings,omitempty" yaml:"Settings,omitempty"`
UserShares UserShares `gorm:"-" json:"Shares,omitempty" yaml:"Shares,omitempty"` UserShares []UserShare `gorm:"foreignKey:UserUID;references:UserUID" json:"Shares,omitempty" yaml:"Shares,omitempty"`
ResetToken string `gorm:"type:VARBINARY(64);" json:"-" yaml:"-"` ResetToken string `gorm:"size:64;" json:"-" yaml:"-"`
PreviewToken string `gorm:"type:VARBINARY(64);column:preview_token;" json:"-" yaml:"-"` PreviewToken string `gorm:"size:64;column:preview_token;" json:"-" yaml:"-"`
DownloadToken string `gorm:"type:VARBINARY(64);column:download_token;" json:"-" yaml:"-"` DownloadToken string `gorm:"size:64;column:download_token;" json:"-" yaml:"-"`
Thumb string `gorm:"type:VARBINARY(128);index;default:'';" json:"Thumb" yaml:"Thumb,omitempty"` Thumb string `gorm:"size:128;index;default:'';" json:"Thumb" yaml:"Thumb,omitempty"`
ThumbSrc string `gorm:"type:VARBINARY(8);default:'';" json:"ThumbSrc" yaml:"ThumbSrc,omitempty"` ThumbSrc string `gorm:"size:8;default:'';" json:"ThumbSrc" yaml:"ThumbSrc,omitempty"`
RefID string `gorm:"type:VARBINARY(16);" json:"-" yaml:"-"` RefID string `gorm:"size:16;" json:"-" yaml:"-"`
CreatedAt time.Time `json:"CreatedAt" yaml:"-"` CreatedAt time.Time `json:"CreatedAt" yaml:"-"`
UpdatedAt time.Time `json:"UpdatedAt" yaml:"-"` UpdatedAt time.Time `json:"UpdatedAt" yaml:"-"`
DeletedAt *time.Time `sql:"index" json:"DeletedAt,omitempty" yaml:"-"` DeletedAt *time.Time `sql:"index" json:"DeletedAt,omitempty" yaml:"-"`
@@ -1090,7 +1090,7 @@ func (m *User) NoShares() bool {
return true return true
} }
return m.UserShares.Empty() return UserShares(m.UserShares).Empty()
} }
// HasShares checks if the user has any shares. // HasShares checks if the user has any shares.
@@ -1105,7 +1105,7 @@ func (m *User) HasShare(uid string) bool {
} }
// Check if the share list contains the specified UID. // Check if the share list contains the specified UID.
return m.UserShares.Contains(uid) return UserShares(m.UserShares).Contains(uid)
} }
// SharedUIDs returns shared entity UIDs. // SharedUIDs returns shared entity UIDs.
@@ -1114,7 +1114,7 @@ func (m *User) SharedUIDs() UIDs {
m.RefreshShares() m.RefreshShares()
} }
return m.UserShares.UIDs() return UserShares(m.UserShares).UIDs()
} }
// RedeemToken updates shared entity UIDs using the specified token. // RedeemToken updates shared entity UIDs using the specified token.

View File

@@ -17,12 +17,12 @@ const (
// UserDetails represents user profile information. // UserDetails represents user profile information.
type UserDetails struct { type UserDetails struct {
UserUID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false;" json:"-" yaml:"-"` UserUID string `gorm:"size:42;uniqueIndex;" json:"-" yaml:"-"`
SubjUID string `gorm:"type:VARBINARY(42);index;" json:"SubjUID,omitempty" yaml:"SubjUID,omitempty"` SubjUID string `gorm:"size:42;index;" json:"SubjUID,omitempty" yaml:"SubjUID,omitempty"`
SubjSrc string `gorm:"type:VARBINARY(8);default:'';" json:"-" yaml:"SubjSrc,omitempty"` SubjSrc string `gorm:"size:8;default:'';" json:"-" yaml:"SubjSrc,omitempty"`
PlaceID string `gorm:"type:VARBINARY(42);index;default:'zz'" json:"-" yaml:"-"` PlaceID string `gorm:"size:42;index;default:'zz'" json:"-" yaml:"-"`
PlaceSrc string `gorm:"type:VARBINARY(8);" json:"-" yaml:"PlaceSrc,omitempty"` PlaceSrc string `gorm:"size:8;" json:"-" yaml:"PlaceSrc,omitempty"`
CellID string `gorm:"type:VARBINARY(42);index;default:'zz'" json:"-" yaml:"CellID,omitempty"` CellID string `gorm:"size:42;index;default:'zz'" json:"-" yaml:"CellID,omitempty"`
BirthYear int `json:"BirthYear" yaml:"BirthYear,omitempty"` BirthYear int `json:"BirthYear" yaml:"BirthYear,omitempty"`
BirthMonth int `json:"BirthMonth" yaml:"BirthMonth,omitempty"` BirthMonth int `json:"BirthMonth" yaml:"BirthMonth,omitempty"`
BirthDay int `json:"BirthDay" yaml:"BirthDay,omitempty"` BirthDay int `json:"BirthDay" yaml:"BirthDay,omitempty"`
@@ -32,23 +32,23 @@ type UserDetails struct {
FamilyName string `gorm:"size:64;" json:"FamilyName" yaml:"FamilyName,omitempty"` FamilyName string `gorm:"size:64;" json:"FamilyName" yaml:"FamilyName,omitempty"`
NameSuffix string `gorm:"size:32;" json:"NameSuffix" yaml:"NameSuffix,omitempty"` NameSuffix string `gorm:"size:32;" json:"NameSuffix" yaml:"NameSuffix,omitempty"`
NickName string `gorm:"size:64;" json:"NickName" yaml:"NickName,omitempty"` NickName string `gorm:"size:64;" json:"NickName" yaml:"NickName,omitempty"`
NameSrc string `gorm:"type:VARBINARY(8);" json:"NameSrc" yaml:"NameSrc,omitempty"` NameSrc string `gorm:"size:8;" json:"NameSrc" yaml:"NameSrc,omitempty"`
UserGender string `gorm:"size:16;" json:"Gender" yaml:"Gender,omitempty"` UserGender string `gorm:"size:16;" json:"Gender" yaml:"Gender,omitempty"`
UserAbout string `gorm:"size:512;" json:"About" yaml:"About,omitempty"` UserAbout string `gorm:"size:512;" json:"About" yaml:"About,omitempty"`
UserBio string `gorm:"size:2048;" json:"Bio" yaml:"Bio,omitempty"` UserBio string `gorm:"size:2048;" json:"Bio" yaml:"Bio,omitempty"`
UserLocation string `gorm:"size:512;" json:"Location" yaml:"Location,omitempty"` UserLocation string `gorm:"size:512;" json:"Location" yaml:"Location,omitempty"`
UserCountry string `gorm:"type:VARBINARY(2);" json:"Country" yaml:"Country,omitempty"` UserCountry string `gorm:"size:2;" json:"Country" yaml:"Country,omitempty"`
UserPhone string `gorm:"size:32;" json:"Phone" yaml:"Phone,omitempty"` UserPhone string `gorm:"size:32;" json:"Phone" yaml:"Phone,omitempty"`
SiteURL string `gorm:"type:VARBINARY(512);column:site_url" json:"SiteURL" yaml:"SiteURL,omitempty"` SiteURL string `gorm:"size:512;column:site_url" json:"SiteURL" yaml:"SiteURL,omitempty"`
ProfileURL string `gorm:"type:VARBINARY(512);column:profile_url" json:"ProfileURL" yaml:"ProfileURL,omitempty"` ProfileURL string `gorm:"size:512;column:profile_url" json:"ProfileURL" yaml:"ProfileURL,omitempty"`
FeedURL string `gorm:"type:VARBINARY(512);column:feed_url" json:"FeedURL,omitempty" yaml:"FeedURL,omitempty"` FeedURL string `gorm:"size:512;column:feed_url" json:"FeedURL,omitempty" yaml:"FeedURL,omitempty"`
AvatarURL string `gorm:"type:VARBINARY(512);column:avatar_url" json:"AvatarURL,omitempty" yaml:"AvatarURL,omitempty"` AvatarURL string `gorm:"size:512;column:avatar_url" json:"AvatarURL,omitempty" yaml:"AvatarURL,omitempty"`
OrgTitle string `gorm:"size:64;" json:"OrgTitle" yaml:"OrgTitle,omitempty"` OrgTitle string `gorm:"size:64;" json:"OrgTitle" yaml:"OrgTitle,omitempty"`
OrgName string `gorm:"size:128;" json:"OrgName" yaml:"OrgName,omitempty"` OrgName string `gorm:"size:128;" json:"OrgName" yaml:"OrgName,omitempty"`
OrgEmail string `gorm:"size:255;index;" json:"OrgEmail" yaml:"OrgEmail,omitempty"` OrgEmail string `gorm:"size:255;index;" json:"OrgEmail" yaml:"OrgEmail,omitempty"`
OrgPhone string `gorm:"size:32;" json:"OrgPhone" yaml:"OrgPhone,omitempty"` OrgPhone string `gorm:"size:32;" json:"OrgPhone" yaml:"OrgPhone,omitempty"`
OrgURL string `gorm:"type:VARBINARY(512);column:org_url" json:"OrgURL" yaml:"OrgURL,omitempty"` OrgURL string `gorm:"size:512;column:org_url" json:"OrgURL" yaml:"OrgURL,omitempty"`
IdURL string `gorm:"type:VARBINARY(512);column:id_url;" json:"IdURL,omitempty" yaml:"IdURL,omitempty"` IdURL string `gorm:"size:512;column:id_url;" json:"IdURL,omitempty" yaml:"IdURL,omitempty"`
CreatedAt time.Time `json:"CreatedAt" yaml:"-"` CreatedAt time.Time `json:"CreatedAt" yaml:"-"`
UpdatedAt time.Time `json:"UpdatedAt" yaml:"-"` UpdatedAt time.Time `json:"UpdatedAt" yaml:"-"`
} }

View File

@@ -10,21 +10,21 @@ import (
// UserSettings represents user preferences. // UserSettings represents user preferences.
type UserSettings struct { type UserSettings struct {
UserUID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false" json:"-" yaml:"UserUID"` UserUID string `gorm:"size:42;uniqueIndex;" json:"-" yaml:"UserUID"`
UITheme string `gorm:"type:VARBINARY(32);column:ui_theme;" json:"UITheme,omitempty" yaml:"UITheme,omitempty"` UITheme string `gorm:"size:32;column:ui_theme;" json:"UITheme,omitempty" yaml:"UITheme,omitempty"`
UILanguage string `gorm:"type:VARBINARY(32);column:ui_language;" json:"UILanguage,omitempty" yaml:"UILanguage,omitempty"` UILanguage string `gorm:"size:32;column:ui_language;" json:"UILanguage,omitempty" yaml:"UILanguage,omitempty"`
UITimeZone string `gorm:"type:VARBINARY(64);column:ui_time_zone;" json:"UITimeZone,omitempty" yaml:"UITimeZone,omitempty"` UITimeZone string `gorm:"size:64;column:ui_time_zone;" json:"UITimeZone,omitempty" yaml:"UITimeZone,omitempty"`
MapsStyle string `gorm:"type:VARBINARY(32);" json:"MapsStyle,omitempty" yaml:"MapsStyle,omitempty"` MapsStyle string `gorm:"size:32;" json:"MapsStyle,omitempty" yaml:"MapsStyle,omitempty"`
MapsAnimate int `gorm:"default:0;" json:"MapsAnimate,omitempty" yaml:"MapsAnimate,omitempty"` MapsAnimate int `gorm:"default:0;" json:"MapsAnimate,omitempty" yaml:"MapsAnimate,omitempty"`
IndexPath string `gorm:"type:VARBINARY(1024);" json:"IndexPath,omitempty" yaml:"IndexPath,omitempty"` IndexPath string `gorm:"size:1024;" json:"IndexPath,omitempty" yaml:"IndexPath,omitempty"`
IndexRescan int `gorm:"default:0;" json:"IndexRescan,omitempty" yaml:"IndexRescan,omitempty"` IndexRescan int `gorm:"default:0;" json:"IndexRescan,omitempty" yaml:"IndexRescan,omitempty"`
ImportPath string `gorm:"type:VARBINARY(1024);" json:"ImportPath,omitempty" yaml:"ImportPath,omitempty"` ImportPath string `gorm:"size:1024;" json:"ImportPath,omitempty" yaml:"ImportPath,omitempty"`
ImportMove int `gorm:"default:0;" json:"ImportMove,omitempty" yaml:"ImportMove,omitempty"` ImportMove int `gorm:"default:0;" json:"ImportMove,omitempty" yaml:"ImportMove,omitempty"`
DownloadOriginals int `gorm:"default:0;" json:"DownloadOriginals,omitempty" yaml:"DownloadOriginals,omitempty"` DownloadOriginals int `gorm:"default:0;" json:"DownloadOriginals,omitempty" yaml:"DownloadOriginals,omitempty"`
DownloadMediaRaw int `gorm:"default:0;" json:"DownloadMediaRaw,omitempty" yaml:"DownloadMediaRaw,omitempty"` DownloadMediaRaw int `gorm:"default:0;" json:"DownloadMediaRaw,omitempty" yaml:"DownloadMediaRaw,omitempty"`
DownloadMediaSidecar int `gorm:"default:0;" json:"DownloadMediaSidecar,omitempty" yaml:"DownloadMediaSidecar,omitempty"` DownloadMediaSidecar int `gorm:"default:0;" json:"DownloadMediaSidecar,omitempty" yaml:"DownloadMediaSidecar,omitempty"`
UploadPath string `gorm:"type:VARBINARY(1024);" json:"UploadPath,omitempty" yaml:"UploadPath,omitempty"` UploadPath string `gorm:"size:1024;" json:"UploadPath,omitempty" yaml:"UploadPath,omitempty"`
DefaultPage string `gorm:"type:VARBINARY(128);" json:"DefaultPage,omitempty" yaml:"DefaultPage,omitempty"` DefaultPage string `gorm:"size:128;" json:"DefaultPage,omitempty" yaml:"DefaultPage,omitempty"`
CreatedAt time.Time `json:"CreatedAt" yaml:"-"` CreatedAt time.Time `json:"CreatedAt" yaml:"-"`
UpdatedAt time.Time `json:"UpdatedAt" yaml:"-"` UpdatedAt time.Time `json:"UpdatedAt" yaml:"-"`
} }

View File

@@ -63,13 +63,13 @@ func (m UserShares) Contains(uid string) bool {
// UserShare represents content shared with a user. // UserShare represents content shared with a user.
type UserShare struct { type UserShare struct {
UserUID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false;" json:"-" yaml:"UserUID"` UserUID string `gorm:"size:42;primaryKey;autoIncrement:false;" json:"-" yaml:"UserUID"`
ShareUID string `gorm:"type:VARBINARY(42);primaryKey;index;" json:"ShareUID" yaml:"ShareUID"` ShareUID string `gorm:"size:42;primaryKey;index;" json:"ShareUID" yaml:"ShareUID"`
LinkUID string `gorm:"type:VARBINARY(42);" json:"LinkUID,omitempty" yaml:"LinkUID,omitempty"` LinkUID string `gorm:"size:42;" json:"LinkUID,omitempty" yaml:"LinkUID,omitempty"`
ExpiresAt *time.Time `sql:"index" json:"ExpiresAt,omitempty" yaml:"ExpiresAt,omitempty"` ExpiresAt *time.Time `sql:"index" json:"ExpiresAt,omitempty" yaml:"ExpiresAt,omitempty"`
Comment string `gorm:"size:512;" json:"Comment,omitempty" yaml:"Comment,omitempty"` Comment string `gorm:"size:512;" json:"Comment,omitempty" yaml:"Comment,omitempty"`
Perm uint `json:"Perm,omitempty" yaml:"Perm,omitempty"` Perm uint `json:"Perm,omitempty" yaml:"Perm,omitempty"`
RefID string `gorm:"type:VARBINARY(16);" json:"-" yaml:"-"` RefID string `gorm:"size:16;" json:"-" yaml:"-"`
CreatedAt time.Time `json:"CreatedAt" yaml:"-"` CreatedAt time.Time `json:"CreatedAt" yaml:"-"`
UpdatedAt time.Time `json:"UpdatedAt" yaml:"-"` UpdatedAt time.Time `json:"UpdatedAt" yaml:"-"`
} }

View File

@@ -18,7 +18,7 @@ type Cameras []Camera
// Camera model and make (as extracted from UpdateExif metadata) // Camera model and make (as extracted from UpdateExif metadata)
type Camera struct { type Camera struct {
ID uint `gorm:"primaryKey" json:"ID" yaml:"ID"` ID uint `gorm:"primaryKey" json:"ID" yaml:"ID"`
CameraSlug string `gorm:"type:VARBINARY(160);uniqueIndex;" json:"Slug" yaml:"-"` CameraSlug string `gorm:"size:160;uniqueIndex;" json:"Slug" yaml:"-"`
CameraName string `gorm:"type:VARCHAR(160);" json:"Name" yaml:"Name"` CameraName string `gorm:"type:VARCHAR(160);" json:"Name" yaml:"Name"`
CameraMake string `gorm:"type:VARCHAR(160);" json:"Make" yaml:"Make,omitempty"` CameraMake string `gorm:"type:VARCHAR(160);" json:"Make" yaml:"Make,omitempty"`
CameraModel string `gorm:"type:VARCHAR(160);" json:"Model" yaml:"Model,omitempty"` CameraModel string `gorm:"type:VARCHAR(160);" json:"Model" yaml:"Model,omitempty"`

View File

@@ -15,13 +15,13 @@ var cellMutex = sync.Mutex{}
// Cell represents an S2 cell with metadata and reference to a place. // Cell represents an S2 cell with metadata and reference to a place.
type Cell struct { type Cell struct {
ID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false;" json:"ID" yaml:"ID"` ID string `gorm:"size:42;primaryKey;autoIncrement:false;" json:"ID" yaml:"ID"`
CellName string `gorm:"type:VARCHAR(200);" json:"Name" yaml:"Name,omitempty"` CellName string `gorm:"type:VARCHAR(200);" json:"Name" yaml:"Name,omitempty"`
CellStreet string `gorm:"type:VARCHAR(100);" json:"Street" yaml:"Street,omitempty"` CellStreet string `gorm:"type:VARCHAR(100);" json:"Street" yaml:"Street,omitempty"`
CellPostcode string `gorm:"type:VARCHAR(50);" json:"Postcode" yaml:"Postcode,omitempty"` CellPostcode string `gorm:"type:VARCHAR(50);" json:"Postcode" yaml:"Postcode,omitempty"`
CellCategory string `gorm:"type:VARCHAR(50);" json:"Category" yaml:"Category,omitempty"` CellCategory string `gorm:"type:VARCHAR(50);" json:"Category" yaml:"Category,omitempty"`
PlaceID string `gorm:"type:VARBINARY(42);default:'zz'" json:"-" yaml:"PlaceID"` PlaceID string `gorm:"size:42;default:'zz'" json:"-" yaml:"PlaceID"`
Place *Place `gorm:"PRELOAD:true" json:"Place" yaml:"-"` Place *Place `json:"Place" yaml:"-"`
CreatedAt time.Time `json:"CreatedAt" yaml:"-"` CreatedAt time.Time `json:"CreatedAt" yaml:"-"`
UpdatedAt time.Time `json:"UpdatedAt" yaml:"-"` UpdatedAt time.Time `json:"UpdatedAt" yaml:"-"`
} }

View File

@@ -19,13 +19,13 @@ type Countries []Country
// Country represents a country location, used for labeling photos. // Country represents a country location, used for labeling photos.
type Country struct { type Country struct {
ID string `gorm:"type:VARBINARY(2);primaryKey" json:"ID" yaml:"ID"` ID string `gorm:"size:2;primaryKey" json:"ID" yaml:"ID"`
CountrySlug string `gorm:"type:VARBINARY(160);uniqueIndex;" json:"Slug" yaml:"-"` CountrySlug string `gorm:"size:160;uniqueIndex;" json:"Slug" yaml:"-"`
CountryName string `gorm:"type:VARCHAR(160);" json:"Name" yaml:"Name,omitempty"` CountryName string `gorm:"type:VARCHAR(160);" json:"Name" yaml:"Name,omitempty"`
CountryDescription string `gorm:"type:VARCHAR(2048);" json:"Description,omitempty" yaml:"Description,omitempty"` CountryDescription string `gorm:"type:VARCHAR(2048);" json:"Description,omitempty" yaml:"Description,omitempty"`
CountryNotes string `gorm:"type:VARCHAR(1024);" json:"Notes,omitempty" yaml:"Notes,omitempty"` CountryNotes string `gorm:"type:VARCHAR(1024);" json:"Notes,omitempty" yaml:"Notes,omitempty"`
CountryPhoto *Photo `json:"-" yaml:"-"` CountryPhoto *Photo `json:"-" yaml:"-"`
CountryPhotoID uint `json:"-" yaml:"-"` CountryPhotoID *uint `json:"-" yaml:"-"`
New bool `gorm:"-" json:"-" yaml:"-"` New bool `gorm:"-" json:"-" yaml:"-"`
} }

View File

@@ -10,7 +10,7 @@ var CountryFixtures = CountryMap{
CountryDescription: "Country description", CountryDescription: "Country description",
CountryNotes: "Country Notes", CountryNotes: "Country Notes",
CountryPhoto: nil, CountryPhoto: nil,
CountryPhotoID: 0, CountryPhotoID: nil,
New: false, New: false,
}, },
} }

View File

@@ -6,6 +6,7 @@ import (
"time" "time"
"gorm.io/driver/mysql" "gorm.io/driver/mysql"
"gorm.io/driver/postgres"
"gorm.io/driver/sqlite" "gorm.io/driver/sqlite"
"gorm.io/gorm" "gorm.io/gorm"
"gorm.io/gorm/logger" "gorm.io/gorm/logger"
@@ -14,6 +15,7 @@ import (
// Supported test databases. // Supported test databases.
const ( const (
MySQL = "mysql" MySQL = "mysql"
Postgres = "postgres"
SQLite3 = "sqlite" SQLite3 = "sqlite"
SQLiteTestDB = ".test.db" SQLiteTestDB = ".test.db"
SQLiteMemoryDSN = ":memory:?cache=shared" SQLiteMemoryDSN = ":memory:?cache=shared"
@@ -21,6 +23,7 @@ const (
var drivers = map[string]func(string) gorm.Dialector{ var drivers = map[string]func(string) gorm.Dialector{
MySQL: mysql.Open, MySQL: mysql.Open,
Postgres: postgres.Open,
SQLite3: sqlite.Open, SQLite3: sqlite.Open,
} }

View File

@@ -6,7 +6,7 @@ import (
// TestEntity is an entity dedicated to test database management functionality. // TestEntity is an entity dedicated to test database management functionality.
type TestEntity struct { type TestEntity struct {
ID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false;" json:"TestID" yaml:"TestID"` ID string `gorm:"size:42;primaryKey;autoIncrement:false;" json:"TestID" yaml:"TestID"`
TestLabel string `gorm:"type:VARCHAR(400);uniqueIndex;" json:"Label" yaml:"Label"` TestLabel string `gorm:"type:VARCHAR(400);uniqueIndex;" json:"Label" yaml:"Label"`
TestCount int `gorm:"default:1" json:"Count" yaml:"-"` TestCount int `gorm:"default:1" json:"Count" yaml:"-"`
CreatedAt time.Time `json:"CreatedAt" yaml:"-"` CreatedAt time.Time `json:"CreatedAt" yaml:"-"`

View File

@@ -14,19 +14,19 @@ var photoDetailsMutex = sync.Mutex{}
type Details struct { type Details struct {
PhotoID uint `gorm:"primaryKey;autoIncrement:false" yaml:"-"` PhotoID uint `gorm:"primaryKey;autoIncrement:false" yaml:"-"`
Keywords string `gorm:"type:VARCHAR(2048);" json:"Keywords" yaml:"Keywords"` Keywords string `gorm:"type:VARCHAR(2048);" json:"Keywords" yaml:"Keywords"`
KeywordsSrc string `gorm:"type:VARBINARY(8);" json:"KeywordsSrc" yaml:"KeywordsSrc,omitempty"` KeywordsSrc string `gorm:"size:8;" json:"KeywordsSrc" yaml:"KeywordsSrc,omitempty"`
Notes string `gorm:"type:VARCHAR(2048);" json:"Notes" yaml:"Notes,omitempty"` Notes string `gorm:"type:VARCHAR(2048);" json:"Notes" yaml:"Notes,omitempty"`
NotesSrc string `gorm:"type:VARBINARY(8);" json:"NotesSrc" yaml:"NotesSrc,omitempty"` NotesSrc string `gorm:"size:8;" json:"NotesSrc" yaml:"NotesSrc,omitempty"`
Subject string `gorm:"type:VARCHAR(1024);" json:"Subject" yaml:"Subject,omitempty"` Subject string `gorm:"type:VARCHAR(1024);" json:"Subject" yaml:"Subject,omitempty"`
SubjectSrc string `gorm:"type:VARBINARY(8);" json:"SubjectSrc" yaml:"SubjectSrc,omitempty"` SubjectSrc string `gorm:"size:8;" json:"SubjectSrc" yaml:"SubjectSrc,omitempty"`
Artist string `gorm:"type:VARCHAR(1024);" json:"Artist" yaml:"Artist,omitempty"` Artist string `gorm:"type:VARCHAR(1024);" json:"Artist" yaml:"Artist,omitempty"`
ArtistSrc string `gorm:"type:VARBINARY(8);" json:"ArtistSrc" yaml:"ArtistSrc,omitempty"` ArtistSrc string `gorm:"size:8;" json:"ArtistSrc" yaml:"ArtistSrc,omitempty"`
Copyright string `gorm:"type:VARCHAR(1024);" json:"Copyright" yaml:"Copyright,omitempty"` Copyright string `gorm:"type:VARCHAR(1024);" json:"Copyright" yaml:"Copyright,omitempty"`
CopyrightSrc string `gorm:"type:VARBINARY(8);" json:"CopyrightSrc" yaml:"CopyrightSrc,omitempty"` CopyrightSrc string `gorm:"size:8;" json:"CopyrightSrc" yaml:"CopyrightSrc,omitempty"`
License string `gorm:"type:VARCHAR(1024);" json:"License" yaml:"License,omitempty"` License string `gorm:"type:VARCHAR(1024);" json:"License" yaml:"License,omitempty"`
LicenseSrc string `gorm:"type:VARBINARY(8);" json:"LicenseSrc" yaml:"LicenseSrc,omitempty"` LicenseSrc string `gorm:"size:8;" json:"LicenseSrc" yaml:"LicenseSrc,omitempty"`
Software string `gorm:"type:VARCHAR(1024);" json:"Software" yaml:"Software,omitempty"` Software string `gorm:"type:VARCHAR(1024);" json:"Software" yaml:"Software,omitempty"`
SoftwareSrc string `gorm:"type:VARBINARY(8);" json:"SoftwareSrc" yaml:"SoftwareSrc,omitempty"` SoftwareSrc string `gorm:"size:8;" json:"SoftwareSrc" yaml:"SoftwareSrc,omitempty"`
CreatedAt time.Time `yaml:"-"` CreatedAt time.Time `yaml:"-"`
UpdatedAt time.Time `yaml:"-"` UpdatedAt time.Time `yaml:"-"`
} }

View File

@@ -11,9 +11,9 @@ type DuplicatesMap map[string]Duplicate
// Duplicate represents an exact file duplicate. // Duplicate represents an exact file duplicate.
type Duplicate struct { type Duplicate struct {
FileName string `gorm:"type:VARBINARY(755);primaryKey;" json:"Name" yaml:"Name"` FileName string `gorm:"size:755;primaryKey;" json:"Name" yaml:"Name"`
FileRoot string `gorm:"type:VARBINARY(16);primaryKey;default:'/';" json:"Root" yaml:"Root,omitempty"` FileRoot string `gorm:"size:16;primaryKey;default:'/';" json:"Root" yaml:"Root,omitempty"`
FileHash string `gorm:"type:VARBINARY(128);default:'';index" json:"Hash" yaml:"Hash,omitempty"` FileHash string `gorm:"size:128;default:'';index" json:"Hash" yaml:"Hash,omitempty"`
FileSize int64 `json:"Size" yaml:"Size,omitempty"` FileSize int64 `json:"Size" yaml:"Size,omitempty"`
ModTime int64 `json:"ModTime" yaml:"-"` ModTime int64 `json:"ModTime" yaml:"-"`
} }

View File

@@ -29,7 +29,7 @@ func LabelCounts() LabelPhotoCounts {
JOIN photos ph ON pl.photo_id = ph.id JOIN photos ph ON pl.photo_id = ph.id
WHERE pl.uncertainty < 100 WHERE pl.uncertainty < 100
AND ph.photo_quality > -1 AND ph.photo_quality > -1
AND ph.photo_private = 0 AND ph.photo_private = FALSE
AND ph.deleted_at IS NULL GROUP BY l.id AND ph.deleted_at IS NULL GROUP BY l.id
UNION ALL UNION ALL
SELECT l.id AS label_id, COUNT(*) AS photo_count FROM labels l SELECT l.id AS label_id, COUNT(*) AS photo_count FROM labels l
@@ -38,7 +38,7 @@ func LabelCounts() LabelPhotoCounts {
JOIN photos ph ON pl.photo_id = ph.id JOIN photos ph ON pl.photo_id = ph.id
WHERE pl.uncertainty < 100 WHERE pl.uncertainty < 100
AND ph.photo_quality > -1 AND ph.photo_quality > -1
AND ph.photo_private = 0 AND ph.photo_private = FALSE
AND ph.deleted_at IS NULL GROUP BY l.id) counts GROUP BY label_id AND ph.deleted_at IS NULL GROUP BY l.id) counts GROUP BY label_id
`).Scan(&result).Error; err != nil { `).Scan(&result).Error; err != nil {
log.Errorf("label-count: %s", err.Error()) log.Errorf("label-count: %s", err.Error())
@@ -59,7 +59,7 @@ func UpdatePlacesCounts() (err error) {
UpdateColumn("photo_count", gorm.Expr("(SELECT COUNT(*) FROM photos p "+ UpdateColumn("photo_count", gorm.Expr("(SELECT COUNT(*) FROM photos p "+
"WHERE places.id = p.place_id "+ "WHERE places.id = p.place_id "+
"AND p.photo_quality > -1 "+ "AND p.photo_quality > -1 "+
"AND p.photo_private = 0 "+ "AND p.photo_private = FALSE "+
"AND p.deleted_at IS NULL)")) "AND p.deleted_at IS NULL)"))
if res.Error != nil { if res.Error != nil {
@@ -87,7 +87,7 @@ func UpdateSubjectCounts() (err error) {
condition := gorm.Expr("subj_type = ?", SubjPerson) condition := gorm.Expr("subj_type = ?", SubjPerson)
switch DbDialect() { switch DbDialect() {
case MySQL: case MySQL, Postgres:
res = Db().Exec(`UPDATE ? LEFT JOIN ( res = Db().Exec(`UPDATE ? LEFT JOIN (
SELECT m.subj_uid, COUNT(DISTINCT f.id) AS subj_files, COUNT(DISTINCT f.photo_id) AS subj_photos FROM ? f SELECT m.subj_uid, COUNT(DISTINCT f.id) AS subj_files, COUNT(DISTINCT f.photo_id) AS subj_photos FROM ? f
JOIN ? m ON f.file_uid = m.file_uid AND m.subj_uid IS NOT NULL AND m.subj_uid <> '' AND m.subj_uid IS NOT NULL JOIN ? m ON f.file_uid = m.file_uid AND m.subj_uid IS NOT NULL AND m.subj_uid <> '' AND m.subj_uid IS NOT NULL
@@ -133,17 +133,17 @@ func UpdateLabelCounts() (err error) {
start := time.Now() start := time.Now()
var res *gorm.DB var res *gorm.DB
if IsDialect(MySQL) { if IsDialect(MySQL) || IsDialect(Postgres) {
res = Db().Exec(`UPDATE labels LEFT JOIN ( res = Db().Exec(`UPDATE labels LEFT JOIN (
SELECT p2.label_id, COUNT(DISTINCT photo_id) AS label_photos FROM ( SELECT p2.label_id, COUNT(DISTINCT photo_id) AS label_photos FROM (
SELECT pl.label_id as label_id, p.id AS photo_id FROM photos p SELECT pl.label_id as label_id, p.id AS photo_id FROM photos p
JOIN photos_labels pl ON pl.photo_id = p.id AND pl.uncertainty < 100 JOIN photos_labels pl ON pl.photo_id = p.id AND pl.uncertainty < 100
WHERE p.photo_quality > -1 AND p.photo_private = 0 AND p.deleted_at IS NULL WHERE p.photo_quality > -1 AND p.photo_private = FALSE AND p.deleted_at IS NULL
UNION UNION
SELECT c.category_id as label_id, p.id AS photo_id FROM photos p SELECT c.category_id as label_id, p.id AS photo_id FROM photos p
JOIN photos_labels pl ON pl.photo_id = p.id AND pl.uncertainty < 100 JOIN photos_labels pl ON pl.photo_id = p.id AND pl.uncertainty < 100
JOIN categories c ON c.label_id = pl.label_id JOIN categories c ON c.label_id = pl.label_id
WHERE p.photo_quality > -1 AND p.photo_private = 0 AND p.deleted_at IS NULL WHERE p.photo_quality > -1 AND p.photo_private = FALSE AND p.deleted_at IS NULL
) p2 GROUP BY p2.label_id ) p2 GROUP BY p2.label_id
) b ON b.label_id = labels.id ) b ON b.label_id = labels.id
SET photo_count = CASE WHEN b.label_photos IS NULL THEN 0 ELSE b.label_photos END`) SET photo_count = CASE WHEN b.label_photos IS NULL THEN 0 ELSE b.label_photos END`)
@@ -157,7 +157,7 @@ func UpdateLabelCounts() (err error) {
JOIN photos ph ON pl.photo_id = ph.id JOIN photos ph ON pl.photo_id = ph.id
WHERE pl.uncertainty < 100 WHERE pl.uncertainty < 100
AND ph.photo_quality > -1 AND ph.photo_quality > -1
AND ph.photo_private = 0 AND ph.photo_private = FALSE
AND ph.deleted_at IS NULL GROUP BY l.id AND ph.deleted_at IS NULL GROUP BY l.id
UNION ALL UNION ALL
SELECT l.id AS label_id, COUNT(*) AS photo_count FROM labels l SELECT l.id AS label_id, COUNT(*) AS photo_count FROM labels l
@@ -166,7 +166,7 @@ func UpdateLabelCounts() (err error) {
JOIN photos ph ON pl.photo_id = ph.id JOIN photos ph ON pl.photo_id = ph.id
WHERE pl.uncertainty < 100 WHERE pl.uncertainty < 100
AND ph.photo_quality > -1 AND ph.photo_quality > -1
AND ph.photo_private = 0 AND ph.photo_private = FALSE
AND ph.deleted_at IS NULL GROUP BY l.id) counts GROUP BY label_id) label_counts WHERE label_id = labels.id)`)) AND ph.deleted_at IS NULL GROUP BY l.id) counts GROUP BY label_id) label_counts WHERE label_id = labels.id)`))
} else { } else {
return fmt.Errorf("sql: unsupported dialect %s", DbDialect()) return fmt.Errorf("sql: unsupported dialect %s", DbDialect())
@@ -217,13 +217,13 @@ func UpdateCounts() (err error) {
default: default:
if err = UnscopedDb().Exec(`UPDATE albums SET deleted_at = ? WHERE album_type=? AND id NOT IN ( if err = UnscopedDb().Exec(`UPDATE albums SET deleted_at = ? WHERE album_type=? AND id NOT IN (
SELECT a.id FROM albums a JOIN photos p ON a.album_month = MONTH(p.taken_at) AND a.album_year = YEAR(p.taken_at) SELECT a.id FROM albums a JOIN photos p ON a.album_month = MONTH(p.taken_at) AND a.album_year = YEAR(p.taken_at)
AND p.deleted_at IS NULL AND p.photo_quality > -1 AND p.photo_private = 0 WHERE album_type=? GROUP BY a.id)`, AND p.deleted_at IS NULL AND p.photo_quality > -1 AND p.photo_private = FALSE WHERE album_type=? GROUP BY a.id)`,
TimeStamp(), AlbumMonth, AlbumMonth).Error; err != nil { TimeStamp(), AlbumMonth, AlbumMonth).Error; err != nil {
return err return err
} }
if err = UnscopedDb().Exec(`UPDATE albums SET deleted_at = NULL WHERE album_type=? AND id IN ( if err = UnscopedDb().Exec(`UPDATE albums SET deleted_at = NULL WHERE album_type=? AND id IN (
SELECT a.id FROM albums a JOIN photos p ON a.album_month = MONTH(p.taken_at) AND a.album_year = YEAR(p.taken_at) SELECT a.id FROM albums a JOIN photos p ON a.album_month = MONTH(p.taken_at) AND a.album_year = YEAR(p.taken_at)
AND p.deleted_at IS NULL AND p.photo_quality > -1 AND p.photo_private = 0 WHERE album_type=? GROUP BY a.id)`, AND p.deleted_at IS NULL AND p.photo_quality > -1 AND p.photo_private = FALSE WHERE album_type=? GROUP BY a.id)`,
AlbumMonth, AlbumMonth).Error; err != nil { AlbumMonth, AlbumMonth).Error; err != nil {
return err return err
} }

View File

@@ -61,7 +61,7 @@ func (list Tables) WaitForMigration(db *gorm.DB) error {
Count int Count int
} }
attempts := 100 const attempts = 100
for name := range list { for name := range list {
for i := 0; i <= attempts; i++ { for i := 0; i <= attempts; i++ {
count := RowCount{} count := RowCount{}
@@ -105,7 +105,6 @@ func (list Tables) Truncate(db *gorm.DB) {
// Migrate migrates all database tables of registered entities. // Migrate migrates all database tables of registered entities.
func (list Tables) Migrate(db *gorm.DB, opt migrate.Options) { func (list Tables) Migrate(db *gorm.DB, opt migrate.Options) {
var name string var name string
var entity interface{}
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
@@ -122,7 +121,37 @@ func (list Tables) Migrate(db *gorm.DB, opt migrate.Options) {
// Run ORM auto migrations. // Run ORM auto migrations.
if opt.AutoMigrate { if opt.AutoMigrate {
// Setup required explicit join tables
err := db.SetupJoinTable(&Photo{}, "Albums", &PhotoAlbum{})
if err != nil {
log.Error("migrate: could not setup join table for Photo - Albums: ", err)
}
err = db.SetupJoinTable(&Photo{}, "Keywords", &PhotoKeyword{})
if err != nil {
log.Error("migrate: could not setup join table for Photo - Keywords: ", err)
}
err = db.SetupJoinTable(&Label{}, "LabelCategories", &Category{})
if err != nil {
log.Error("migrate: could not setup join table for Label - Categories: ", err)
}
/*
ifaces := make([]interface{}, len(list))
idx := 0
for _, value := range list {
ifaces[idx] = value
idx++
}
log.Debugf("migrate: auto-migrating %d entity tables", len(ifaces))
err = db.AutoMigrate(ifaces...)
if err != nil {
log.Error("migrate: auto-migration of entities failed: ", err)
}*/
var entity interface{}
for name, entity = range list { for name, entity = range list {
log.Debugf("migrate: auto-migrating %s", name)
if err := db.AutoMigrate(entity); err != nil { if err := db.AutoMigrate(entity); err != nil {
log.Debugf("migrate: %s (waiting 1s)", err.Error()) log.Debugf("migrate: %s (waiting 1s)", err.Error())

View File

@@ -11,8 +11,8 @@ import (
type Error struct { type Error struct {
ID uint `gorm:"primaryKey" json:"ID" yaml:"ID"` ID uint `gorm:"primaryKey" json:"ID" yaml:"ID"`
ErrorTime time.Time `sql:"index" json:"Time" yaml:"Time"` ErrorTime time.Time `sql:"index" json:"Time" yaml:"Time"`
ErrorLevel string `gorm:"type:VARBINARY(32)" json:"Level" yaml:"Level"` ErrorLevel string `gorm:"size:32" json:"Level" yaml:"Level"`
ErrorMessage string `gorm:"type:VARBINARY(2048)" json:"Message" yaml:"Message"` ErrorMessage string `gorm:"size:2048" json:"Message" yaml:"Message"`
} }
// Errors represents a list of error log messages. // Errors represents a list of error log messages.

View File

@@ -19,16 +19,16 @@ var UpdateFaces = atomic.Bool{}
// Face represents the face of a Subject. // Face represents the face of a Subject.
type Face struct { type Face struct {
ID string `gorm:"type:VARBINARY(64);primaryKey;autoIncrement:false;" json:"ID" yaml:"ID"` ID string `gorm:"size:64;primaryKey;autoIncrement:false;" json:"ID" yaml:"ID"`
FaceSrc string `gorm:"type:VARBINARY(8);" json:"Src" yaml:"Src,omitempty"` FaceSrc string `gorm:"size:8;" json:"Src" yaml:"Src,omitempty"`
FaceKind int `json:"Kind" yaml:"Kind,omitempty"` FaceKind int `json:"Kind" yaml:"Kind,omitempty"`
FaceHidden bool `json:"Hidden" yaml:"Hidden,omitempty"` FaceHidden bool `json:"Hidden" yaml:"Hidden,omitempty"`
SubjUID string `gorm:"type:VARBINARY(42);index;default:'';" json:"SubjUID" yaml:"SubjUID,omitempty"` SubjUID string `gorm:"size:42;index;default:'';" json:"SubjUID" yaml:"SubjUID,omitempty"`
Samples int `json:"Samples" yaml:"Samples,omitempty"` Samples int `json:"Samples" yaml:"Samples,omitempty"`
SampleRadius float64 `json:"SampleRadius" yaml:"SampleRadius,omitempty"` SampleRadius float64 `json:"SampleRadius" yaml:"SampleRadius,omitempty"`
Collisions int `json:"Collisions" yaml:"Collisions,omitempty"` Collisions int `json:"Collisions" yaml:"Collisions,omitempty"`
CollisionRadius float64 `json:"CollisionRadius" yaml:"CollisionRadius,omitempty"` CollisionRadius float64 `json:"CollisionRadius" yaml:"CollisionRadius,omitempty"`
EmbeddingJSON json.RawMessage `gorm:"type:MEDIUMBLOB;" json:"-" yaml:"EmbeddingJSON,omitempty"` EmbeddingJSON json.RawMessage `json:"-" yaml:"EmbeddingJSON,omitempty"`
embedding face.Embedding `gorm:"-" yaml:"-"` embedding face.Embedding `gorm:"-" yaml:"-"`
MatchedAt *time.Time `json:"MatchedAt" yaml:"MatchedAt,omitempty"` MatchedAt *time.Time `json:"MatchedAt" yaml:"MatchedAt,omitempty"`
CreatedAt time.Time `json:"CreatedAt" yaml:"CreatedAt,omitempty"` CreatedAt time.Time `json:"CreatedAt" yaml:"CreatedAt,omitempty"`

View File

@@ -42,22 +42,22 @@ type File struct {
ID uint `gorm:"primaryKey" json:"-" yaml:"-"` ID uint `gorm:"primaryKey" json:"-" yaml:"-"`
Photo *Photo `json:"-" yaml:"-"` Photo *Photo `json:"-" yaml:"-"`
PhotoID uint `gorm:"index:idx_files_photo_id;" json:"-" yaml:"-"` PhotoID uint `gorm:"index:idx_files_photo_id;" json:"-" yaml:"-"`
PhotoUID string `gorm:"type:VARBINARY(42);index;" json:"PhotoUID" yaml:"PhotoUID"` PhotoUID string `gorm:"size:42;index;" json:"PhotoUID" yaml:"PhotoUID"`
PhotoTakenAt time.Time `gorm:"type:DATETIME;index;" json:"TakenAt" yaml:"TakenAt"` PhotoTakenAt time.Time `gorm:"index;" json:"TakenAt" yaml:"TakenAt"`
TimeIndex *string `gorm:"type:VARBINARY(64);" json:"TimeIndex" yaml:"TimeIndex"` TimeIndex *string `gorm:"size:64;" json:"TimeIndex" yaml:"TimeIndex"`
MediaID *string `gorm:"type:VARBINARY(32);" json:"MediaID" yaml:"MediaID"` MediaID *string `gorm:"size:32;" json:"MediaID" yaml:"MediaID"`
MediaUTC int64 `gorm:"column:media_utc;index;" json:"MediaUTC" yaml:"MediaUTC,omitempty"` MediaUTC int64 `gorm:"column:media_utc;index;" json:"MediaUTC" yaml:"MediaUTC,omitempty"`
InstanceID string `gorm:"type:VARBINARY(64);index;" json:"InstanceID,omitempty" yaml:"InstanceID,omitempty"` InstanceID string `gorm:"size:64;index;" json:"InstanceID,omitempty" yaml:"InstanceID,omitempty"`
FileUID string `gorm:"type:VARBINARY(42);uniqueIndex;" json:"UID" yaml:"UID"` FileUID string `gorm:"size:42;uniqueIndex;" json:"UID" yaml:"UID"`
FileName string `gorm:"type:VARBINARY(1024);uniqueIndex:idx_files_name_root;" json:"Name" yaml:"Name"` FileName string `gorm:"size:1024;uniqueIndex:idx_files_name_root;" json:"Name" yaml:"Name"`
FileRoot string `gorm:"type:VARBINARY(16);default:'/';uniqueIndex:idx_files_name_root;" json:"Root" yaml:"Root,omitempty"` FileRoot string `gorm:"size:16;default:'/';uniqueIndex:idx_files_name_root;" json:"Root" yaml:"Root,omitempty"`
OriginalName string `gorm:"type:VARBINARY(755);" json:"OriginalName" yaml:"OriginalName,omitempty"` OriginalName string `gorm:"size:755;" json:"OriginalName" yaml:"OriginalName,omitempty"`
FileHash string `gorm:"type:VARBINARY(128);index" json:"Hash" yaml:"Hash,omitempty"` FileHash string `gorm:"size:128;index" json:"Hash" yaml:"Hash,omitempty"`
FileSize int64 `json:"Size" yaml:"Size,omitempty"` FileSize int64 `json:"Size" yaml:"Size,omitempty"`
FileCodec string `gorm:"type:VARBINARY(32)" json:"Codec" yaml:"Codec,omitempty"` FileCodec string `gorm:"size:32" json:"Codec" yaml:"Codec,omitempty"`
FileType string `gorm:"type:VARBINARY(16)" json:"FileType" yaml:"FileType,omitempty"` FileType string `gorm:"size:16" json:"FileType" yaml:"FileType,omitempty"`
MediaType string `gorm:"type:VARBINARY(16)" json:"MediaType" yaml:"MediaType,omitempty"` MediaType string `gorm:"size:16" json:"MediaType" yaml:"MediaType,omitempty"`
FileMime string `gorm:"type:VARBINARY(64)" json:"Mime" yaml:"Mime,omitempty"` FileMime string `gorm:"size:64" json:"Mime" yaml:"Mime,omitempty"`
FilePrimary bool `gorm:"index:idx_files_photo_id;" json:"Primary" yaml:"Primary,omitempty"` FilePrimary bool `gorm:"index:idx_files_photo_id;" json:"Primary" yaml:"Primary,omitempty"`
FileSidecar bool `json:"Sidecar" yaml:"Sidecar,omitempty"` FileSidecar bool `json:"Sidecar" yaml:"Sidecar,omitempty"`
FileMissing bool `json:"Missing" yaml:"Missing,omitempty"` FileMissing bool `json:"Missing" yaml:"Missing,omitempty"`
@@ -69,19 +69,19 @@ type File struct {
FileWidth int `gorm:"column:file_width;" json:"Width" yaml:"Width,omitempty"` FileWidth int `gorm:"column:file_width;" json:"Width" yaml:"Width,omitempty"`
FileHeight int `gorm:"column:file_height;" json:"Height" yaml:"Height,omitempty"` FileHeight int `gorm:"column:file_height;" json:"Height" yaml:"Height,omitempty"`
FileOrientation int `gorm:"column:file_orientation;" json:"Orientation" yaml:"Orientation,omitempty"` FileOrientation int `gorm:"column:file_orientation;" json:"Orientation" yaml:"Orientation,omitempty"`
FileOrientationSrc string `gorm:"column:file_orientation_src;type:VARBINARY(8);default:'';" json:"OrientationSrc" yaml:"OrientationSrc,omitempty"` FileOrientationSrc string `gorm:"column:file_orientation_src;size:8;default:'';" json:"OrientationSrc" yaml:"OrientationSrc,omitempty"`
FileProjection string `gorm:"column:file_projection;type:VARBINARY(64);" json:"Projection,omitempty" yaml:"Projection,omitempty"` FileProjection string `gorm:"column:file_projection;size:64;" json:"Projection,omitempty" yaml:"Projection,omitempty"`
FileAspectRatio float32 `gorm:"column:file_aspect_ratio;type:FLOAT;" json:"AspectRatio" yaml:"AspectRatio,omitempty"` FileAspectRatio float32 `gorm:"column:file_aspect_ratio;type:FLOAT;" json:"AspectRatio" yaml:"AspectRatio,omitempty"`
FileHDR bool `gorm:"column:file_hdr;" json:"HDR" yaml:"HDR,omitempty"` FileHDR bool `gorm:"column:file_hdr;" json:"HDR" yaml:"HDR,omitempty"`
FileWatermark bool `gorm:"column:file_watermark;" json:"Watermark" yaml:"Watermark,omitempty"` FileWatermark bool `gorm:"column:file_watermark;" json:"Watermark" yaml:"Watermark,omitempty"`
FileColorProfile string `gorm:"type:VARBINARY(64);" json:"ColorProfile,omitempty" yaml:"ColorProfile,omitempty"` FileColorProfile string `gorm:"size:64;" json:"ColorProfile,omitempty" yaml:"ColorProfile,omitempty"`
FileMainColor string `gorm:"type:VARBINARY(16);" json:"MainColor" yaml:"MainColor,omitempty"` FileMainColor string `gorm:"size:16;" json:"MainColor" yaml:"MainColor,omitempty"`
FileColors string `gorm:"type:VARBINARY(18);" json:"Colors" yaml:"Colors,omitempty"` FileColors string `gorm:"size:18;" json:"Colors" yaml:"Colors,omitempty"`
FileLuminance string `gorm:"type:VARBINARY(18);" json:"Luminance" yaml:"Luminance,omitempty"` FileLuminance string `gorm:"size:18;" json:"Luminance" yaml:"Luminance,omitempty"`
FileDiff int `json:"Diff" yaml:"Diff,omitempty"` FileDiff int `json:"Diff" yaml:"Diff,omitempty"`
FileChroma int16 `json:"Chroma" yaml:"Chroma,omitempty"` FileChroma int16 `json:"Chroma" yaml:"Chroma,omitempty"`
FileSoftware string `gorm:"type:VARCHAR(64)" json:"Software" yaml:"Software,omitempty"` FileSoftware string `gorm:"type:VARCHAR(64)" json:"Software" yaml:"Software,omitempty"`
FileError string `gorm:"type:VARBINARY(512);index;" json:"Error" yaml:"Error,omitempty"` FileError string `gorm:"size:512;index;" json:"Error" yaml:"Error,omitempty"`
ModTime int64 `json:"ModTime" yaml:"-"` ModTime int64 `json:"ModTime" yaml:"-"`
CreatedAt time.Time `json:"CreatedAt" yaml:"-"` CreatedAt time.Time `json:"CreatedAt" yaml:"-"`
CreatedIn int64 `json:"CreatedIn" yaml:"-"` CreatedIn int64 `json:"CreatedIn" yaml:"-"`
@@ -89,8 +89,8 @@ type File struct {
UpdatedIn int64 `json:"UpdatedIn" yaml:"-"` UpdatedIn int64 `json:"UpdatedIn" yaml:"-"`
PublishedAt *time.Time `sql:"index" json:"PublishedAt,omitempty" yaml:"PublishedAt,omitempty"` PublishedAt *time.Time `sql:"index" json:"PublishedAt,omitempty" yaml:"PublishedAt,omitempty"`
DeletedAt *time.Time `sql:"index" json:"DeletedAt,omitempty" yaml:"-"` DeletedAt *time.Time `sql:"index" json:"DeletedAt,omitempty" yaml:"-"`
Share []FileShare `json:"-" yaml:"-"` Share []FileShare `gorm:"foreignKey:FileID" json:"-" yaml:"-"`
Sync []FileSync `json:"-" yaml:"-"` Sync []FileSync `gorm:"foreignKey:FileID" json:"-" yaml:"-"`
markers *Markers markers *Markers
} }
@@ -126,13 +126,13 @@ func (m File) RegenerateIndex() {
} }
switch DbDialect() { switch DbDialect() {
case MySQL: case MySQL, Postgres:
Log("files", "regenerate photo_taken_at", Log("files", "regenerate photo_taken_at",
Db().Exec("UPDATE files JOIN ? p ON p.id = files.photo_id SET files.photo_taken_at = p.taken_at_local WHERE ?", Db().Exec("UPDATE files JOIN ? p ON p.id = files.photo_id SET files.photo_taken_at = p.taken_at_local WHERE ?",
gorm.Expr(photosTable), updateWhere).Error) gorm.Expr(photosTable), updateWhere).Error)
Log("files", "regenerate media_id", Log("files", "regenerate media_id",
Db().Exec("UPDATE files SET media_id = CASE WHEN file_missing = 0 AND deleted_at IS NULL THEN CONCAT((10000000000 - photo_id), '-', 1 + file_sidecar - file_primary, '-', file_uid) ELSE NULL END WHERE ?", Db().Exec("UPDATE files SET media_id = CASE WHEN file_missing = FALSE AND deleted_at IS NULL THEN CONCAT((10000000000 - photo_id), '-', 1 + file_sidecar - file_primary, '-', file_uid) ELSE NULL END WHERE ?",
updateWhere).Error) updateWhere).Error)
Log("files", "regenerate time_index", Log("files", "regenerate time_index",
@@ -144,7 +144,7 @@ func (m File) RegenerateIndex() {
gorm.Expr(photosTable), updateWhere).Error) gorm.Expr(photosTable), updateWhere).Error)
Log("files", "regenerate media_id", Log("files", "regenerate media_id",
Db().Exec("UPDATE files SET media_id = CASE WHEN file_missing = 0 AND deleted_at IS NULL THEN ((10000000000 - photo_id) || '-' || (1 + file_sidecar - file_primary) || '-' || file_uid) ELSE NULL END WHERE ?", Db().Exec("UPDATE files SET media_id = CASE WHEN file_missing = FALSE AND deleted_at IS NULL THEN ((10000000000 - photo_id) || '-' || (1 + file_sidecar - file_primary) || '-' || file_uid) ELSE NULL END WHERE ?",
updateWhere).Error) updateWhere).Error)
Log("files", "regenerate time_index", Log("files", "regenerate time_index",
@@ -170,7 +170,7 @@ func FirstFileByHash(fileHash string) (File, error) {
func PrimaryFile(photoUid string) (*File, error) { func PrimaryFile(photoUid string) (*File, error) {
file := File{} file := File{}
res := Db().Unscoped().First(&file, "file_primary = 1 AND photo_uid = ?", photoUid) res := Db().Unscoped().First(&file, "file_primary = TRUE AND photo_uid = ?", photoUid)
return &file, res.Error return &file, res.Error
} }
@@ -369,14 +369,14 @@ func (m *File) Purge() error {
m.FileMissing = true m.FileMissing = true
m.FilePrimary = false m.FilePrimary = false
m.DeletedAt = &deletedAt m.DeletedAt = &deletedAt
return UnscopedDb().Exec("UPDATE files SET file_missing = 1, file_primary = 0, deleted_at = ? WHERE id = ?", &deletedAt, m.ID).Error return UnscopedDb().Exec("UPDATE files SET file_missing = TRUE, file_primary = FALSE, deleted_at = ? WHERE id = ?", &deletedAt, m.ID).Error
} }
// Found restores a previously purged file. // Found restores a previously purged file.
func (m *File) Found() error { func (m *File) Found() error {
m.FileMissing = false m.FileMissing = false
m.DeletedAt = nil m.DeletedAt = nil
return UnscopedDb().Exec("UPDATE files SET file_missing = 0, deleted_at = NULL WHERE id = ?", m.ID).Error return UnscopedDb().Exec("UPDATE files SET file_missing = FALSE, deleted_at = NULL WHERE id = ?", m.ID).Error
} }
// AllFilesMissing returns true, if all files for the photo of this file are missing. // AllFilesMissing returns true, if all files for the photo of this file are missing.
@@ -384,7 +384,7 @@ func (m *File) AllFilesMissing() bool {
count := int64(0) count := int64(0)
if err := Db().Model(&File{}). if err := Db().Model(&File{}).
Where("photo_id = ? AND file_missing = 0", m.PhotoID). Where("photo_id = ? AND file_missing = FALSE", m.PhotoID).
Count(&count).Error; err != nil { Count(&count).Error; err != nil {
log.Errorf("file: %s", err.Error()) log.Errorf("file: %s", err.Error())
} }

View File

@@ -15,11 +15,11 @@ const (
type FileShare struct { type FileShare struct {
FileID uint `gorm:"primaryKey;autoIncrement:false"` FileID uint `gorm:"primaryKey;autoIncrement:false"`
ServiceID uint `gorm:"primaryKey;autoIncrement:false"` ServiceID uint `gorm:"primaryKey;autoIncrement:false"`
RemoteName string `gorm:"primaryKey;autoIncrement:false;type:VARBINARY(255)"` RemoteName string `gorm:"primaryKey;autoIncrement:false;size:255"`
Status string `gorm:"type:VARBINARY(16);"` Status string `gorm:"size:16;"`
Error string `gorm:"type:VARBINARY(512);"` Error string `gorm:"size:512;"`
Errors int Errors int
File *File File *File `gorm:"foreignKey:FileID"`
Account *Service `gorm:"foreignKey:ServiceID"` Account *Service `gorm:"foreignKey:ServiceID"`
CreatedAt time.Time CreatedAt time.Time
UpdatedAt time.Time UpdatedAt time.Time

View File

@@ -14,13 +14,13 @@ const (
// FileSync represents a one-to-many relation between File and Account for syncing with remote services. // FileSync represents a one-to-many relation between File and Account for syncing with remote services.
type FileSync struct { type FileSync struct {
RemoteName string `gorm:"primaryKey;autoIncrement:false;type:VARBINARY(255)"` RemoteName string `gorm:"primaryKey;autoIncrement:false;size:255"`
ServiceID uint `gorm:"primaryKey;autoIncrement:false"` ServiceID uint `gorm:"primaryKey;autoIncrement:false"`
FileID uint `gorm:"index;"` FileID uint `gorm:"index;"`
RemoteDate time.Time RemoteDate time.Time
RemoteSize int64 RemoteSize int64
Status string `gorm:"type:VARBINARY(16);"` Status string `gorm:"size:16;"`
Error string `gorm:"type:VARBINARY(512);"` Error string `gorm:"size:512;"`
Errors int Errors int
File *File `gorm:"foreignKey:FileID"` File *File `gorm:"foreignKey:FileID"`
Account *Service `gorm:"foreignKey:ServiceID"` Account *Service `gorm:"foreignKey:ServiceID"`

View File

@@ -23,15 +23,15 @@ type Folders []Folder
// Folder represents a file system directory. // Folder represents a file system directory.
type Folder struct { type Folder struct {
Path string `gorm:"type:VARBINARY(1024);uniqueIndex:idx_folders_path_root;" json:"Path" yaml:"Path"` Path string `gorm:"size:1024;uniqueIndex:idx_folders_path_root;" json:"Path" yaml:"Path"`
Root string `gorm:"type:VARBINARY(16);default:'';uniqueIndex:idx_folders_path_root;" json:"Root" yaml:"Root,omitempty"` Root string `gorm:"size:16;default:'';uniqueIndex:idx_folders_path_root;" json:"Root" yaml:"Root,omitempty"`
FolderUID string `gorm:"type:VARBINARY(42);primaryKey;" json:"UID,omitempty" yaml:"UID,omitempty"` FolderUID string `gorm:"size:42;primaryKey;" json:"UID,omitempty" yaml:"UID,omitempty"`
FolderType string `gorm:"type:VARBINARY(16);" json:"Type" yaml:"Type,omitempty"` FolderType string `gorm:"size:16;" json:"Type" yaml:"Type,omitempty"`
FolderTitle string `gorm:"type:VARCHAR(200);" json:"Title" yaml:"Title,omitempty"` FolderTitle string `gorm:"type:VARCHAR(200);" json:"Title" yaml:"Title,omitempty"`
FolderCategory string `gorm:"type:VARCHAR(100);index;" json:"Category" yaml:"Category,omitempty"` FolderCategory string `gorm:"type:VARCHAR(100);index;" json:"Category" yaml:"Category,omitempty"`
FolderDescription string `gorm:"type:VARCHAR(2048);" json:"Description,omitempty" yaml:"Description,omitempty"` FolderDescription string `gorm:"type:VARCHAR(2048);" json:"Description,omitempty" yaml:"Description,omitempty"`
FolderOrder string `gorm:"type:VARBINARY(32);" json:"Order" yaml:"Order,omitempty"` FolderOrder string `gorm:"size:32;" json:"Order" yaml:"Order,omitempty"`
FolderCountry string `gorm:"type:VARBINARY(2);index:idx_folders_country_year_month;default:'zz'" json:"Country" yaml:"Country,omitempty"` FolderCountry string `gorm:"size:2;index:idx_folders_country_year_month;default:'zz'" json:"Country" yaml:"Country,omitempty"`
FolderYear int `gorm:"index:idx_folders_country_year_month;" json:"Year" yaml:"Year,omitempty"` FolderYear int `gorm:"index:idx_folders_country_year_month;" json:"Year" yaml:"Year,omitempty"`
FolderMonth int `gorm:"index:idx_folders_country_year_month;" json:"Month" yaml:"Month,omitempty"` FolderMonth int `gorm:"index:idx_folders_country_year_month;" json:"Month" yaml:"Month,omitempty"`
FolderDay int `json:"Day" yaml:"Day,omitempty"` FolderDay int `json:"Day" yaml:"Day,omitempty"`

View File

@@ -26,18 +26,18 @@ type Labels []Label
// Label is used for photo, album and location categorization // Label is used for photo, album and location categorization
type Label struct { type Label struct {
ID uint `gorm:"primaryKey" json:"ID" yaml:"-"` ID uint `gorm:"primaryKey" json:"ID" yaml:"-"`
LabelUID string `gorm:"type:VARBINARY(42);uniqueIndex;" json:"UID" yaml:"UID"` LabelUID string `gorm:"size:42;uniqueIndex;" json:"UID" yaml:"UID"`
LabelSlug string `gorm:"type:VARBINARY(160);uniqueIndex;" json:"Slug" yaml:"-"` LabelSlug string `gorm:"size:160;uniqueIndex;" json:"Slug" yaml:"-"`
CustomSlug string `gorm:"type:VARBINARY(160);index;" json:"CustomSlug" yaml:"-"` CustomSlug string `gorm:"size:160;index;" json:"CustomSlug" yaml:"-"`
LabelName string `gorm:"type:VARCHAR(160);" json:"Name" yaml:"Name"` LabelName string `gorm:"type:VARCHAR(160);" json:"Name" yaml:"Name"`
LabelPriority int `json:"Priority" yaml:"Priority,omitempty"` LabelPriority int `json:"Priority" yaml:"Priority,omitempty"`
LabelFavorite bool `json:"Favorite" yaml:"Favorite,omitempty"` LabelFavorite bool `json:"Favorite" yaml:"Favorite,omitempty"`
LabelDescription string `gorm:"type:VARCHAR(2048);" json:"Description" yaml:"Description,omitempty"` LabelDescription string `gorm:"type:VARCHAR(2048);" json:"Description" yaml:"Description,omitempty"`
LabelNotes string `gorm:"type:VARCHAR(1024);" json:"Notes" yaml:"Notes,omitempty"` LabelNotes string `gorm:"type:VARCHAR(1024);" json:"Notes" yaml:"Notes,omitempty"`
LabelCategories []*Label `gorm:"many2many:categories;joinForeignKey:category_id" json:"-" yaml:"-"` LabelCategories []*Label `gorm:"many2many:categories;foreignKey:ID;joinForeignKey:LabelID;References:ID;joinReferences:CategoryID" json:"-" yaml:"-"`
PhotoCount int `gorm:"default:1" json:"PhotoCount" yaml:"-"` PhotoCount int `gorm:"default:1" json:"PhotoCount" yaml:"-"`
Thumb string `gorm:"type:VARBINARY(128);index;default:''" json:"Thumb" yaml:"Thumb,omitempty"` Thumb string `gorm:"size:128;index;default:''" json:"Thumb" yaml:"Thumb,omitempty"`
ThumbSrc string `gorm:"type:VARBINARY(8);default:''" json:"ThumbSrc,omitempty" yaml:"ThumbSrc,omitempty"` ThumbSrc string `gorm:"size:8;default:''" json:"ThumbSrc,omitempty" yaml:"ThumbSrc,omitempty"`
CreatedAt time.Time `json:"CreatedAt" yaml:"-"` CreatedAt time.Time `json:"CreatedAt" yaml:"-"`
UpdatedAt time.Time `json:"UpdatedAt" yaml:"-"` UpdatedAt time.Time `json:"UpdatedAt" yaml:"-"`
PublishedAt *time.Time `sql:"index" json:"PublishedAt,omitempty" yaml:"PublishedAt,omitempty"` PublishedAt *time.Time `sql:"index" json:"PublishedAt,omitempty" yaml:"PublishedAt,omitempty"`

View File

@@ -13,10 +13,10 @@ type Users []User
type User struct { type User struct {
ID int `gorm:"primaryKey" json:"-" yaml:"-"` ID int `gorm:"primaryKey" json:"-" yaml:"-"`
AddressID int `gorm:"default:1" json:"-" yaml:"-"` AddressID int `gorm:"default:1" json:"-" yaml:"-"`
UserUID string `gorm:"type:VARBINARY(42);uniqueIndex;" json:"UID" yaml:"UID"` UserUID string `gorm:"size:42;uniqueIndex;" json:"UID" yaml:"UID"`
MotherUID string `gorm:"type:VARBINARY(42);" json:"MotherUID" yaml:"MotherUID,omitempty"` MotherUID string `gorm:"size:42;" json:"MotherUID" yaml:"MotherUID,omitempty"`
FatherUID string `gorm:"type:VARBINARY(42);" json:"FatherUID" yaml:"FatherUID,omitempty"` FatherUID string `gorm:"size:42;" json:"FatherUID" yaml:"FatherUID,omitempty"`
GlobalUID string `gorm:"type:VARBINARY(42);index;" json:"GlobalUID" yaml:"GlobalUID,omitempty"` GlobalUID string `gorm:"size:42;index;" json:"GlobalUID" yaml:"GlobalUID,omitempty"`
FullName string `gorm:"size:128;" json:"FullName" yaml:"FullName,omitempty"` FullName string `gorm:"size:128;" json:"FullName" yaml:"FullName,omitempty"`
NickName string `gorm:"size:64;" json:"NickName" yaml:"NickName,omitempty"` NickName string `gorm:"size:64;" json:"NickName" yaml:"NickName,omitempty"`
MaidenName string `gorm:"size:64;" json:"MaidenName" yaml:"MaidenName,omitempty"` MaidenName string `gorm:"size:64;" json:"MaidenName" yaml:"MaidenName,omitempty"`
@@ -28,14 +28,14 @@ type User struct {
PrimaryEmail string `gorm:"size:255;index;" json:"PrimaryEmail" yaml:"PrimaryEmail,omitempty"` PrimaryEmail string `gorm:"size:255;index;" json:"PrimaryEmail" yaml:"PrimaryEmail,omitempty"`
EmailConfirmed bool `json:"EmailConfirmed" yaml:"EmailConfirmed,omitempty"` EmailConfirmed bool `json:"EmailConfirmed" yaml:"EmailConfirmed,omitempty"`
BackupEmail string `gorm:"size:255;" json:"BackupEmail" yaml:"BackupEmail,omitempty"` BackupEmail string `gorm:"size:255;" json:"BackupEmail" yaml:"BackupEmail,omitempty"`
PersonURL string `gorm:"type:VARBINARY(255);" json:"PersonURL" yaml:"PersonURL,omitempty"` PersonURL string `gorm:"size:255;" json:"PersonURL" yaml:"PersonURL,omitempty"`
PersonPhone string `gorm:"size:32;" json:"PersonPhone" yaml:"PersonPhone,omitempty"` PersonPhone string `gorm:"size:32;" json:"PersonPhone" yaml:"PersonPhone,omitempty"`
PersonStatus string `gorm:"size:32;" json:"PersonStatus" yaml:"PersonStatus,omitempty"` PersonStatus string `gorm:"size:32;" json:"PersonStatus" yaml:"PersonStatus,omitempty"`
PersonAvatar string `gorm:"type:VARBINARY(255);" json:"PersonAvatar" yaml:"PersonAvatar,omitempty"` PersonAvatar string `gorm:"size:255;" json:"PersonAvatar" yaml:"PersonAvatar,omitempty"`
PersonLocation string `gorm:"size:128;" json:"PersonLocation" yaml:"PersonLocation,omitempty"` PersonLocation string `gorm:"size:128;" json:"PersonLocation" yaml:"PersonLocation,omitempty"`
PersonBio string `gorm:"type:TEXT;" json:"PersonBio" yaml:"PersonBio,omitempty"` PersonBio string `gorm:"type:TEXT;" json:"PersonBio" yaml:"PersonBio,omitempty"`
PersonAccounts string `gorm:"type:LONGTEXT;" json:"-" yaml:"-"` PersonAccounts string `gorm:"type:LONGTEXT;" json:"-" yaml:"-"`
BusinessURL string `gorm:"type:VARBINARY(255);" json:"BusinessURL" yaml:"BusinessURL,omitempty"` BusinessURL string `gorm:"size:255;" json:"BusinessURL" yaml:"BusinessURL,omitempty"`
BusinessPhone string `gorm:"size:32;" json:"BusinessPhone" yaml:"BusinessPhone,omitempty"` BusinessPhone string `gorm:"size:32;" json:"BusinessPhone" yaml:"BusinessPhone,omitempty"`
BusinessEmail string `gorm:"size:255;" json:"BusinessEmail" yaml:"BusinessEmail,omitempty"` BusinessEmail string `gorm:"size:255;" json:"BusinessEmail" yaml:"BusinessEmail,omitempty"`
CompanyName string `gorm:"size:128;" json:"CompanyName" yaml:"CompanyName,omitempty"` CompanyName string `gorm:"size:128;" json:"CompanyName" yaml:"CompanyName,omitempty"`
@@ -53,14 +53,14 @@ type User struct {
RoleFamily bool `json:"RoleFamily" yaml:"RoleFamily,omitempty"` RoleFamily bool `json:"RoleFamily" yaml:"RoleFamily,omitempty"`
RoleFriend bool `json:"RoleFriend" yaml:"RoleFriend,omitempty"` RoleFriend bool `json:"RoleFriend" yaml:"RoleFriend,omitempty"`
WebDAV bool `gorm:"column:webdav" json:"WebDAV" yaml:"WebDAV,omitempty"` WebDAV bool `gorm:"column:webdav" json:"WebDAV" yaml:"WebDAV,omitempty"`
StoragePath string `gorm:"column:storage_path;type:VARBINARY(500);" json:"StoragePath" yaml:"StoragePath,omitempty"` StoragePath string `gorm:"column:storage_path;size:500;" json:"StoragePath" yaml:"StoragePath,omitempty"`
CanInvite bool `json:"CanInvite" yaml:"CanInvite,omitempty"` CanInvite bool `json:"CanInvite" yaml:"CanInvite,omitempty"`
InviteToken string `gorm:"type:VARBINARY(32);" json:"-" yaml:"-"` InviteToken string `gorm:"size:32;" json:"-" yaml:"-"`
InvitedBy string `gorm:"type:VARBINARY(32);" json:"-" yaml:"-"` InvitedBy string `gorm:"size:32;" json:"-" yaml:"-"`
ConfirmToken string `gorm:"type:VARBINARY(64);" json:"-" yaml:"-"` ConfirmToken string `gorm:"size:64;" json:"-" yaml:"-"`
ResetToken string `gorm:"type:VARBINARY(64);" json:"-" yaml:"-"` ResetToken string `gorm:"size:64;" json:"-" yaml:"-"`
ApiToken string `gorm:"column:api_token;type:VARBINARY(128);" json:"-" yaml:"-"` ApiToken string `gorm:"column:api_token;size:128;" json:"-" yaml:"-"`
ApiSecret string `gorm:"column:api_secret;type:VARBINARY(128);" json:"-" yaml:"-"` ApiSecret string `gorm:"column:api_secret;size:128;" json:"-" yaml:"-"`
LoginAttempts int `json:"-" yaml:"-"` LoginAttempts int `json:"-" yaml:"-"`
LoginAt *time.Time `json:"-" yaml:"-"` LoginAt *time.Time `json:"-" yaml:"-"`
CreatedAt time.Time `json:"CreatedAt" yaml:"-"` CreatedAt time.Time `json:"CreatedAt" yaml:"-"`

View File

@@ -18,7 +18,7 @@ type Lenses []Lens
// Lens represents camera lens (as extracted from UpdateExif metadata) // Lens represents camera lens (as extracted from UpdateExif metadata)
type Lens struct { type Lens struct {
ID uint `gorm:"primaryKey" json:"ID" yaml:"ID"` ID uint `gorm:"primaryKey" json:"ID" yaml:"ID"`
LensSlug string `gorm:"type:VARBINARY(160);uniqueIndex;" json:"Slug" yaml:"Slug,omitempty"` LensSlug string `gorm:"size:160;uniqueIndex;" json:"Slug" yaml:"Slug,omitempty"`
LensName string `gorm:"type:VARCHAR(160);" json:"Name" yaml:"Name"` LensName string `gorm:"type:VARCHAR(160);" json:"Name" yaml:"Name"`
LensMake string `gorm:"type:VARCHAR(160);" json:"Make" yaml:"Make,omitempty"` LensMake string `gorm:"type:VARCHAR(160);" json:"Make" yaml:"Make,omitempty"`
LensModel string `gorm:"type:VARCHAR(160);" json:"Model" yaml:"Model,omitempty"` LensModel string `gorm:"type:VARCHAR(160);" json:"Model" yaml:"Model,omitempty"`

View File

@@ -22,18 +22,18 @@ type Links []Link
// Link represents a link to share content. // Link represents a link to share content.
type Link struct { type Link struct {
LinkUID string `gorm:"type:VARBINARY(42);primaryKey;" json:"UID,omitempty" yaml:"UID,omitempty"` LinkUID string `gorm:"size:42;primaryKey;" json:"UID,omitempty" yaml:"UID,omitempty"`
ShareUID string `gorm:"type:VARBINARY(42);uniqueIndex:idx_links_uid_token;" json:"ShareUID" yaml:"ShareUID"` ShareUID string `gorm:"size:42;uniqueIndex:idx_links_uid_token;" json:"ShareUID" yaml:"ShareUID"`
ShareSlug string `gorm:"type:VARBINARY(160);index;" json:"Slug" yaml:"Slug,omitempty"` ShareSlug string `gorm:"size:160;index;" json:"Slug" yaml:"Slug,omitempty"`
LinkToken string `gorm:"type:VARBINARY(160);uniqueIndex:idx_links_uid_token;" json:"Token" yaml:"Token,omitempty"` LinkToken string `gorm:"size:160;uniqueIndex:idx_links_uid_token;" json:"Token" yaml:"Token,omitempty"`
LinkExpires int `json:"Expires" yaml:"Expires,omitempty"` LinkExpires int `json:"Expires" yaml:"Expires,omitempty"`
LinkViews uint `json:"Views" yaml:"-"` LinkViews uint `json:"Views" yaml:"-"`
MaxViews uint `json:"MaxViews" yaml:"-"` MaxViews uint `json:"MaxViews" yaml:"-"`
HasPassword bool `json:"VerifyPassword" yaml:"VerifyPassword,omitempty"` HasPassword bool `json:"VerifyPassword" yaml:"VerifyPassword,omitempty"`
Comment string `gorm:"size:512;" json:"Comment,omitempty" yaml:"Comment,omitempty"` Comment string `gorm:"size:512;" json:"Comment,omitempty" yaml:"Comment,omitempty"`
Perm uint `json:"Perm,omitempty" yaml:"Perm,omitempty"` Perm uint `json:"Perm,omitempty" yaml:"Perm,omitempty"`
RefID string `gorm:"type:VARBINARY(16);" json:"-" yaml:"-"` RefID string `gorm:"size:16;" json:"-" yaml:"-"`
CreatedBy string `gorm:"type:VARBINARY(42);index" json:"CreatedBy,omitempty" yaml:"CreatedBy,omitempty"` CreatedBy string `gorm:"size:42;index" json:"CreatedBy,omitempty" yaml:"CreatedBy,omitempty"`
CreatedAt time.Time `deepcopier:"skip" json:"CreatedAt" yaml:"CreatedAt"` CreatedAt time.Time `deepcopier:"skip" json:"CreatedAt" yaml:"CreatedAt"`
ModifiedAt time.Time `deepcopier:"skip" json:"ModifiedAt" yaml:"ModifiedAt"` ModifiedAt time.Time `deepcopier:"skip" json:"ModifiedAt" yaml:"ModifiedAt"`
} }

View File

@@ -25,22 +25,22 @@ const (
// Marker represents an image marker point. // Marker represents an image marker point.
type Marker struct { type Marker struct {
MarkerUID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false;" json:"UID" yaml:"UID"` MarkerUID string `gorm:"size:42;primaryKey;autoIncrement:false;" json:"UID" yaml:"UID"`
FileUID string `gorm:"type:VARBINARY(42);index;default:'';" json:"FileUID" yaml:"FileUID"` FileUID string `gorm:"size:42;index;default:'';" json:"FileUID" yaml:"FileUID"`
MarkerType string `gorm:"type:VARBINARY(8);default:'';" json:"Type" yaml:"Type"` MarkerType string `gorm:"size:8;default:'';" json:"Type" yaml:"Type"`
MarkerSrc string `gorm:"type:VARBINARY(8);default:'';" json:"Src" yaml:"Src,omitempty"` MarkerSrc string `gorm:"size:8;default:'';" json:"Src" yaml:"Src,omitempty"`
MarkerName string `gorm:"type:VARCHAR(160);" json:"Name" yaml:"Name,omitempty"` MarkerName string `gorm:"type:VARCHAR(160);" json:"Name" yaml:"Name,omitempty"`
MarkerReview bool `json:"Review" yaml:"Review,omitempty"` MarkerReview bool `json:"Review" yaml:"Review,omitempty"`
MarkerInvalid bool `json:"Invalid" yaml:"Invalid,omitempty"` MarkerInvalid bool `json:"Invalid" yaml:"Invalid,omitempty"`
SubjUID string `gorm:"type:VARBINARY(42);index:idx_markers_subj_uid_src;" json:"SubjUID" yaml:"SubjUID,omitempty"` SubjUID string `gorm:"size:42;index:idx_markers_subj_uid_src;" json:"SubjUID" yaml:"SubjUID,omitempty"`
SubjSrc string `gorm:"type:VARBINARY(8);index:idx_markers_subj_uid_src;default:'';" json:"SubjSrc" yaml:"SubjSrc,omitempty"` SubjSrc string `gorm:"size:8;index:idx_markers_subj_uid_src;default:'';" json:"SubjSrc" yaml:"SubjSrc,omitempty"`
subject *Subject `gorm:"foreignKey:SubjUID;"` subject *Subject `gorm:"foreignKey:SubjUID;"`
FaceID string `gorm:"type:VARBINARY(64);index;" json:"FaceID" yaml:"FaceID,omitempty"` FaceID string `gorm:"size:64;index;" json:"FaceID" yaml:"FaceID,omitempty"`
FaceDist float64 `gorm:"default:-1;" json:"FaceDist" yaml:"FaceDist,omitempty"` FaceDist float64 `gorm:"default:-1;" json:"FaceDist" yaml:"FaceDist,omitempty"`
face *Face `gorm:"foreignKey:FaceID;"` face *Face `gorm:"foreignKey:FaceID;"`
EmbeddingsJSON json.RawMessage `gorm:"type:MEDIUMBLOB;" json:"-" yaml:"EmbeddingsJSON,omitempty"` EmbeddingsJSON json.RawMessage `json:"-" yaml:"EmbeddingsJSON,omitempty"`
embeddings face.Embeddings `gorm:"-" yaml:"-"` embeddings face.Embeddings `gorm:"-" yaml:"-"`
LandmarksJSON json.RawMessage `gorm:"type:MEDIUMBLOB;" json:"-" yaml:"LandmarksJSON,omitempty"` LandmarksJSON json.RawMessage `json:"-" yaml:"LandmarksJSON,omitempty"`
X float32 `gorm:"type:FLOAT;" json:"X" yaml:"X,omitempty"` X float32 `gorm:"type:FLOAT;" json:"X" yaml:"X,omitempty"`
Y float32 `gorm:"type:FLOAT;" json:"Y" yaml:"Y,omitempty"` Y float32 `gorm:"type:FLOAT;" json:"Y" yaml:"Y,omitempty"`
W float32 `gorm:"type:FLOAT;" json:"W" yaml:"W,omitempty"` W float32 `gorm:"type:FLOAT;" json:"W" yaml:"W,omitempty"`
@@ -48,7 +48,7 @@ type Marker struct {
Q int `json:"Q" yaml:"Q,omitempty"` Q int `json:"Q" yaml:"Q,omitempty"`
Size int `gorm:"default:-1;" json:"Size" yaml:"Size,omitempty"` Size int `gorm:"default:-1;" json:"Size" yaml:"Size,omitempty"`
Score int `gorm:"type:SMALLINT;" json:"Score" yaml:"Score,omitempty"` Score int `gorm:"type:SMALLINT;" json:"Score" yaml:"Score,omitempty"`
Thumb string `gorm:"type:VARBINARY(128);index;default:'';" json:"Thumb" yaml:"Thumb,omitempty"` Thumb string `gorm:"size:128;index;default:'';" json:"Thumb" yaml:"Thumb,omitempty"`
MatchedAt *time.Time `sql:"index" json:"MatchedAt" yaml:"MatchedAt,omitempty"` MatchedAt *time.Time `sql:"index" json:"MatchedAt" yaml:"MatchedAt,omitempty"`
CreatedAt time.Time CreatedAt time.Time
UpdatedAt time.Time UpdatedAt time.Time

View File

@@ -18,7 +18,7 @@ import (
// Passcode represents a two-factor authentication key. // Passcode represents a two-factor authentication key.
type Passcode struct { type Passcode struct {
UID string `gorm:"type:VARBINARY(255);primaryKey;" json:"UID"` UID string `gorm:"size:255;primaryKey;" json:"UID"`
KeyType string `gorm:"size:64;default:'';primaryKey;" json:"Type" yaml:"Type"` KeyType string `gorm:"size:64;default:'';primaryKey;" json:"Type" yaml:"Type"`
KeyURL string `gorm:"size:2048;default:'';column:key_url;" json:"-" yaml:"-"` KeyURL string `gorm:"size:2048;default:'';column:key_url;" json:"-" yaml:"-"`
key *otp.Key `gorm:"-" yaml:"-"` key *otp.Key `gorm:"-" yaml:"-"`

View File

@@ -16,8 +16,8 @@ var DefaultPasswordCost = 12
// Password represents a password hash. // Password represents a password hash.
type Password struct { type Password struct {
UID string `gorm:"type:VARBINARY(255);primaryKey;" json:"UID"` UID string `gorm:"size:255;primaryKey;" json:"UID"`
Hash string `deepcopier:"skip" gorm:"type:VARBINARY(255);" json:"Hash"` Hash string `deepcopier:"skip" gorm:"size:255;" json:"Hash"`
CreatedAt time.Time `deepcopier:"skip" json:"CreatedAt"` CreatedAt time.Time `deepcopier:"skip" json:"CreatedAt"`
UpdatedAt time.Time `deepcopier:"skip" json:"UpdatedAt"` UpdatedAt time.Time `deepcopier:"skip" json:"UpdatedAt"`
} }

View File

@@ -53,39 +53,39 @@ func MapKey(takenAt time.Time, cellId string) string {
// Photo represents a photo, all its properties, and link to all its images and sidecar files. // Photo represents a photo, all its properties, and link to all its images and sidecar files.
type Photo struct { type Photo struct {
ID uint `gorm:"primaryKey" yaml:"-"` ID uint `gorm:"primaryKey" yaml:"-"`
UUID string `gorm:"type:VARBINARY(64);index;" json:"DocumentID,omitempty" yaml:"DocumentID,omitempty"` UUID string `gorm:"size:64;index;" json:"DocumentID,omitempty" yaml:"DocumentID,omitempty"`
TakenAt time.Time `gorm:"type:DATETIME;index:idx_photos_taken_uid;" json:"TakenAt" yaml:"TakenAt"` TakenAt time.Time `gorm:"index:idx_photos_taken_uid;" json:"TakenAt" yaml:"TakenAt"`
TakenAtLocal time.Time `gorm:"type:DATETIME;" json:"TakenAtLocal" yaml:"TakenAtLocal"` TakenAtLocal time.Time `json:"TakenAtLocal" yaml:"TakenAtLocal"`
TakenSrc string `gorm:"type:VARBINARY(8);" json:"TakenSrc" yaml:"TakenSrc,omitempty"` TakenSrc string `gorm:"size:8;" json:"TakenSrc" yaml:"TakenSrc,omitempty"`
PhotoUID string `gorm:"type:VARBINARY(42);uniqueIndex;index:idx_photos_taken_uid;" json:"UID" yaml:"UID"` PhotoUID string `gorm:"size:42;uniqueIndex;index:idx_photos_taken_uid;" json:"UID" yaml:"UID"`
PhotoType string `gorm:"type:VARBINARY(8);default:'image';" json:"Type" yaml:"Type"` PhotoType string `gorm:"size:8;default:'image';" json:"Type" yaml:"Type"`
TypeSrc string `gorm:"type:VARBINARY(8);" json:"TypeSrc" yaml:"TypeSrc,omitempty"` TypeSrc string `gorm:"size:8;" json:"TypeSrc" yaml:"TypeSrc,omitempty"`
PhotoTitle string `gorm:"type:VARCHAR(200);" json:"Title" yaml:"Title"` PhotoTitle string `gorm:"type:VARCHAR(200);" json:"Title" yaml:"Title"`
TitleSrc string `gorm:"type:VARBINARY(8);" json:"TitleSrc" yaml:"TitleSrc,omitempty"` TitleSrc string `gorm:"size:8;" json:"TitleSrc" yaml:"TitleSrc,omitempty"`
PhotoDescription string `gorm:"type:VARCHAR(4096);" json:"Description" yaml:"Description,omitempty"` PhotoDescription string `gorm:"type:VARCHAR(4096);" json:"Description" yaml:"Description,omitempty"`
DescriptionSrc string `gorm:"type:VARBINARY(8);" json:"DescriptionSrc" yaml:"DescriptionSrc,omitempty"` DescriptionSrc string `gorm:"size:8;" json:"DescriptionSrc" yaml:"DescriptionSrc,omitempty"`
PhotoPath string `gorm:"type:VARBINARY(1024);index:idx_photos_path_name;" json:"Path" yaml:"-"` PhotoPath string `gorm:"size:1024;index:idx_photos_path_name;" json:"Path" yaml:"-"`
PhotoName string `gorm:"type:VARBINARY(255);index:idx_photos_path_name;" json:"Name" yaml:"-"` PhotoName string `gorm:"size:255;index:idx_photos_path_name;" json:"Name" yaml:"-"`
OriginalName string `gorm:"type:VARBINARY(755);" json:"OriginalName" yaml:"OriginalName,omitempty"` OriginalName string `gorm:"size:755;" json:"OriginalName" yaml:"OriginalName,omitempty"`
PhotoStack int8 `json:"Stack" yaml:"Stack,omitempty"` PhotoStack int8 `json:"Stack" yaml:"Stack,omitempty"`
PhotoFavorite bool `json:"Favorite" yaml:"Favorite,omitempty"` PhotoFavorite bool `json:"Favorite" yaml:"Favorite,omitempty"`
PhotoPrivate bool `json:"Private" yaml:"Private,omitempty"` PhotoPrivate bool `json:"Private" yaml:"Private,omitempty"`
PhotoScan bool `json:"Scan" yaml:"Scan,omitempty"` PhotoScan bool `json:"Scan" yaml:"Scan,omitempty"`
PhotoPanorama bool `json:"Panorama" yaml:"Panorama,omitempty"` PhotoPanorama bool `json:"Panorama" yaml:"Panorama,omitempty"`
TimeZone string `gorm:"type:VARBINARY(64);" json:"TimeZone" yaml:"TimeZone,omitempty"` TimeZone string `gorm:"size:64;" json:"TimeZone" yaml:"TimeZone,omitempty"`
PlaceID string `gorm:"type:VARBINARY(42);index;default:'zz'" json:"PlaceID" yaml:"-"` PlaceID string `gorm:"size:42;index;default:'zz'" json:"PlaceID" yaml:"-"`
PlaceSrc string `gorm:"type:VARBINARY(8);" json:"PlaceSrc" yaml:"PlaceSrc,omitempty"` PlaceSrc string `gorm:"size:8;" json:"PlaceSrc" yaml:"PlaceSrc,omitempty"`
CellID string `gorm:"type:VARBINARY(42);index;default:'zz'" json:"CellID" yaml:"-"` CellID string `gorm:"size:42;index;default:'zz'" json:"CellID" yaml:"-"`
CellAccuracy int `json:"CellAccuracy" yaml:"CellAccuracy,omitempty"` CellAccuracy int `json:"CellAccuracy" yaml:"CellAccuracy,omitempty"`
PhotoAltitude int `json:"Altitude" yaml:"Altitude,omitempty"` PhotoAltitude int `json:"Altitude" yaml:"Altitude,omitempty"`
PhotoLat float32 `gorm:"type:FLOAT;index;" json:"Lat" yaml:"Lat,omitempty"` PhotoLat float32 `gorm:"type:FLOAT;index;" json:"Lat" yaml:"Lat,omitempty"`
PhotoLng float32 `gorm:"type:FLOAT;index;" json:"Lng" yaml:"Lng,omitempty"` PhotoLng float32 `gorm:"type:FLOAT;index;" json:"Lng" yaml:"Lng,omitempty"`
PhotoCountry string `gorm:"type:VARBINARY(2);index:idx_photos_country_year_month;default:'zz'" json:"Country" yaml:"-"` PhotoCountry string `gorm:"size:2;index:idx_photos_country_year_month;default:'zz'" json:"Country" yaml:"-"`
PhotoYear int `gorm:"index:idx_photos_ymd;index:idx_photos_country_year_month;" json:"Year" yaml:"Year"` PhotoYear int `gorm:"index:idx_photos_ymd;index:idx_photos_country_year_month;" json:"Year" yaml:"Year"`
PhotoMonth int `gorm:"index:idx_photos_ymd;index:idx_photos_country_year_month;" json:"Month" yaml:"Month"` PhotoMonth int `gorm:"index:idx_photos_ymd;index:idx_photos_country_year_month;" json:"Month" yaml:"Month"`
PhotoDay int `gorm:"index:idx_photos_ymd" json:"Day" yaml:"Day"` PhotoDay int `gorm:"index:idx_photos_ymd" json:"Day" yaml:"Day"`
PhotoIso int `json:"Iso" yaml:"ISO,omitempty"` PhotoIso int `json:"Iso" yaml:"ISO,omitempty"`
PhotoExposure string `gorm:"type:VARBINARY(64);" json:"Exposure" yaml:"Exposure,omitempty"` PhotoExposure string `gorm:"size:64;" json:"Exposure" yaml:"Exposure,omitempty"`
PhotoFNumber float32 `gorm:"type:FLOAT;" json:"FNumber" yaml:"FNumber,omitempty"` PhotoFNumber float32 `gorm:"type:FLOAT;" json:"FNumber" yaml:"FNumber,omitempty"`
PhotoFocalLength int `json:"FocalLength" yaml:"FocalLength,omitempty"` PhotoFocalLength int `json:"FocalLength" yaml:"FocalLength,omitempty"`
PhotoQuality int `gorm:"type:SMALLINT" json:"Quality" yaml:"Quality,omitempty"` PhotoQuality int `gorm:"type:SMALLINT" json:"Quality" yaml:"Quality,omitempty"`
@@ -94,19 +94,19 @@ type Photo struct {
PhotoDuration time.Duration `json:"Duration,omitempty" yaml:"Duration,omitempty"` PhotoDuration time.Duration `json:"Duration,omitempty" yaml:"Duration,omitempty"`
PhotoColor int16 `json:"Color" yaml:"-"` PhotoColor int16 `json:"Color" yaml:"-"`
CameraID uint `gorm:"index:idx_photos_camera_lens;default:1" json:"CameraID" yaml:"-"` CameraID uint `gorm:"index:idx_photos_camera_lens;default:1" json:"CameraID" yaml:"-"`
CameraSerial string `gorm:"type:VARBINARY(160);" json:"CameraSerial" yaml:"CameraSerial,omitempty"` CameraSerial string `gorm:"size:160;" json:"CameraSerial" yaml:"CameraSerial,omitempty"`
CameraSrc string `gorm:"type:VARBINARY(8);" json:"CameraSrc" yaml:"-"` CameraSrc string `gorm:"size:8;" json:"CameraSrc" yaml:"-"`
LensID uint `gorm:"index:idx_photos_camera_lens;default:1" json:"LensID" yaml:"-"` LensID uint `gorm:"index:idx_photos_camera_lens;default:1" json:"LensID" yaml:"-"`
Details *Details `json:"Details" yaml:"Details"` Details *Details `gorm:"foreignKey:PhotoID" json:"Details" yaml:"Details"`
Camera *Camera `json:"Camera" yaml:"-"` Camera *Camera `json:"Camera" yaml:"-"`
Lens *Lens `json:"Lens" yaml:"-"` Lens *Lens `json:"Lens" yaml:"-"`
Cell *Cell `json:"Cell" yaml:"-"` Cell *Cell `json:"Cell" yaml:"-"`
Place *Place `json:"Place" yaml:"-"` Place *Place `json:"Place" yaml:"-"`
Keywords []Keyword `gorm:"many2many:photos_keywords;foreignKey:ID;joinForeignKey:PhotoID;References:ID;joinReferences:KeywordID" json:"-" yaml:"-"` Keywords []Keyword `gorm:"many2many:photos_keywords;foreignKey:ID;joinForeignKey:PhotoID;References:ID;joinReferences:KeywordID" json:"-" yaml:"-"`
Albums []Album `gorm:"many2many:photos_albums;foreignKey:PhotoUID;References:AlbumUID" json:"Albums" yaml:"-"` Albums []Album `gorm:"many2many:photos_albums;foreignKey:PhotoUID;joinForeignKey:photo_uid;References:AlbumUID;joinReferences:album_uid" json:"Albums" yaml:"-"`
Files []File `yaml:"-"` Files []File `yaml:"-"`
Labels []PhotoLabel `gorm:"foreignKey:PhotoID" yaml:"-"` Labels []PhotoLabel `yaml:"-"`
CreatedBy string `gorm:"type:VARBINARY(42);index" json:"CreatedBy,omitempty" yaml:"CreatedBy,omitempty"` CreatedBy string `gorm:"size:42;index" json:"CreatedBy,omitempty" yaml:"CreatedBy,omitempty"`
CreatedAt time.Time `yaml:"CreatedAt,omitempty"` CreatedAt time.Time `yaml:"CreatedAt,omitempty"`
UpdatedAt time.Time `yaml:"UpdatedAt,omitempty"` UpdatedAt time.Time `yaml:"UpdatedAt,omitempty"`
EditedAt *time.Time `yaml:"EditedAt,omitempty"` EditedAt *time.Time `yaml:"EditedAt,omitempty"`
@@ -503,7 +503,7 @@ func (m *Photo) PreloadAlbums() {
q := Db(). q := Db().
Table("albums"). Table("albums").
Select(`albums.*`). Select(`albums.*`).
Joins("JOIN photos_albums pa ON pa.album_uid = albums.album_uid AND pa.photo_uid = ? AND pa.hidden = 0", m.PhotoUID). Joins("JOIN photos_albums pa ON pa.album_uid = albums.album_uid AND pa.photo_uid = ? AND pa.hidden = FALSE", m.PhotoUID).
Where("albums.deleted_at IS NULL"). Where("albums.deleted_at IS NULL").
Order("albums.album_title ASC") Order("albums.album_title ASC")
@@ -702,7 +702,7 @@ func (m *Photo) AllFilesMissing() bool {
count := int64(0) count := int64(0)
if err := Db().Model(&File{}). if err := Db().Model(&File{}).
Where("photo_id = ? AND file_missing = 0", m.ID). Where("photo_id = ? AND file_missing = FALSE", m.ID).
Count(&count).Error; err != nil { Count(&count).Error; err != nil {
log.Error(err) log.Error(err)
} }
@@ -922,7 +922,7 @@ func (m *Photo) SetPrimary(fileUid string) (err error) {
if fileUid != "" { if fileUid != "" {
// Do nothing. // Do nothing.
} else if err = Db().Model(File{}). } else if err = Db().Model(File{}).
Where("photo_uid = ? AND file_type IN (?) AND file_missing = 0 AND file_error = ''", m.PhotoUID, media.PreviewExpr). Where("photo_uid = ? AND file_type IN (?) AND file_missing = FALSE AND file_error = ''", m.PhotoUID, media.PreviewExpr).
Order("file_width DESC, file_hdr DESC").Limit(1). Order("file_width DESC, file_hdr DESC").Limit(1).
Pluck("file_uid", &files).Error; err != nil { Pluck("file_uid", &files).Error; err != nil {
return err return err

View File

@@ -4,19 +4,17 @@ import (
"time" "time"
) )
type PhotoAlbums []PhotoAlbum type PhotoAlbums = []PhotoAlbum
// PhotoAlbum represents the many_to_many relation between Photo and Album // PhotoAlbum represents the many_to_many relation between Photo and Album
type PhotoAlbum struct { type PhotoAlbum struct {
PhotoUID string `gorm:"type:VARBINARY(42);primaryKey;" json:"PhotoUID" yaml:"UID"` PhotoUID string `gorm:"size:42;primaryKey:pk_pa" json:"PhotoUID" yaml:"UID"`
AlbumUID string `gorm:"type:VARBINARY(42);primaryKey;" json:"AlbumUID" yaml:"-"` AlbumUID string `gorm:"size:42;primaryKey:pk_pa" json:"AlbumUID" yaml:"-"`
Order int `json:"Order" yaml:"Order,omitempty"` Order int `json:"Order" yaml:"Order,omitempty"`
Hidden bool `json:"Hidden" yaml:"Hidden,omitempty"` Hidden bool `json:"Hidden" yaml:"Hidden,omitempty"`
Missing bool `json:"Missing" yaml:"Missing,omitempty"` Missing bool `json:"Missing" yaml:"Missing,omitempty"`
CreatedAt time.Time `json:"CreatedAt" yaml:"CreatedAt,omitempty"` CreatedAt time.Time `json:"CreatedAt" yaml:"CreatedAt,omitempty"`
UpdatedAt time.Time `json:"UpdatedAt" yaml:"-"` UpdatedAt time.Time `json:"UpdatedAt" yaml:"-"`
Photo *Photo `gorm:"foreignKey:PhotoUID;references:PhotoUID;" yaml:"-"`
Album *Album `gorm:"foreignKey:AlbumUID;references:AlbumUID;" yaml:"-"`
} }
// TableName returns the entity table name. // TableName returns the entity table name.

View File

@@ -29,8 +29,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 0, Order: 0,
CreatedAt: time.Date(2020, 3, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 3, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 3, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 3, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("19800101_000002_D640C559"),
Album: AlbumFixtures.Pointer("holiday-2030"),
}, },
"2": { "2": {
PhotoUID: "ps6sg6be2lvl0y11", PhotoUID: "ps6sg6be2lvl0y11",
@@ -40,8 +38,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 0, Order: 0,
CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("Photo04"),
Album: AlbumFixtures.Pointer("berlin-2019"),
}, },
"3": { "3": {
PhotoUID: "ps6sg6be2lvl0yh8", PhotoUID: "ps6sg6be2lvl0yh8",
@@ -51,8 +47,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 0, Order: 0,
CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("Photo01"),
Album: AlbumFixtures.Pointer("berlin-2019"),
}, },
"4": { "4": {
PhotoUID: "ps6sg6bexxvl0yh0", PhotoUID: "ps6sg6bexxvl0yh0",
@@ -62,8 +56,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 0, Order: 0,
CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("Photo19"),
Album: AlbumFixtures.Pointer("april-1990"),
}, },
"5": { "5": {
PhotoUID: "ps6sg6be2lvl0yh0", PhotoUID: "ps6sg6be2lvl0yh0",
@@ -73,8 +65,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 0, Order: 0,
CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("Photo03"),
Album: AlbumFixtures.Pointer("berlin-2019"),
}, },
"6": { "6": {
PhotoUID: "ps6sg6be2lvl0yh0", PhotoUID: "ps6sg6be2lvl0yh0",
@@ -84,8 +74,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 0, Order: 0,
CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("Photo03"),
Album: AlbumFixtures.Pointer("berlin-2019"),
}, },
"7": { "7": {
PhotoUID: "ps6sg6be2lvl0y21", PhotoUID: "ps6sg6be2lvl0y21",
@@ -95,8 +83,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 1, Order: 1,
CreatedAt: time.Date(2020, 3, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 3, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 5, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 5, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("Photo14"),
Album: AlbumFixtures.Pointer("berlin-2019"),
}, },
"8": { "8": {
PhotoUID: "ps6sg6be2lvl0y21", PhotoUID: "ps6sg6be2lvl0y21",
@@ -106,8 +92,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 1, Order: 1,
CreatedAt: time.Date(2020, 3, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 3, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 5, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 5, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("Photo14"),
Album: AlbumFixtures.Pointer("berlin-2019"),
}, },
"9": { "9": {
PhotoUID: "ps6sg6be2lvl0yh0", PhotoUID: "ps6sg6be2lvl0yh0",
@@ -117,8 +101,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 0, Order: 0,
CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("Photo03"),
Album: AlbumFixtures.Pointer("light&"),
}, },
"10": { "10": {
PhotoUID: "ps6sg6be2lvl0yh0", PhotoUID: "ps6sg6be2lvl0yh0",
@@ -128,8 +110,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 0, Order: 0,
CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("Photo03"),
Album: AlbumFixtures.Pointer("pets&dogs"),
}, },
"11": { "11": {
PhotoUID: "ps6sg6be2lvl0yh0", PhotoUID: "ps6sg6be2lvl0yh0",
@@ -139,8 +119,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 0, Order: 0,
CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("Photo03"),
Album: AlbumFixtures.Pointer("&ilikefood"),
}, },
"12": { "12": {
PhotoUID: "ps6sg6be2lvl0yh0", PhotoUID: "ps6sg6be2lvl0yh0",
@@ -150,8 +128,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 0, Order: 0,
CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("Photo03"),
Album: AlbumFixtures.Pointer("sale%"),
}, },
"13": { "13": {
PhotoUID: "ps6sg6be2lvl0yh0", PhotoUID: "ps6sg6be2lvl0yh0",
@@ -161,8 +137,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 0, Order: 0,
CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("Photo03"),
Album: AlbumFixtures.Pointer("%gold"),
}, },
"14": { "14": {
PhotoUID: "ps6sg6be2lvl0yh0", PhotoUID: "ps6sg6be2lvl0yh0",
@@ -172,8 +146,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 0, Order: 0,
CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("Photo03"),
Album: AlbumFixtures.Pointer("i-love-%-dog"),
}, },
"15": { "15": {
PhotoUID: "ps6sg6be2lvl0yh0", PhotoUID: "ps6sg6be2lvl0yh0",
@@ -183,8 +155,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 0, Order: 0,
CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("Photo03"),
Album: AlbumFixtures.Pointer("'family"),
}, },
"16": { "16": {
PhotoUID: "ps6sg6be2lvl0yh0", PhotoUID: "ps6sg6be2lvl0yh0",
@@ -194,8 +164,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 0, Order: 0,
CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("Photo03"),
Album: AlbumFixtures.Pointer("father's-day"),
}, },
"17": { "17": {
PhotoUID: "ps6sg6be2lvl0yh0", PhotoUID: "ps6sg6be2lvl0yh0",
@@ -205,8 +173,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 0, Order: 0,
CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("Photo03"),
Album: AlbumFixtures.Pointer("ice-cream'"),
}, },
"18": { "18": {
PhotoUID: "ps6sg6be2lvl0yh0", PhotoUID: "ps6sg6be2lvl0yh0",
@@ -216,8 +182,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 0, Order: 0,
CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("Photo03"),
Album: AlbumFixtures.Pointer("*forrest"),
}, },
"19": { "19": {
PhotoUID: "ps6sg6be2lvl0yh0", PhotoUID: "ps6sg6be2lvl0yh0",
@@ -227,8 +191,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 0, Order: 0,
CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("Photo03"),
Album: AlbumFixtures.Pointer("my*kids"),
}, },
"20": { "20": {
PhotoUID: "ps6sg6be2lvl0yh0", PhotoUID: "ps6sg6be2lvl0yh0",
@@ -238,8 +200,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 0, Order: 0,
CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("Photo03"),
Album: AlbumFixtures.Pointer("yoga***"),
}, },
"21": { "21": {
PhotoUID: "ps6sg6be2lvl0yh0", PhotoUID: "ps6sg6be2lvl0yh0",
@@ -249,8 +209,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 0, Order: 0,
CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("Photo03"),
Album: AlbumFixtures.Pointer("|banana"),
}, },
"22": { "22": {
PhotoUID: "ps6sg6be2lvl0yh0", PhotoUID: "ps6sg6be2lvl0yh0",
@@ -260,8 +218,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 0, Order: 0,
CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("Photo03"),
Album: AlbumFixtures.Pointer("red|green"),
}, },
"23": { "23": {
PhotoUID: "ps6sg6be2lvl0yh0", PhotoUID: "ps6sg6be2lvl0yh0",
@@ -271,8 +227,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 0, Order: 0,
CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("Photo03"),
Album: AlbumFixtures.Pointer("blue|"),
}, },
"24": { "24": {
PhotoUID: "ps6sg6be2lvl0yh0", PhotoUID: "ps6sg6be2lvl0yh0",
@@ -282,8 +236,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 0, Order: 0,
CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("Photo03"),
Album: AlbumFixtures.Pointer("345-shirt"),
}, },
"25": { "25": {
PhotoUID: "ps6sg6be2lvl0yh0", PhotoUID: "ps6sg6be2lvl0yh0",
@@ -293,8 +245,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 0, Order: 0,
CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("Photo03"),
Album: AlbumFixtures.Pointer("color-555-blue"),
}, },
"26": { "26": {
PhotoUID: "ps6sg6be2lvl0yh0", PhotoUID: "ps6sg6be2lvl0yh0",
@@ -304,8 +254,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 0, Order: 0,
CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("Photo03"),
Album: AlbumFixtures.Pointer("route-66"),
}, },
"27": { "27": {
PhotoUID: "ps6sg6be2lvl0yh9", PhotoUID: "ps6sg6be2lvl0yh9",
@@ -315,8 +263,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 0, Order: 0,
CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("Photo02"),
Album: AlbumFixtures.Pointer("father's-day"),
}, },
"28": { "28": {
PhotoUID: "ps6sg6be2lvl0yh9", PhotoUID: "ps6sg6be2lvl0yh9",
@@ -326,8 +272,6 @@ var PhotoAlbumFixtures = PhotoAlbumMap{
Order: 0, Order: 0,
CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC), CreatedAt: time.Date(2020, 2, 6, 2, 6, 51, 0, time.UTC),
UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC), UpdatedAt: time.Date(2020, 4, 28, 14, 6, 0, 0, time.UTC),
Photo: PhotoFixtures.Pointer("Photo02"),
Album: AlbumFixtures.Pointer("light&"),
}, },
} }

View File

@@ -11,10 +11,10 @@ type PhotoLabels []PhotoLabel
type PhotoLabel struct { type PhotoLabel struct {
PhotoID uint `gorm:"primaryKey;autoIncrement:false"` PhotoID uint `gorm:"primaryKey;autoIncrement:false"`
LabelID uint `gorm:"primaryKey;autoIncrement:false"` LabelID uint `gorm:"primaryKey;autoIncrement:false"`
LabelSrc string `gorm:"type:VARBINARY(8);"` LabelSrc string `gorm:"size:8;"`
Uncertainty int `gorm:"type:SMALLINT"` Uncertainty int `gorm:"type:SMALLINT"`
Photo *Photo Photo *Photo `gorm:"foreignKey:PhotoID;references:ID;" yaml:"-"`
Label *Label Label *Label `gorm:"foreignKey:LabelID;references:ID;"`
} }
// TableName returns the entity table name. // TableName returns the entity table name.

View File

@@ -13,7 +13,7 @@ var photoMergeMutex = sync.Mutex{}
func (m *Photo) ResolvePrimary() error { func (m *Photo) ResolvePrimary() error {
var file File var file File
if err := Db().Where("file_primary = 1 AND photo_id = ?", m.ID). if err := Db().Where("file_primary = TRUE AND photo_id = ?", m.ID).
Order("file_width DESC, file_hdr DESC"). Order("file_width DESC, file_hdr DESC").
First(&file).Error; err == nil && file.ID > 0 { First(&file).Error; err == nil && file.ID > 0 {
return file.ResolvePrimary() return file.ResolvePrimary()
@@ -103,7 +103,7 @@ func (m *Photo) Merge(mergeMeta, mergeUuid bool) (original Photo, merged Photos,
deleted := TimeStamp() deleted := TimeStamp()
logResult(UnscopedDb().Exec("UPDATE files SET photo_id = ?, photo_uid = ?, file_primary = 0 WHERE photo_id = ?", original.ID, original.PhotoUID, merge.ID)) logResult(UnscopedDb().Exec("UPDATE files SET photo_id = ?, photo_uid = ?, file_primary = FALSE WHERE photo_id = ?", original.ID, original.PhotoUID, merge.ID))
logResult(UnscopedDb().Exec("UPDATE photos SET photo_quality = -1, deleted_at = ? WHERE id = ?", TimeStamp(), merge.ID)) logResult(UnscopedDb().Exec("UPDATE photos SET photo_quality = -1, deleted_at = ? WHERE id = ?", TimeStamp(), merge.ID))
switch DbDialect() { switch DbDialect() {

View File

@@ -4,9 +4,9 @@ import "github.com/photoprism/photoprism/internal/event"
// PhotoUser represents the user and group ownership of a Photo and the corresponding permissions. // PhotoUser represents the user and group ownership of a Photo and the corresponding permissions.
type PhotoUser struct { type PhotoUser struct {
UID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false" json:"UID" yaml:"UID"` UID string `gorm:"size:42;primaryKey;autoIncrement:false" json:"UID" yaml:"UID"`
UserUID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false;index" json:"UserUID,omitempty" yaml:"UserUID,omitempty"` UserUID string `gorm:"size:42;primaryKey;autoIncrement:false;index" json:"UserUID,omitempty" yaml:"UserUID,omitempty"`
TeamUID string `gorm:"type:VARBINARY(42);index" json:"TeamUID,omitempty" yaml:"TeamUID,omitempty"` TeamUID string `gorm:"size:42;index" json:"TeamUID,omitempty" yaml:"TeamUID,omitempty"`
Perm uint `json:"Perm,omitempty" yaml:"Perm,omitempty"` Perm uint `json:"Perm,omitempty" yaml:"Perm,omitempty"`
} }

View File

@@ -13,12 +13,12 @@ var placeMutex = sync.Mutex{}
// Place represents a distinct region identified by city, district, state, and country. // Place represents a distinct region identified by city, district, state, and country.
type Place struct { type Place struct {
ID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false;" json:"PlaceID" yaml:"PlaceID"` ID string `gorm:"size:42;primaryKey;autoIncrement:false;" json:"PlaceID" yaml:"PlaceID"`
PlaceLabel string `gorm:"type:VARCHAR(400);" json:"Label" yaml:"Label"` PlaceLabel string `gorm:"type:VARCHAR(400);" json:"Label" yaml:"Label"`
PlaceDistrict string `gorm:"type:VARCHAR(100);index;" json:"District" yaml:"District,omitempty"` PlaceDistrict string `gorm:"type:VARCHAR(100);index;" json:"District" yaml:"District,omitempty"`
PlaceCity string `gorm:"type:VARCHAR(100);index;" json:"City" yaml:"City,omitempty"` PlaceCity string `gorm:"type:VARCHAR(100);index;" json:"City" yaml:"City,omitempty"`
PlaceState string `gorm:"type:VARCHAR(100);index;" json:"State" yaml:"State,omitempty"` PlaceState string `gorm:"type:VARCHAR(100);index;" json:"State" yaml:"State,omitempty"`
PlaceCountry string `gorm:"type:VARBINARY(2);" json:"Country" yaml:"Country,omitempty"` PlaceCountry string `gorm:"size:2;" json:"Country" yaml:"Country,omitempty"`
PlaceKeywords string `gorm:"type:VARCHAR(300);" json:"Keywords" yaml:"Keywords,omitempty"` PlaceKeywords string `gorm:"type:VARCHAR(300);" json:"Keywords" yaml:"Keywords,omitempty"`
PlaceFavorite bool `json:"Favorite" yaml:"Favorite,omitempty"` PlaceFavorite bool `json:"Favorite" yaml:"Favorite,omitempty"`
PhotoCount int `gorm:"default:1" json:"PhotoCount" yaml:"-"` PhotoCount int `gorm:"default:1" json:"PhotoCount" yaml:"-"`

View File

@@ -11,9 +11,9 @@ import (
// Reaction represents a human response to content such as photos and albums. // Reaction represents a human response to content such as photos and albums.
type Reaction struct { type Reaction struct {
UID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false" json:"UID,omitempty" yaml:"UID,omitempty"` UID string `gorm:"size:42;primaryKey;autoIncrement:false" json:"UID,omitempty" yaml:"UID,omitempty"`
UserUID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false" json:"UserUID,omitempty" yaml:"UserUID,omitempty"` UserUID string `gorm:"size:42;primaryKey;autoIncrement:false" json:"UserUID,omitempty" yaml:"UserUID,omitempty"`
Reaction string `gorm:"type:VARBINARY(64);primaryKey;autoIncrement:false" json:"Reaction,omitempty" yaml:"Reaction,omitempty"` Reaction string `gorm:"size:64;primaryKey;autoIncrement:false" json:"Reaction,omitempty" yaml:"Reaction,omitempty"`
Reacted int `json:"Reacted,omitempty" yaml:"Reacted,omitempty"` Reacted int `json:"Reacted,omitempty" yaml:"Reacted,omitempty"`
ReactedAt *time.Time `sql:"index" json:"ReactedAt,omitempty" yaml:"ReactedAt,omitempty"` ReactedAt *time.Time `sql:"index" json:"ReactedAt,omitempty" yaml:"ReactedAt,omitempty"`
} }

View File

@@ -37,21 +37,21 @@ type Service struct {
AccName string `gorm:"type:VARCHAR(160);"` AccName string `gorm:"type:VARCHAR(160);"`
AccOwner string `gorm:"type:VARCHAR(160);"` AccOwner string `gorm:"type:VARCHAR(160);"`
AccURL string `gorm:"type:VARCHAR(255);"` AccURL string `gorm:"type:VARCHAR(255);"`
AccType string `gorm:"type:VARBINARY(255);"` AccType string `gorm:"size:255;"`
AccKey string `gorm:"type:VARBINARY(255);"` AccKey string `gorm:"size:255;"`
AccUser string `gorm:"type:VARBINARY(255);"` AccUser string `gorm:"size:255;"`
AccPass string `gorm:"type:VARBINARY(255);"` AccPass string `gorm:"size:255;"`
AccTimeout string `gorm:"type:VARBINARY(16);"` AccTimeout string `gorm:"size:16;"`
AccError string `gorm:"type:VARBINARY(512);"` AccError string `gorm:"size:512;"`
AccErrors int AccErrors int
AccShare bool AccShare bool
AccSync bool AccSync bool
RetryLimit int RetryLimit int
SharePath string `gorm:"type:VARBINARY(1024);"` SharePath string `gorm:"size:1024;"`
ShareSize string `gorm:"type:VARBINARY(16);"` ShareSize string `gorm:"size:16;"`
ShareExpires int ShareExpires int
SyncPath string `gorm:"type:VARBINARY(1024);"` SyncPath string `gorm:"size:1024;"`
SyncStatus string `gorm:"type:VARBINARY(16);"` SyncStatus string `gorm:"size:16;"`
SyncInterval int SyncInterval int
SyncDate sql.NullTime `deepcopier:"skip"` SyncDate sql.NullTime `deepcopier:"skip"`
SyncUpload bool SyncUpload bool

View File

@@ -19,10 +19,10 @@ var subjectMutex = sync.Mutex{}
// Subject represents a named photo subject, typically a person. // Subject represents a named photo subject, typically a person.
type Subject struct { type Subject struct {
SubjUID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false;" json:"UID" yaml:"UID"` SubjUID string `gorm:"size:42;primaryKey;autoIncrement:false;" json:"UID" yaml:"UID"`
SubjType string `gorm:"type:VARBINARY(8);default:'';" json:"Type,omitempty" yaml:"Type,omitempty"` SubjType string `gorm:"size:8;default:'';" json:"Type,omitempty" yaml:"Type,omitempty"`
SubjSrc string `gorm:"type:VARBINARY(8);default:'';" json:"Src,omitempty" yaml:"Src,omitempty"` SubjSrc string `gorm:"size:8;default:'';" json:"Src,omitempty" yaml:"Src,omitempty"`
SubjSlug string `gorm:"type:VARBINARY(160);index;default:'';" json:"Slug" yaml:"-"` SubjSlug string `gorm:"size:160;index;default:'';" json:"Slug" yaml:"-"`
SubjName string `gorm:"size:160;uniqueIndex;default:'';" json:"Name" yaml:"Name"` SubjName string `gorm:"size:160;uniqueIndex;default:'';" json:"Name" yaml:"Name"`
SubjAlias string `gorm:"size:160;default:'';" json:"Alias" yaml:"Alias"` SubjAlias string `gorm:"size:160;default:'';" json:"Alias" yaml:"Alias"`
SubjAbout string `gorm:"size:512;" json:"About" yaml:"About,omitempty"` SubjAbout string `gorm:"size:512;" json:"About" yaml:"About,omitempty"`
@@ -34,8 +34,8 @@ type Subject struct {
SubjExcluded bool `gorm:"default:false;" json:"Excluded" yaml:"Excluded,omitempty"` SubjExcluded bool `gorm:"default:false;" json:"Excluded" yaml:"Excluded,omitempty"`
FileCount int `gorm:"default:0;" json:"FileCount" yaml:"-"` FileCount int `gorm:"default:0;" json:"FileCount" yaml:"-"`
PhotoCount int `gorm:"default:0;" json:"PhotoCount" yaml:"-"` PhotoCount int `gorm:"default:0;" json:"PhotoCount" yaml:"-"`
Thumb string `gorm:"type:VARBINARY(128);index;default:'';" json:"Thumb" yaml:"Thumb,omitempty"` Thumb string `gorm:"size:128;index;default:'';" json:"Thumb" yaml:"Thumb,omitempty"`
ThumbSrc string `gorm:"type:VARBINARY(8);default:'';" json:"ThumbSrc,omitempty" yaml:"ThumbSrc,omitempty"` ThumbSrc string `gorm:"size:8;default:'';" json:"ThumbSrc,omitempty" yaml:"ThumbSrc,omitempty"`
CreatedAt time.Time `json:"CreatedAt" yaml:"-"` CreatedAt time.Time `json:"CreatedAt" yaml:"-"`
UpdatedAt time.Time `json:"UpdatedAt" yaml:"-"` UpdatedAt time.Time `json:"UpdatedAt" yaml:"-"`
DeletedAt *time.Time `sql:"index" json:"DeletedAt,omitempty" yaml:"-"` DeletedAt *time.Time `sql:"index" json:"DeletedAt,omitempty" yaml:"-"`

View File

@@ -73,7 +73,7 @@ var DialectMySQL = Migrations{
ID: "20220329-083000", ID: "20220329-083000",
Dialect: "mysql", Dialect: "mysql",
Stage: "main", Stage: "main",
Statements: []string{"UPDATE files SET media_id = CASE WHEN file_missing = 0 AND deleted_at IS NULL THEN CONCAT((10000000000 - photo_id), '-', 1 + file_sidecar - file_primary, '-', file_uid) END;"}, Statements: []string{"UPDATE files SET media_id = CASE WHEN file_missing = FALSE AND deleted_at IS NULL THEN CONCAT((10000000000 - photo_id), '-', 1 + file_sidecar - file_primary, '-', file_uid) END;"},
}, },
{ {
ID: "20220329-090000", ID: "20220329-090000",
@@ -91,7 +91,7 @@ var DialectMySQL = Migrations{
ID: "20220329-093000", ID: "20220329-093000",
Dialect: "mysql", Dialect: "mysql",
Stage: "main", Stage: "main",
Statements: []string{"UPDATE files SET time_index = CASE WHEN file_missing = 0 AND deleted_at IS NULL THEN CONCAT(100000000000000 - CAST(photo_taken_at AS UNSIGNED), '-', media_id) END;"}, Statements: []string{"UPDATE files SET time_index = CASE WHEN file_missing = FALSE AND deleted_at IS NULL THEN CONCAT(100000000000000 - CAST(photo_taken_at AS UNSIGNED), '-', media_id) END;"},
}, },
{ {
ID: "20220421-200000", ID: "20220421-200000",

View File

@@ -0,0 +1,5 @@
package migrate
// Generated code, do not edit.
var DialectPostgres = Migrations{}

View File

@@ -0,0 +1,102 @@
package migrate
// Generated code, do not edit.
var DialectSQLite = Migrations{
{
ID: "20211121-094727",
Dialect: "sqlite",
Stage: "main",
Statements: []string{"DROP INDEX IF EXISTS idx_places_place_label;"},
},
{
ID: "20211124-120008",
Dialect: "sqlite",
Stage: "main",
Statements: []string{"DROP INDEX IF EXISTS uix_places_place_label;", "DROP INDEX IF EXISTS uix_places_label;"},
},
{
ID: "20220329-040000",
Dialect: "sqlite",
Stage: "main",
Statements: []string{"DROP INDEX IF EXISTS idx_albums_album_filter;"},
},
{
ID: "20220329-050000",
Dialect: "sqlite",
Stage: "main",
Statements: []string{"CREATE INDEX IF NOT EXISTS idx_albums_album_filter ON albums (album_filter);"},
},
{
ID: "20220329-061000",
Dialect: "sqlite",
Stage: "main",
Statements: []string{"CREATE INDEX IF NOT EXISTS idx_files_photo_id ON files (photo_id, file_primary);"},
},
{
ID: "20220329-071000",
Dialect: "sqlite",
Stage: "main",
Statements: []string{"UPDATE files SET photo_taken_at = (SELECT taken_at_local FROM photos WHERE photos.id = photo_id) WHERE photo_id IS NOT NULL;"},
},
{
ID: "20220329-081000",
Dialect: "sqlite",
Stage: "main",
Statements: []string{"CREATE UNIQUE INDEX IF NOT EXISTS idx_files_search_media ON files (media_id);"},
},
{
ID: "20220329-083000",
Dialect: "sqlite",
Stage: "main",
Statements: []string{"UPDATE files SET media_id = CASE WHEN photo_id IS NOT NULL AND file_missing = FALSE AND deleted_at IS NULL THEN ((10000000000 - photo_id) || '-' || (1 + file_sidecar - file_primary) || '-' || file_uid) END WHERE 1;"},
},
{
ID: "20220329-091000",
Dialect: "sqlite",
Stage: "main",
Statements: []string{"CREATE UNIQUE INDEX IF NOT EXISTS idx_files_search_timeline ON files (time_index);"},
},
{
ID: "20220329-093000",
Dialect: "sqlite",
Stage: "main",
Statements: []string{"UPDATE files SET time_index = CASE WHEN media_id IS NOT NULL AND photo_taken_at IS NOT NULL THEN ((100000000000000 - strftime('%Y%m%d%H%M%S', photo_taken_at)) || '-' || media_id) ELSE NULL END WHERE photo_id IS NOT NULL;"},
},
{
ID: "20220421-200000",
Dialect: "sqlite",
Stage: "main",
Statements: []string{"CREATE INDEX IF NOT EXISTS idx_files_missing_root ON files (file_missing, file_root);"},
},
{
ID: "20221015-100000",
Dialect: "sqlite",
Stage: "pre",
Statements: []string{"ALTER TABLE accounts RENAME TO services;"},
},
{
ID: "20221015-100100",
Dialect: "sqlite",
Stage: "pre",
Statements: []string{"ALTER TABLE files_sync RENAME COLUMN account_id TO service_id;", "ALTER TABLE files_share RENAME COLUMN account_id TO service_id;"},
},
{
ID: "20230309-000001",
Dialect: "sqlite",
Stage: "main",
Statements: []string{"UPDATE auth_users SET auth_provider = 'local' WHERE id = 1;", "UPDATE auth_users SET auth_provider = 'none' WHERE id = -1;", "UPDATE auth_users SET auth_provider = 'token' WHERE id = -2;", "UPDATE auth_users SET auth_provider = 'default' WHERE auth_provider = '' OR auth_provider = 'password' OR auth_provider IS NULL;"},
},
{
ID: "20230313-000001",
Dialect: "sqlite",
Stage: "main",
Statements: []string{"UPDATE auth_users SET user_role = 'contributor' WHERE user_role = 'uploader';", "UPDATE auth_sessions SET auth_provider = 'link' WHERE auth_provider = 'token';"},
},
{
ID: "20240112-000001",
Dialect: "sqlite",
Stage: "main",
Statements: []string{"DELETE FROM auth_sessions;"},
},
}

View File

@@ -49,7 +49,7 @@ var DialectSQLite3 = Migrations{
ID: "20220329-083000", ID: "20220329-083000",
Dialect: "sqlite", Dialect: "sqlite",
Stage: "main", Stage: "main",
Statements: []string{"UPDATE files SET media_id = CASE WHEN photo_id IS NOT NULL AND file_missing = 0 AND deleted_at IS NULL THEN ((10000000000 - photo_id) || '-' || (1 + file_sidecar - file_primary) || '-' || file_uid) END WHERE 1;"}, Statements: []string{"UPDATE files SET media_id = CASE WHEN photo_id IS NOT NULL AND file_missing = FALSE AND deleted_at IS NULL THEN ((10000000000 - photo_id) || '-' || (1 + file_sidecar - file_primary) || '-' || file_uid) END WHERE 1;"},
}, },
{ {
ID: "20220329-091000", ID: "20220329-091000",

View File

@@ -6,14 +6,17 @@ import "sync"
const ( const (
MySQL = "mysql" MySQL = "mysql"
SQLite3 = "sqlite" SQLite3 = "sqlite"
Postgres = "postgres"
) )
var Dialects = map[string]Migrations{ var Dialects = map[string]Migrations{
MySQL: DialectMySQL, MySQL: DialectMySQL,
SQLite3: DialectSQLite3, SQLite3: DialectSQLite3,
Postgres: DialectPostgres,
} }
var once = map[string]*sync.Once{ var once = map[string]*sync.Once{
MySQL: {}, MySQL: {},
SQLite3: {}, SQLite3: {},
Postgres: {},
} }

View File

@@ -117,6 +117,7 @@ func gen_migrations(name string) {
func main() { func main() {
gen_migrations("MySQL") gen_migrations("MySQL")
gen_migrations("SQLite") gen_migrations("SQLite")
gen_migrations("Postgres")
} }
var migrationsTemplate = template.Must(template.New("").Parse(` var migrationsTemplate = template.Must(template.New("").Parse(`

View File

@@ -21,6 +21,7 @@ func Run(db *gorm.DB, opt Options) (err error) {
// Make sure a "migrations" table exists. // Make sure a "migrations" table exists.
once[name].Do(func() { once[name].Do(func() {
err = db.AutoMigrate(&Migration{}) err = db.AutoMigrate(&Migration{})
}) })
@@ -29,8 +30,10 @@ func Run(db *gorm.DB, opt Options) (err error) {
} }
// Run migrations for dialect. // Run migrations for dialect.
if migrations, ok := Dialects[name]; ok && len(migrations) > 0 { if migrations, ok := Dialects[name]; ok {
if len(migrations) > 0 {
migrations.Start(db, opt) migrations.Start(db, opt)
}
return nil return nil
} else { } else {
return fmt.Errorf("migrate: no migrations found for %s", name) return fmt.Errorf("migrate: no migrations found for %s", name)

View File

@@ -60,7 +60,7 @@ func (m *Version) Migrated(db *gorm.DB) error {
m.MigratedAt = &timeStamp m.MigratedAt = &timeStamp
m.Error = "" m.Error = ""
return db.Model(m).Updates(Map{"MigratedAt": m.MigratedAt, "Error": m.Error}).Error return db.Save(m).Error
} }
// NewVersion creates a Version entity from a model name and a make name. // NewVersion creates a Version entity from a model name and a make name.

View File

@@ -152,7 +152,7 @@ func (ind *Index) UserMediaFile(m *MediaFile, o IndexOptions, originalName, phot
} else if photoQuery = entity.UnscopedDb().First(&photo, "photo_path = ? AND photo_name = ? AND photo_stack > -1", filePath, fileBase); photoQuery.Error == nil { } else if photoQuery = entity.UnscopedDb().First(&photo, "photo_path = ? AND photo_name = ? AND photo_stack > -1", filePath, fileBase); photoQuery.Error == nil {
// Found. // Found.
fileStacked = true fileStacked = true
} else if photoQuery = entity.UnscopedDb().First(&photo, "id IN (SELECT photo_id FROM files WHERE file_name = LIKE ? AND file_root = ? AND file_sidecar = 0 AND file_missing = 0) AND photo_path = ? AND photo_stack > -1", fs.StripKnownExt(fileName)+".%", entity.RootOriginals, filePath); photoQuery.Error == nil { } else if photoQuery = entity.UnscopedDb().First(&photo, "id IN (SELECT photo_id FROM files WHERE file_name = LIKE ? AND file_root = ? AND file_sidecar = FALSE AND file_missing = FALSE) AND photo_path = ? AND photo_stack > -1", fs.StripKnownExt(fileName)+".%", entity.RootOriginals, filePath); photoQuery.Error == nil {
// Found. // Found.
fileStacked = true fileStacked = true
} }
@@ -287,7 +287,7 @@ func (ind *Index) UserMediaFile(m *MediaFile, o IndexOptions, originalName, phot
// Flag first JPEG as primary file for this photo. // Flag first JPEG as primary file for this photo.
if !file.FilePrimary { if !file.FilePrimary {
if photoExists { if photoExists {
if res := entity.UnscopedDb().Where("photo_id = ? AND file_primary = 1 AND file_type IN (?) AND file_error = ''", photo.ID, media.PreviewExpr).First(&primaryFile); res.Error != nil { if res := entity.UnscopedDb().Where("photo_id = ? AND file_primary = TRUE AND file_type IN (?) AND file_error = ''", photo.ID, media.PreviewExpr).First(&primaryFile); res.Error != nil {
file.FilePrimary = m.IsPreviewImage() file.FilePrimary = m.IsPreviewImage()
} }
} else { } else {

View File

@@ -7,7 +7,7 @@ import (
// AccountUploads a list of files for uploading to a remote account. // AccountUploads a list of files for uploading to a remote account.
func AccountUploads(a entity.Service, limit int) (results entity.Files, err error) { func AccountUploads(a entity.Service, limit int) (results entity.Files, err error) {
s := Db().Where("files.file_missing = 0"). s := Db().Where("files.file_missing = FALSE").
Where("files.id NOT IN (SELECT file_id FROM files_sync WHERE file_id > 0 AND service_id = ?)", a.ID) Where("files.id NOT IN (SELECT file_id FROM files_sync WHERE file_id > 0 AND service_id = ?)", a.ID)
if !a.SyncRaw { if !a.SyncRaw {

View File

@@ -62,7 +62,7 @@ func AlbumCoverByUID(uid string, public bool) (file entity.File, err error) {
return file, err return file, err
} else if len(photos) > 0 { } else if len(photos) > 0 {
for _, photo := range photos { for _, photo := range photos {
if err := Db().Where("photo_uid = ? AND file_primary = 1", photo.PhotoUID).First(&file).Error; err != nil { if err := Db().Where("photo_uid = ? AND file_primary = TRUE", photo.PhotoUID).First(&file).Error; err != nil {
return file, err return file, err
} else { } else {
return file, nil return file, nil
@@ -85,14 +85,14 @@ func AlbumCoverByUID(uid string, public bool) (file entity.File, err error) {
} }
// Build query. // Build query.
stmt := Db().Where("files.file_primary = 1 AND files.file_missing = 0 AND files.file_type IN (?) AND files.deleted_at IS NULL", media.PreviewExpr). stmt := Db().Where("files.file_primary = TRUE AND files.file_missing = FALSE AND files.file_type IN (?) AND files.deleted_at IS NULL", media.PreviewExpr).
Joins("JOIN albums a ON a.album_uid = ?", uid). Joins("JOIN albums a ON a.album_uid = ?", uid).
Joins("JOIN photos_albums pa ON pa.album_uid = a.album_uid AND pa.photo_uid = files.photo_uid AND pa.hidden = 0 AND pa.missing = 0"). Joins("JOIN photos_albums pa ON pa.album_uid = a.album_uid AND pa.photo_uid = files.photo_uid AND pa.hidden = FALSE AND pa.missing = FALSE").
Joins("JOIN photos ON photos.id = files.photo_id AND photos.deleted_at IS NULL") Joins("JOIN photos ON photos.id = files.photo_id AND photos.deleted_at IS NULL")
// Public pictures only? // Public pictures only?
if public { if public {
stmt = stmt.Where("photos.photo_private = 0") stmt = stmt.Where("photos.photo_private = FALSE")
} }
// Find first picture. // Find first picture.
@@ -130,7 +130,7 @@ func UpdateMissingAlbumEntries() error {
switch DbDialect() { switch DbDialect() {
default: default:
return UnscopedDb().Exec(`UPDATE photos_albums SET missing = 1 return UnscopedDb().Exec(`UPDATE photos_albums SET missing = TRUE
WHERE photo_uid IN (SELECT photo_uid FROM photos WHERE deleted_at IS NOT NULL OR photo_quality < 0) WHERE photo_uid IN (SELECT photo_uid FROM photos WHERE deleted_at IS NOT NULL OR photo_quality < 0)
OR photo_uid IN (SELECT pa.photo_uid FROM photos_albums pa LEFT JOIN photos p ON pa.photo_uid = p.photo_uid WHERE p.photo_uid IS NULL)`).Error OR photo_uid IN (SELECT pa.photo_uid FROM photos_albums pa LEFT JOIN photos p ON pa.photo_uid = p.photo_uid WHERE p.photo_uid IS NULL)`).Error
} }
@@ -144,7 +144,7 @@ func AlbumEntryFound(uid string) error {
switch DbDialect() { switch DbDialect() {
default: default:
return UnscopedDb().Exec(`UPDATE photos_albums SET missing = 0 WHERE photo_uid = ?`, uid).Error return UnscopedDb().Exec(`UPDATE photos_albums SET missing = FALSE WHERE photo_uid = ?`, uid).Error
} }
} }

View File

@@ -35,13 +35,13 @@ func (c *Counts) Refresh() {
Take(c) Take(c)
Db().Table("photos"). Db().Table("photos").
Select("SUM(photo_type = 'video' AND photo_quality > -1 AND photo_private = 0) AS videos, " + Select("COUNT(CASE WHEN photo_type = 'video' AND photo_quality > -1 AND photo_private = FALSE THEN 1 END) AS videos, " +
"SUM(photo_quality > -1 AND photo_quality < 3 AND photo_private = 0) AS review, " + "COUNT(CASE WHEN photo_quality > -1 AND photo_quality < 3 AND photo_private = FALSE THEN 1 END) AS review, " +
"SUM(photo_quality = -1) AS hidden, " + "COUNT(CASE WHEN photo_quality = -1 THEN 1 END) AS hidden, " +
"SUM(photo_type NOT IN ('live', 'video') AND photo_quality > -1 AND photo_private = 0) AS photos, " + "COUNT(CASE WHEN photo_type NOT IN ('live', 'video') AND photo_quality > -1 AND photo_private = FALSE THEN 1 END) AS photos, " +
"SUM(photo_favorite = 1 AND photo_private = 0 AND photo_quality > -1) AS favorites, " + "COUNT(CASE WHEN photo_favorite = TRUE AND photo_private = FALSE AND photo_quality > -1 THEN 1 END) AS favorites, " +
"SUM(photo_private = 1 AND photo_quality > -1) AS private"). "COUNT(CASE WHEN photo_private = TRUE AND photo_quality > -1 THEN 1 END) AS private").
Where("photos.id NOT IN (SELECT photo_id FROM files WHERE file_primary = 1 AND (file_missing = 1 OR file_error <> ''))"). Where("photos.id NOT IN (SELECT photo_id FROM files WHERE file_primary = TRUE AND (file_missing = TRUE OR file_error <> ''))").
Where("deleted_at IS NULL"). Where("deleted_at IS NULL").
Take(c) Take(c)
@@ -49,19 +49,19 @@ func (c *Counts) Refresh() {
Select("MAX(photo_count) as label_max_photos, COUNT(*) AS labels"). Select("MAX(photo_count) as label_max_photos, COUNT(*) AS labels").
Where("photo_count > 0"). Where("photo_count > 0").
Where("deleted_at IS NULL"). Where("deleted_at IS NULL").
Where("(label_priority >= 0 OR label_favorite = 1)"). Where("(label_priority >= 0 OR label_favorite = TRUE)").
Take(c) Take(c)
Db().Table("albums"). Db().Table("albums").
Select("SUM(album_type = ?) AS albums, SUM(album_type = ?) AS moments, "+ Select("COUNT(CASE WHEN album_type = ? THEN 1 END) AS albums, COUNT(CASE WHEN album_type = ? THEN 1 END) AS moments, "+
"SUM(album_type = ?) AS folders", "COUNT(CASE WHEN album_type = ? THEN 1 END) AS folders",
entity.AlbumManual, entity.AlbumMoment, entity.AlbumFolder). entity.AlbumManual, entity.AlbumMoment, entity.AlbumFolder).
Where("deleted_at IS NULL"). Where("deleted_at IS NULL").
Take(c) Take(c)
Db().Table("files"). Db().Table("files").
Select("COUNT(*) AS files"). Select("COUNT(*) AS files").
Where("file_missing = 0 AND file_root = ?", entity.RootOriginals). Where("file_missing = FALSE AND file_root = ?", entity.RootOriginals).
Take(c) Take(c)
Db().Table("countries"). Db().Table("countries").
@@ -69,7 +69,7 @@ func (c *Counts) Refresh() {
Take(c) Take(c)
Db().Table("places"). Db().Table("places").
Select("SUM(photo_count > 0) AS places"). Select("COUNT(CASE WHEN photo_count > 0 THEN 1 END) AS places").
Where("id <> 'zz'"). Where("id <> 'zz'").
Take(c) Take(c)
} }

View File

@@ -29,18 +29,18 @@ func UpdateAlbumDefaultCovers() (err error) {
res = Db().Exec(`UPDATE albums LEFT JOIN ( res = Db().Exec(`UPDATE albums LEFT JOIN (
SELECT p2.album_uid, f.file_hash FROM files f, ( SELECT p2.album_uid, f.file_hash FROM files f, (
SELECT pa.album_uid, max(p.id) AS photo_id FROM photos p SELECT pa.album_uid, max(p.id) AS photo_id FROM photos p
JOIN photos_albums pa ON pa.photo_uid = p.photo_uid AND pa.hidden = 0 AND pa.missing = 0 JOIN photos_albums pa ON pa.photo_uid = p.photo_uid AND pa.hidden = FALSE AND pa.missing = FALSE
WHERE p.photo_quality > 0 AND p.photo_private = 0 AND p.deleted_at IS NULL WHERE p.photo_quality > 0 AND p.photo_private = FALSE AND p.deleted_at IS NULL
GROUP BY pa.album_uid) p2 WHERE p2.photo_id = f.photo_id AND f.file_primary = 1 AND f.file_error = '' AND f.file_type IN (?) GROUP BY pa.album_uid) p2 WHERE p2.photo_id = f.photo_id AND f.file_primary = TRUE AND f.file_error = '' AND f.file_type IN (?)
) b ON b.album_uid = albums.album_uid ) b ON b.album_uid = albums.album_uid
SET thumb = b.file_hash WHERE ?`, media.PreviewExpr, condition) SET thumb = b.file_hash WHERE ?`, media.PreviewExpr, condition)
case SQLite3: case SQLite3:
res = Db().Table(entity.Album{}.TableName()). res = Db().Table(entity.Album{}.TableName()).
UpdateColumn("thumb", gorm.Expr(`( UpdateColumn("thumb", gorm.Expr(`(
SELECT f.file_hash FROM files f SELECT f.file_hash FROM files f
JOIN photos_albums pa ON pa.album_uid = albums.album_uid AND pa.photo_uid = f.photo_uid AND pa.hidden = 0 AND pa.missing = 0 JOIN photos_albums pa ON pa.album_uid = albums.album_uid AND pa.photo_uid = f.photo_uid AND pa.hidden = FALSE AND pa.missing = FALSE
JOIN photos p ON p.id = f.photo_id AND p.photo_private = 0 AND p.deleted_at IS NULL AND p.photo_quality > 0 JOIN photos p ON p.id = f.photo_id AND p.photo_private = FALSE AND p.deleted_at IS NULL AND p.photo_quality > 0
WHERE f.deleted_at IS NULL AND f.file_missing = 0 AND f.file_hash <> '' AND f.file_primary = 1 AND f.file_error = '' AND f.file_type IN (?) WHERE f.deleted_at IS NULL AND f.file_missing = FALSE AND f.file_hash <> '' AND f.file_primary = TRUE AND f.file_error = '' AND f.file_type IN (?)
ORDER BY p.taken_at DESC LIMIT 1 ORDER BY p.taken_at DESC LIMIT 1
) WHERE ?`, media.PreviewExpr, condition)) ) WHERE ?`, media.PreviewExpr, condition))
default: default:
@@ -77,18 +77,18 @@ func UpdateAlbumFolderCovers() (err error) {
res = Db().Exec(`UPDATE albums LEFT JOIN ( res = Db().Exec(`UPDATE albums LEFT JOIN (
SELECT p2.photo_path, f.file_hash FROM files f, ( SELECT p2.photo_path, f.file_hash FROM files f, (
SELECT p.photo_path, max(p.id) AS photo_id FROM photos p SELECT p.photo_path, max(p.id) AS photo_id FROM photos p
WHERE p.photo_quality > 0 AND p.photo_private = 0 AND p.deleted_at IS NULL WHERE p.photo_quality > 0 AND p.photo_private = FALSE AND p.deleted_at IS NULL
GROUP BY p.photo_path) p2 WHERE p2.photo_id = f.photo_id AND f.file_primary = 1 AND f.file_error = '' AND f.file_type IN (?) GROUP BY p.photo_path) p2 WHERE p2.photo_id = f.photo_id AND f.file_primary = TRUE AND f.file_error = '' AND f.file_type IN (?)
) b ON b.photo_path = albums.album_path ) b ON b.photo_path = albums.album_path
SET thumb = b.file_hash WHERE ?`, media.PreviewExpr, condition) SET thumb = b.file_hash WHERE ?`, media.PreviewExpr, condition)
case SQLite3: case SQLite3:
res = Db().Table(entity.Album{}.TableName()).UpdateColumn("thumb", gorm.Expr(`( res = Db().Table(entity.Album{}.TableName()).UpdateColumn("thumb", gorm.Expr(`(
SELECT f.file_hash FROM files f,( SELECT f.file_hash FROM files f,(
SELECT p.photo_path, max(p.id) AS photo_id FROM photos p SELECT p.photo_path, max(p.id) AS photo_id FROM photos p
WHERE p.photo_quality > 0 AND p.photo_private = 0 AND p.deleted_at IS NULL WHERE p.photo_quality > 0 AND p.photo_private = FALSE AND p.deleted_at IS NULL
GROUP BY p.photo_path GROUP BY p.photo_path
) b ) b
WHERE f.photo_id = b.photo_id AND f.file_primary = 1 AND f.file_error = '' AND f.file_type IN (?) WHERE f.photo_id = b.photo_id AND f.file_primary = TRUE AND f.file_error = '' AND f.file_type IN (?)
AND b.photo_path = albums.album_path LIMIT 1) AND b.photo_path = albums.album_path LIMIT 1)
WHERE ?`, media.PreviewExpr, condition)) WHERE ?`, media.PreviewExpr, condition))
default: default:
@@ -125,18 +125,18 @@ func UpdateAlbumMonthCovers() (err error) {
res = Db().Exec(`UPDATE albums LEFT JOIN ( res = Db().Exec(`UPDATE albums LEFT JOIN (
SELECT p2.photo_year, p2.photo_month, f.file_hash FROM files f, ( SELECT p2.photo_year, p2.photo_month, f.file_hash FROM files f, (
SELECT p.photo_year, p.photo_month, max(p.id) AS photo_id FROM photos p SELECT p.photo_year, p.photo_month, max(p.id) AS photo_id FROM photos p
WHERE p.photo_quality > 0 AND p.photo_private = 0 AND p.deleted_at IS NULL WHERE p.photo_quality > 0 AND p.photo_private = FALSE AND p.deleted_at IS NULL
GROUP BY p.photo_year, p.photo_month) p2 WHERE p2.photo_id = f.photo_id AND f.file_primary = 1 AND f.file_error = '' AND f.file_type IN (?) GROUP BY p.photo_year, p.photo_month) p2 WHERE p2.photo_id = f.photo_id AND f.file_primary = TRUE AND f.file_error = '' AND f.file_type IN (?)
) b ON b.photo_year = albums.album_year AND b.photo_month = albums.album_month ) b ON b.photo_year = albums.album_year AND b.photo_month = albums.album_month
SET thumb = b.file_hash WHERE ?`, media.PreviewExpr, condition) SET thumb = b.file_hash WHERE ?`, media.PreviewExpr, condition)
case SQLite3: case SQLite3:
res = Db().Table(entity.Album{}.TableName()).UpdateColumn("thumb", gorm.Expr(`( res = Db().Table(entity.Album{}.TableName()).UpdateColumn("thumb", gorm.Expr(`(
SELECT f.file_hash FROM files f,( SELECT f.file_hash FROM files f,(
SELECT p.photo_year, p.photo_month, max(p.id) AS photo_id FROM photos p SELECT p.photo_year, p.photo_month, max(p.id) AS photo_id FROM photos p
WHERE p.photo_quality > 0 AND p.photo_private = 0 AND p.deleted_at IS NULL WHERE p.photo_quality > 0 AND p.photo_private = FALSE AND p.deleted_at IS NULL
GROUP BY p.photo_year, p.photo_month GROUP BY p.photo_year, p.photo_month
) b ) b
WHERE f.photo_id = b.photo_id AND f.file_primary = 1 AND f.file_error = '' AND f.file_type IN (?) WHERE f.photo_id = b.photo_id AND f.file_primary = TRUE AND f.file_error = '' AND f.file_type IN (?)
AND b.photo_year = albums.album_year AND b.photo_month = albums.album_month LIMIT 1) AND b.photo_year = albums.album_year AND b.photo_month = albums.album_month LIMIT 1)
WHERE ?`, media.PreviewExpr, condition)) WHERE ?`, media.PreviewExpr, condition))
default: default:
@@ -194,23 +194,23 @@ func UpdateLabelCovers() (err error) {
SELECT p2.label_id, f.file_hash FROM files f, ( SELECT p2.label_id, f.file_hash FROM files f, (
SELECT pl.label_id as label_id, max(p.id) AS photo_id FROM photos p SELECT pl.label_id as label_id, max(p.id) AS photo_id FROM photos p
JOIN photos_labels pl ON pl.photo_id = p.id AND pl.uncertainty < 100 JOIN photos_labels pl ON pl.photo_id = p.id AND pl.uncertainty < 100
WHERE p.photo_quality > 0 AND p.photo_private = 0 AND p.deleted_at IS NULL WHERE p.photo_quality > 0 AND p.photo_private = FALSE AND p.deleted_at IS NULL
GROUP BY pl.label_id GROUP BY pl.label_id
UNION UNION
SELECT c.category_id as label_id, max(p.id) AS photo_id FROM photos p SELECT c.category_id as label_id, max(p.id) AS photo_id FROM photos p
JOIN photos_labels pl ON pl.photo_id = p.id AND pl.uncertainty < 100 JOIN photos_labels pl ON pl.photo_id = p.id AND pl.uncertainty < 100
JOIN categories c ON c.label_id = pl.label_id JOIN categories c ON c.label_id = pl.label_id
WHERE p.photo_quality > 0 AND p.photo_private = 0 AND p.deleted_at IS NULL WHERE p.photo_quality > 0 AND p.photo_private = FALSE AND p.deleted_at IS NULL
GROUP BY c.category_id GROUP BY c.category_id
) p2 WHERE p2.photo_id = f.photo_id AND f.file_primary = 1 AND f.file_error = '' AND f.file_type IN (?) AND f.file_missing = 0 ) p2 WHERE p2.photo_id = f.photo_id AND f.file_primary = TRUE AND f.file_error = '' AND f.file_type IN (?) AND f.file_missing = FALSE
) b ON b.label_id = labels.id ) b ON b.label_id = labels.id
SET thumb = b.file_hash WHERE ?`, media.PreviewExpr, condition) SET thumb = b.file_hash WHERE ?`, media.PreviewExpr, condition)
case SQLite3: case SQLite3:
res = Db().Table(entity.Label{}.TableName()).UpdateColumn("thumb", gorm.Expr(`( res = Db().Table(entity.Label{}.TableName()).UpdateColumn("thumb", gorm.Expr(`(
SELECT f.file_hash FROM files f SELECT f.file_hash FROM files f
JOIN photos_labels pl ON pl.label_id = labels.id AND pl.photo_id = f.photo_id AND pl.uncertainty < 100 JOIN photos_labels pl ON pl.label_id = labels.id AND pl.photo_id = f.photo_id AND pl.uncertainty < 100
JOIN photos p ON p.id = f.photo_id AND p.photo_private = 0 AND p.deleted_at IS NULL AND p.photo_quality > 0 JOIN photos p ON p.id = f.photo_id AND p.photo_private = FALSE AND p.deleted_at IS NULL AND p.photo_quality > 0
WHERE f.deleted_at IS NULL AND f.file_hash <> '' AND f.file_missing = 0 AND f.file_primary = 1 AND f.file_error = '' AND f.file_type IN (?) WHERE f.deleted_at IS NULL AND f.file_hash <> '' AND f.file_missing = FALSE AND f.file_primary = TRUE AND f.file_error = '' AND f.file_type IN (?)
ORDER BY p.photo_quality DESC, pl.uncertainty ASC, p.taken_at DESC LIMIT 1 ORDER BY p.photo_quality DESC, pl.uncertainty ASC, p.taken_at DESC LIMIT 1
) WHERE ?`, media.PreviewExpr, condition)) ) WHERE ?`, media.PreviewExpr, condition))
@@ -219,8 +219,8 @@ func UpdateLabelCovers() (err error) {
SELECT f.file_hash FROM files f SELECT f.file_hash FROM files f
JOIN photos_labels pl ON pl.photo_id = f.photo_id AND pl.uncertainty < 100 JOIN photos_labels pl ON pl.photo_id = f.photo_id AND pl.uncertainty < 100
JOIN categories c ON c.label_id = pl.label_id AND c.category_id = labels.id JOIN categories c ON c.label_id = pl.label_id AND c.category_id = labels.id
JOIN photos p ON p.id = f.photo_id AND p.photo_private = 0 AND p.deleted_at IS NULL AND p.photo_quality > 0 JOIN photos p ON p.id = f.photo_id AND p.photo_private = FALSE AND p.deleted_at IS NULL AND p.photo_quality > 0
WHERE f.deleted_at IS NULL AND f.file_hash <> '' AND f.file_missing = 0 AND f.file_primary = 1 AND f.file_error = '' AND f.file_type IN (?) WHERE f.deleted_at IS NULL AND f.file_hash <> '' AND f.file_missing = FALSE AND f.file_primary = TRUE AND f.file_error = '' AND f.file_type IN (?)
ORDER BY p.photo_quality DESC, pl.uncertainty ASC, p.taken_at DESC LIMIT 1 ORDER BY p.photo_quality DESC, pl.uncertainty ASC, p.taken_at DESC LIMIT 1
) WHERE thumb IS NULL`, media.PreviewExpr)) ) WHERE thumb IS NULL`, media.PreviewExpr))

View File

@@ -112,7 +112,7 @@ func SelectedFiles(f form.Selection, o FileSelection) (results entity.Files, err
OR photos.photo_path IN ( OR photos.photo_path IN (
SELECT a.path FROM folders a WHERE a.folder_uid IN (?) UNION SELECT a.path FROM folders a WHERE a.folder_uid IN (?) UNION
SELECT b.path FROM folders a JOIN folders b ON b.path LIKE %s WHERE a.folder_uid IN (?)) SELECT b.path FROM folders a JOIN folders b ON b.path LIKE %s WHERE a.folder_uid IN (?))
OR photos.photo_uid IN (SELECT photo_uid FROM photos_albums WHERE hidden = 0 AND album_uid IN (?)) OR photos.photo_uid IN (SELECT photo_uid FROM photos_albums WHERE hidden = FALSE AND album_uid IN (?))
OR files.file_uid IN (SELECT file_uid FROM %s m WHERE m.subj_uid IN (?)) OR files.file_uid IN (SELECT file_uid FROM %s m WHERE m.subj_uid IN (?))
OR photos.id IN (SELECT pl.photo_id FROM photos_labels pl JOIN labels l ON pl.label_id = l.id AND pl.uncertainty < 100 AND l.deleted_at IS NULL WHERE l.label_uid IN (?)) OR photos.id IN (SELECT pl.photo_id FROM photos_labels pl JOIN labels l ON pl.label_id = l.id AND pl.uncertainty < 100 AND l.deleted_at IS NULL WHERE l.label_uid IN (?))
OR photos.id IN (SELECT pl.photo_id FROM photos_labels pl JOIN categories c ON c.label_id = pl.label_id AND pl.uncertainty < 100 JOIN labels lc ON lc.id = c.category_id AND lc.deleted_at IS NULL WHERE lc.label_uid IN (?))`, OR photos.id IN (SELECT pl.photo_id FROM photos_labels pl JOIN categories c ON c.label_id = pl.label_id AND pl.uncertainty < 100 JOIN labels lc ON lc.id = c.category_id AND lc.deleted_at IS NULL WHERE lc.label_uid IN (?))`,
@@ -122,7 +122,7 @@ func SelectedFiles(f form.Selection, o FileSelection) (results entity.Files, err
s := UnscopedDb().Table("files"). s := UnscopedDb().Table("files").
Select("files.*"). Select("files.*").
Joins("JOIN photos ON photos.id = files.photo_id"). Joins("JOIN photos ON photos.id = files.photo_id").
Where("files.file_missing = 0 AND files.file_name <> '' AND files.file_hash <> ''"). Where("files.file_missing = FALSE AND files.file_name <> '' AND files.file_hash <> ''").
Where(where, f.Photos, f.Places, f.Files, f.Files, f.Files, f.Albums, f.Subjects, f.Labels, f.Labels). Where(where, f.Photos, f.Places, f.Files, f.Files, f.Files, f.Albums, f.Subjects, f.Labels, f.Labels).
Group("files.id") Group("files.id")
@@ -153,7 +153,7 @@ func SelectedFiles(f form.Selection, o FileSelection) (results entity.Files, err
// Previews files only? // Previews files only?
if o.Primary { if o.Primary {
s = s.Where("files.file_primary = 1") s = s.Where("files.file_primary = TRUE")
} }
// Files in originals only? // Files in originals only?

View File

@@ -19,11 +19,11 @@ func FilesByPath(limit, offset int, rootName, pathName string, public bool) (fil
stmt := Db(). stmt := Db().
Table("files").Select("files.*"). Table("files").Select("files.*").
Joins("JOIN photos ON photos.id = files.photo_id AND photos.deleted_at IS NULL"). Joins("JOIN photos ON photos.id = files.photo_id AND photos.deleted_at IS NULL").
Where("files.file_missing = 0 AND files.file_root = ?", rootName). Where("files.file_missing = FALSE AND files.file_root = ?", rootName).
Where("photos.photo_path = ?", pathName) Where("photos.photo_path = ?", pathName)
if public { if public {
stmt = stmt.Where("photos.photo_private = 0") stmt = stmt.Where("photos.photo_private = FALSE")
} }
err = stmt.Order("files.file_name"). err = stmt.Order("files.file_name").
@@ -42,7 +42,7 @@ func Files(limit, offset int, pathName string, includeMissing bool) (files entit
stmt := Db() stmt := Db()
if !includeMissing { if !includeMissing {
stmt = stmt.Where("file_missing = 0") stmt = stmt.Where("file_missing = FALSE")
} }
if pathName != "" { if pathName != "" {
@@ -56,7 +56,7 @@ func Files(limit, offset int, pathName string, includeMissing bool) (files entit
// FilesByUID finds files for the given UIDs. // FilesByUID finds files for the given UIDs.
func FilesByUID(u []string, limit int, offset int) (files entity.Files, err error) { func FilesByUID(u []string, limit int, offset int) (files entity.Files, err error) {
if err = Db().Where("(photo_uid IN (?) AND file_primary = 1) OR file_uid IN (?)", u, u).Preload("Photo").Limit(limit).Offset(offset).Find(&files).Error; err != nil { if err = Db().Where("(photo_uid IN (?) AND file_primary = TRUE) OR file_uid IN (?)", u, u).Preload("Photo").Limit(limit).Offset(offset).Find(&files).Error; err != nil {
return files, err return files, err
} }
@@ -71,7 +71,7 @@ func FileByPhotoUID(photoUID string) (*entity.File, error) {
return &f, fmt.Errorf("photo uid required") return &f, fmt.Errorf("photo uid required")
} }
err := Db().Where("photo_uid = ? AND file_primary = 1", photoUID).Preload("Photo").First(&f).Error err := Db().Where("photo_uid = ? AND file_primary = TRUE", photoUID).Preload("Photo").First(&f).Error
return &f, err return &f, err
} }
@@ -84,7 +84,7 @@ func VideoByPhotoUID(photoUID string) (*entity.File, error) {
return &f, fmt.Errorf("photo uid required") return &f, fmt.Errorf("photo uid required")
} }
err := Db().Where("photo_uid = ? AND file_missing = 0", photoUID). err := Db().Where("photo_uid = ? AND file_missing = FALSE", photoUID).
Where("file_video = 1 OR file_duration > 0 OR file_frames > 0 OR file_type = ?", fs.ImageGIF). Where("file_video = 1 OR file_duration > 0 OR file_frames > 0 OR file_type = ?", fs.ImageGIF).
Order("file_error ASC, file_video DESC, file_duration DESC, file_frames DESC"). Order("file_error ASC, file_video DESC, file_duration DESC, file_frames DESC").
Preload("Photo").First(&f).Error Preload("Photo").First(&f).Error
@@ -124,7 +124,7 @@ func RenameFile(srcRoot, srcName, destRoot, destName string) error {
return fmt.Errorf("cannot rename %s/%s to %s/%s", srcRoot, srcName, destRoot, destName) return fmt.Errorf("cannot rename %s/%s to %s/%s", srcRoot, srcName, destRoot, destName)
} }
return Db().Exec("UPDATE files SET file_root = ?, file_name = ?, file_missing = 0, deleted_at = NULL WHERE file_root = ? AND file_name = ?", destRoot, destName, srcRoot, srcName).Error return Db().Exec("UPDATE files SET file_root = ?, file_name = ?, file_missing = FALSE, deleted_at = NULL WHERE file_root = ? AND file_name = ?", destRoot, destName, srcRoot, srcName).Error
} }
// SetPhotoPrimary sets a new primary image file for a photo. // SetPhotoPrimary sets a new primary image file for a photo.
@@ -138,7 +138,7 @@ func SetPhotoPrimary(photoUID, fileUID string) (err error) {
if fileUID != "" { if fileUID != "" {
// Do nothing. // Do nothing.
} else if err = Db().Model(entity.File{}). } else if err = Db().Model(entity.File{}).
Where("photo_uid = ? AND file_missing = 0 AND file_type IN (?)", photoUID, media.PreviewExpr). Where("photo_uid = ? AND file_missing = FALSE AND file_type IN (?)", photoUID, media.PreviewExpr).
Order("file_width DESC, file_hdr DESC").Limit(1).Pluck("file_uid", &files).Error; err != nil { Order("file_width DESC, file_hdr DESC").Limit(1).Pluck("file_uid", &files).Error; err != nil {
return err return err
} else if len(files) == 0 { } else if len(files) == 0 {
@@ -199,7 +199,7 @@ func IndexedFiles() (result FileMap, err error) {
// Query indexed files. // Query indexed files.
var files []File var files []File
if err := UnscopedDb().Raw("SELECT file_root, file_name, mod_time FROM files WHERE file_missing = 0 AND deleted_at IS NULL").Scan(&files).Error; err != nil { if err := UnscopedDb().Raw("SELECT file_root, file_name, mod_time FROM files WHERE file_missing = FALSE AND deleted_at IS NULL").Scan(&files).Error; err != nil {
return result, err return result, err
} }

View File

@@ -12,7 +12,7 @@ type HashMap map[string]bool
func CountFileHashes() (count int64) { func CountFileHashes() (count int64) {
if err := UnscopedDb(). if err := UnscopedDb().
Table(entity.File{}.TableName()). Table(entity.File{}.TableName()).
Where("file_missing = 0 AND deleted_at IS NULL"). Where("file_missing = FALSE AND deleted_at IS NULL").
Select("COUNT(DISTINCT(file_hash))").Count(&count).Error; err != nil { Select("COUNT(DISTINCT(file_hash))").Count(&count).Error; err != nil {
log.Errorf("files: %s (count hashes)", err) log.Errorf("files: %s (count hashes)", err)
} }
@@ -49,7 +49,7 @@ func FileHashMap() (result HashMap, err error) {
if rows, err := UnscopedDb(). if rows, err := UnscopedDb().
Table(entity.File{}.TableName()). Table(entity.File{}.TableName()).
Where("file_missing = 0 AND deleted_at IS NULL"). Where("file_missing = FALSE AND deleted_at IS NULL").
Where("file_hash IS NOT NULL AND file_hash <> ''"). Where("file_hash IS NOT NULL AND file_hash <> ''").
Select("file_hash").Rows(); err != nil { Select("file_hash").Rows(); err != nil {
return result, err return result, err

View File

@@ -42,8 +42,8 @@ func FoldersByPath(rootName, rootPath, path string, recursive bool) (folders ent
// FolderCoverByUID returns a folder cover file based on the uid. // FolderCoverByUID returns a folder cover file based on the uid.
func FolderCoverByUID(uid string) (file entity.File, err error) { func FolderCoverByUID(uid string) (file entity.File, err error) {
if err = Db().Where("files.file_primary = 1 AND files.file_missing = 0 AND files.file_type IN (?) AND files.deleted_at IS NULL", media.PreviewExpr). if err = Db().Where("files.file_primary = TRUE AND files.file_missing = FALSE AND files.file_type IN (?) AND files.deleted_at IS NULL", media.PreviewExpr).
Joins("JOIN photos ON photos.id = files.photo_id AND photos.deleted_at IS NULL AND photos.photo_quality > -1 AND photos.photo_private = 0"). Joins("JOIN photos ON photos.id = files.photo_id AND photos.deleted_at IS NULL AND photos.photo_quality > -1 AND photos.photo_private = FALSE").
Joins("JOIN folders ON photos.photo_path = folders.path AND folders.folder_uid = ?", uid). Joins("JOIN folders ON photos.photo_path = folders.path AND folders.folder_uid = ?", uid).
Order("photos.photo_quality DESC"). Order("photos.photo_quality DESC").
Limit(1). Limit(1).
@@ -58,7 +58,7 @@ func FolderCoverByUID(uid string) (file entity.File, err error) {
func AlbumFolders(threshold int) (folders entity.Folders, err error) { func AlbumFolders(threshold int) (folders entity.Folders, err error) {
db := UnscopedDb().Table("folders"). db := UnscopedDb().Table("folders").
Select("folders.path, folders.root, folders.folder_uid, folders.folder_title, folders.folder_country, folders.folder_year, folders.folder_month, COUNT(photos.id) AS photo_count"). Select("folders.path, folders.root, folders.folder_uid, folders.folder_title, folders.folder_country, folders.folder_year, folders.folder_month, COUNT(photos.id) AS photo_count").
Joins("JOIN photos ON photos.photo_path = folders.path AND photos.deleted_at IS NULL AND photos.photo_quality >= 3 AND photos.photo_private = 0"). Joins("JOIN photos ON photos.photo_path = folders.path AND photos.deleted_at IS NULL AND photos.photo_quality >= 3 AND photos.photo_private = FALSE").
Group("folders.path, folders.root, folders.folder_uid, folders.folder_title, folders.folder_country, folders.folder_year, folders.folder_month"). Group("folders.path, folders.root, folders.folder_uid, folders.folder_title, folders.folder_country, folders.folder_year, folders.folder_month").
Having("photo_count >= ?", threshold) Having("photo_count >= ?", threshold)

View File

@@ -37,7 +37,7 @@ func LabelThumbBySlug(labelSlug string) (file entity.File, err error) {
if err := Db().Where("files.file_primary AND files.file_type IN (?) AND files.deleted_at IS NULL", media.PreviewExpr). if err := Db().Where("files.file_primary AND files.file_type IN (?) AND files.deleted_at IS NULL", media.PreviewExpr).
Joins("JOIN labels ON labels.label_slug = ?", labelSlug). Joins("JOIN labels ON labels.label_slug = ?", labelSlug).
Joins("JOIN photos_labels ON photos_labels.label_id = labels.id AND photos_labels.photo_id = files.photo_id AND photos_labels.uncertainty < 100"). Joins("JOIN photos_labels ON photos_labels.label_id = labels.id AND photos_labels.photo_id = files.photo_id AND photos_labels.uncertainty < 100").
Joins("JOIN photos ON photos.id = files.photo_id AND photos.photo_private = 0 AND photos.deleted_at IS NULL"). Joins("JOIN photos ON photos.id = files.photo_id AND photos.photo_private = FALSE AND photos.deleted_at IS NULL").
Order("photos.photo_quality DESC, photos_labels.uncertainty ASC"). Order("photos.photo_quality DESC, photos_labels.uncertainty ASC").
First(&file).Error; err != nil { First(&file).Error; err != nil {
return file, err return file, err
@@ -52,7 +52,7 @@ func LabelThumbByUID(labelUID string) (file entity.File, err error) {
err = Db().Where("files.file_primary AND files.deleted_at IS NULL"). err = Db().Where("files.file_primary AND files.deleted_at IS NULL").
Joins("JOIN labels ON labels.label_uid = ?", labelUID). Joins("JOIN labels ON labels.label_uid = ?", labelUID).
Joins("JOIN photos_labels ON photos_labels.label_id = labels.id AND photos_labels.photo_id = files.photo_id AND photos_labels.uncertainty < 100"). Joins("JOIN photos_labels ON photos_labels.label_id = labels.id AND photos_labels.photo_id = files.photo_id AND photos_labels.uncertainty < 100").
Joins("JOIN photos ON photos.id = files.photo_id AND photos.photo_private = 0 AND photos.deleted_at IS NULL"). Joins("JOIN photos ON photos.id = files.photo_id AND photos.photo_private = FALSE AND photos.deleted_at IS NULL").
Order("photos.photo_quality DESC, photos_labels.uncertainty ASC"). Order("photos.photo_quality DESC, photos_labels.uncertainty ASC").
First(&file).Error First(&file).Error
@@ -65,7 +65,7 @@ func LabelThumbByUID(labelUID string) (file entity.File, err error) {
Joins("JOIN photos_labels ON photos_labels.photo_id = files.photo_id AND photos_labels.uncertainty < 100"). Joins("JOIN photos_labels ON photos_labels.photo_id = files.photo_id AND photos_labels.uncertainty < 100").
Joins("JOIN categories c ON photos_labels.label_id = c.label_id"). Joins("JOIN categories c ON photos_labels.label_id = c.label_id").
Joins("JOIN labels ON c.category_id = labels.id AND labels.label_uid= ?", labelUID). Joins("JOIN labels ON c.category_id = labels.id AND labels.label_uid= ?", labelUID).
Joins("JOIN photos ON photos.id = files.photo_id AND photos.photo_private = 0 AND photos.deleted_at IS NULL"). Joins("JOIN photos ON photos.id = files.photo_id AND photos.photo_private = FALSE AND photos.deleted_at IS NULL").
Order("photos.photo_quality DESC, photos_labels.uncertainty ASC"). Order("photos.photo_quality DESC, photos_labels.uncertainty ASC").
First(&file).Error First(&file).Error

View File

@@ -201,7 +201,7 @@ func MomentsTime(threshold int, public bool) (results Moments, err error) {
// Ignore private pictures? // Ignore private pictures?
if public { if public {
stmt = stmt.Where("photo_private = 0") stmt = stmt.Where("photo_private = FALSE")
} }
stmt = stmt.Group("photos.photo_year, photos.photo_month"). stmt = stmt.Group("photos.photo_year, photos.photo_month").
@@ -223,7 +223,7 @@ func MomentsCountries(threshold int, public bool) (results Moments, err error) {
// Ignore private pictures? // Ignore private pictures?
if public { if public {
stmt = stmt.Where("photo_private = 0") stmt = stmt.Where("photo_private = FALSE")
} }
stmt = stmt.Group("photo_year, photo_country"). stmt = stmt.Group("photo_year, photo_country").
@@ -245,7 +245,7 @@ func MomentsStates(threshold int, public bool) (results Moments, err error) {
// Ignore private pictures? // Ignore private pictures?
if public { if public {
stmt = stmt.Where("photo_private = 0") stmt = stmt.Where("photo_private = FALSE")
} }
stmt = stmt.Group("p.place_country, p.place_state"). stmt = stmt.Group("p.place_country, p.place_state").
@@ -276,7 +276,7 @@ func MomentsLabels(threshold int, public bool) (results Moments, err error) {
// Ignore private pictures? // Ignore private pictures?
if public { if public {
stmt = stmt.Where("photo_private = 0") stmt = stmt.Where("photo_private = FALSE")
} }
stmt = stmt.Group("l.label_slug"). stmt = stmt.Group("l.label_slug").
@@ -309,16 +309,16 @@ func RemoveDuplicateMoments() (removed int, err error) {
if res := UnscopedDb().Exec(`DELETE FROM links WHERE share_uid if res := UnscopedDb().Exec(`DELETE FROM links WHERE share_uid
IN (SELECT a.album_uid FROM albums a JOIN albums b ON a.album_type <> ? IN (SELECT a.album_uid FROM albums a JOIN albums b ON a.album_type <> ?
AND a.album_type = b.album_type AND a.id > b.id AND a.album_type = b.album_type AND a.id > b.id
WHERE (a.album_slug = b.album_slug OR a.album_filter = b.album_filter) WHERE (a.album_slug = b.album_slug OR a.album_filter = b.album_filter))`,
GROUP BY a.album_uid)`, entity.AlbumManual); res.Error != nil { entity.AlbumManual); res.Error != nil {
return removed, res.Error return removed, res.Error
} }
if res := UnscopedDb().Exec(`DELETE FROM albums WHERE id if res := UnscopedDb().Exec(`DELETE FROM albums WHERE id
IN (SELECT a.id FROM albums a JOIN albums b ON a.album_type <> ? IN (SELECT a.id FROM albums a JOIN albums b ON a.album_type <> ?
AND a.album_type = b.album_type AND a.id > b.id AND a.album_type = b.album_type AND a.id > b.id
WHERE (a.album_slug = b.album_slug OR a.album_filter = b.album_filter) WHERE (a.album_slug = b.album_slug OR a.album_filter = b.album_filter))`,
GROUP BY a.album_uid)`, entity.AlbumManual); res.Error != nil { entity.AlbumManual); res.Error != nil {
return removed, res.Error return removed, res.Error
} else if res.RowsAffected > 0 { } else if res.RowsAffected > 0 {
removed = int(res.RowsAffected) removed = int(res.RowsAffected)

View File

@@ -77,7 +77,7 @@ func PhotoPreloadByUID(photoUID string) (photo entity.Photo, err error) {
func MissingPhotos(limit int, offset int) (entities entity.Photos, err error) { func MissingPhotos(limit int, offset int) (entities entity.Photos, err error) {
err = Db(). err = Db().
Select("photos.*"). Select("photos.*").
Where("id NOT IN (SELECT photo_id FROM files WHERE file_missing = 0 AND file_root = '/' AND deleted_at IS NULL)"). Where("id NOT IN (SELECT photo_id FROM files WHERE file_missing = FALSE AND file_root = '/' AND deleted_at IS NULL)").
Order("photos.id"). Order("photos.id").
Limit(limit).Offset(offset).Find(&entities).Error Limit(limit).Offset(offset).Find(&entities).Error
@@ -139,7 +139,7 @@ func FixPrimaries() error {
// Remove primary file flag from broken or missing files. // Remove primary file flag from broken or missing files.
if err := UnscopedDb().Table(entity.File{}.TableName()). if err := UnscopedDb().Table(entity.File{}.TableName()).
Where("(file_error <> '' OR file_missing = 1) AND file_primary <> 0"). Where("(file_error <> '' OR file_missing = TRUE) AND file_primary <> 0").
UpdateColumn("file_primary", 0).Error; err != nil { UpdateColumn("file_primary", 0).Error; err != nil {
return err return err
} }
@@ -148,7 +148,7 @@ func FixPrimaries() error {
if err := UnscopedDb(). if err := UnscopedDb().
Raw(`SELECT * FROM photos Raw(`SELECT * FROM photos
WHERE deleted_at IS NULL WHERE deleted_at IS NULL
AND id NOT IN (SELECT photo_id FROM files WHERE file_primary = 1)`). AND id NOT IN (SELECT photo_id FROM files WHERE file_primary = TRUE)`).
Find(&photos).Error; err != nil { Find(&photos).Error; err != nil {
return err return err
} }
@@ -188,7 +188,7 @@ func FlagHiddenPhotos() (err error) {
// Find and flag hidden photos. // Find and flag hidden photos.
if err = Db().Table(entity.Photo{}.TableName()). if err = Db().Table(entity.Photo{}.TableName()).
Where("id NOT IN (SELECT photo_id FROM files WHERE file_primary = 1 AND file_missing = 0 AND file_error = '' AND deleted_at IS NULL) AND photo_quality > -1"). Where("id NOT IN (SELECT photo_id FROM files WHERE file_primary = TRUE AND file_missing = FALSE AND file_error = '' AND deleted_at IS NULL) AND photo_quality > -1").
Pluck("id", &hidden).Error; err != nil { Pluck("id", &hidden).Error; err != nil {
// Find query failed. // Find query failed.
return err return err

View File

@@ -38,7 +38,7 @@ func SelectedPhotos(f form.Selection) (results entity.Photos, err error) {
OR photos.photo_path IN ( OR photos.photo_path IN (
SELECT a.path FROM folders a WHERE a.folder_uid IN (?) UNION SELECT a.path FROM folders a WHERE a.folder_uid IN (?) UNION
SELECT b.path FROM folders a JOIN folders b ON b.path LIKE %s WHERE a.folder_uid IN (?)) SELECT b.path FROM folders a JOIN folders b ON b.path LIKE %s WHERE a.folder_uid IN (?))
OR photos.photo_uid IN (SELECT photo_uid FROM photos_albums WHERE hidden = 0 AND album_uid IN (?)) OR photos.photo_uid IN (SELECT photo_uid FROM photos_albums WHERE hidden = FALSE AND album_uid IN (?))
OR photos.id IN (SELECT f.photo_id FROM files f JOIN %s m ON f.file_uid = m.file_uid WHERE f.deleted_at IS NULL AND m.subj_uid IN (?)) OR photos.id IN (SELECT f.photo_id FROM files f JOIN %s m ON f.file_uid = m.file_uid WHERE f.deleted_at IS NULL AND m.subj_uid IN (?))
OR photos.id IN (SELECT pl.photo_id FROM photos_labels pl JOIN labels l ON pl.label_id = l.id AND pl.uncertainty < 100 AND l.deleted_at IS NULL WHERE l.label_uid IN (?)) OR photos.id IN (SELECT pl.photo_id FROM photos_labels pl JOIN labels l ON pl.label_id = l.id AND pl.uncertainty < 100 AND l.deleted_at IS NULL WHERE l.label_uid IN (?))
OR photos.id IN (SELECT pl.photo_id FROM photos_labels pl JOIN categories c ON c.label_id = pl.label_id AND pl.uncertainty < 100 JOIN labels lc ON lc.id = c.category_id AND lc.deleted_at IS NULL WHERE lc.label_uid IN (?))`, OR photos.id IN (SELECT pl.photo_id FROM photos_labels pl JOIN categories c ON c.label_id = pl.label_id AND pl.uncertainty < 100 JOIN labels lc ON lc.id = c.category_id AND lc.deleted_at IS NULL WHERE lc.label_uid IN (?))`,

View File

@@ -71,7 +71,7 @@ func PurgeOrphanDuplicates() error {
result := UnscopedDb(). result := UnscopedDb().
Delete(entity.Duplicate{}, Delete(entity.Duplicate{},
"file_hash NOT IN (SELECT file_hash FROM files WHERE file_missing = 0 AND deleted_at IS NULL)") "file_hash NOT IN (SELECT file_hash FROM files WHERE file_missing = FALSE AND deleted_at IS NULL)")
return result.Error return result.Error
} }

View File

@@ -26,7 +26,7 @@ func PeopleCount() (count int, err error) {
err = Db(). err = Db().
Table(entity.Subject{}.TableName()). Table(entity.Subject{}.TableName()).
Where("deleted_at IS NULL"). Where("deleted_at IS NULL").
Where("subj_hidden = 0"). Where("subj_hidden = FALSE").
Where("subj_type = ?", entity.SubjPerson). Where("subj_type = ?", entity.SubjPerson).
Count(&cnt).Error Count(&cnt).Error

View File

@@ -32,7 +32,7 @@ func UserAlbums(f form.SearchAlbums, sess *entity.Session) (results AlbumResults
// Base query. // Base query.
s := UnscopedDb().Table("albums"). s := UnscopedDb().Table("albums").
Select("albums.*, cp.photo_count, cl.link_count, CASE WHEN albums.album_year = 0 THEN 0 ELSE 1 END AS has_year, CASE WHEN albums.album_location = '' THEN 1 ELSE 0 END AS no_location"). Select("albums.*, cp.photo_count, cl.link_count, CASE WHEN albums.album_year = 0 THEN 0 ELSE 1 END AS has_year, CASE WHEN albums.album_location = '' THEN 1 ELSE 0 END AS no_location").
Joins("LEFT JOIN (SELECT album_uid, count(photo_uid) AS photo_count FROM photos_albums WHERE hidden = 0 AND missing = 0 GROUP BY album_uid) AS cp ON cp.album_uid = albums.album_uid"). Joins("LEFT JOIN (SELECT album_uid, count(photo_uid) AS photo_count FROM photos_albums WHERE hidden = FALSE AND missing = FALSE GROUP BY album_uid) AS cp ON cp.album_uid = albums.album_uid").
Joins("LEFT JOIN (SELECT share_uid, count(share_uid) AS link_count FROM links GROUP BY share_uid) AS cl ON cl.share_uid = albums.album_uid"). Joins("LEFT JOIN (SELECT share_uid, count(share_uid) AS link_count FROM links GROUP BY share_uid) AS cl ON cl.share_uid = albums.album_uid").
Where("albums.deleted_at IS NULL") Where("albums.deleted_at IS NULL")
@@ -153,7 +153,7 @@ func UserAlbums(f form.SearchAlbums, sess *entity.Session) (results AlbumResults
// Albums with public pictures only? // Albums with public pictures only?
if f.Public { if f.Public {
s = s.Where("albums.album_private = 0 AND (albums.album_type <> 'folder' OR albums.album_path IN (SELECT photo_path FROM photos WHERE photo_private = 0 AND photo_quality > -1 AND deleted_at IS NULL))") s = s.Where("albums.album_private = FALSE AND (albums.album_type <> 'folder' OR albums.album_path IN (SELECT photo_path FROM photos WHERE photo_private = FALSE AND photo_quality > -1 AND deleted_at IS NULL))")
} else { } else {
s = s.Where("albums.album_type <> 'folder' OR albums.album_path IN (SELECT photo_path FROM photos WHERE photo_quality > -1 AND deleted_at IS NULL)") s = s.Where("albums.album_type <> 'folder' OR albums.album_path IN (SELECT photo_path FROM photos WHERE photo_quality > -1 AND deleted_at IS NULL)")
} }
@@ -176,7 +176,7 @@ func UserAlbums(f form.SearchAlbums, sess *entity.Session) (results AlbumResults
// Favorites only? // Favorites only?
if f.Favorite { if f.Favorite {
s = s.Where("albums.album_favorite = 1") s = s.Where("albums.album_favorite = TRUE")
} }
// Filter by year? // Filter by year?
@@ -185,7 +185,7 @@ func UserAlbums(f form.SearchAlbums, sess *entity.Session) (results AlbumResults
// year assigned to them, unlike calendar albums and moments for example. // year assigned to them, unlike calendar albums and moments for example.
if f.Type == entity.AlbumManual { if f.Type == entity.AlbumManual {
s = s.Where("? OR albums.album_uid IN (SELECT DISTINCT pay.album_uid FROM photos_albums pay "+ s = s.Where("? OR albums.album_uid IN (SELECT DISTINCT pay.album_uid FROM photos_albums pay "+
"JOIN photos py ON pay.photo_uid = py.photo_uid WHERE py.photo_year IN (?) AND pay.hidden = 0 AND pay.missing = 0)", "JOIN photos py ON pay.photo_uid = py.photo_uid WHERE py.photo_year IN (?) AND pay.hidden = FALSE AND pay.missing = FALSE)",
gorm.Expr(AnyInt("albums.album_year", f.Year, txt.Or, entity.UnknownYear, txt.YearMax)), strings.Split(f.Year, txt.Or)) gorm.Expr(AnyInt("albums.album_year", f.Year, txt.Or, entity.UnknownYear, txt.YearMax)), strings.Split(f.Year, txt.Or))
} else { } else {
s = s.Where(AnyInt("albums.album_year", f.Year, txt.Or, entity.UnknownYear, txt.YearMax)) s = s.Where(AnyInt("albums.album_year", f.Year, txt.Or, entity.UnknownYear, txt.YearMax))

View File

@@ -91,7 +91,7 @@ func Faces(f form.SearchFaces) (results FaceResults, err error) {
// Show hidden faces? // Show hidden faces?
if !txt.Yes(f.Hidden) { if !txt.Yes(f.Hidden) {
s = s.Where(fmt.Sprintf("%s.face_hidden = 0", facesTable)) s = s.Where(fmt.Sprintf("%s.face_hidden = FALSE", facesTable))
} }
// Perform query. // Perform query.

View File

@@ -78,11 +78,11 @@ func Labels(f form.SearchLabels) (results []Label, err error) {
} }
if f.Favorite { if f.Favorite {
s = s.Where("labels.label_favorite = 1") s = s.Where("labels.label_favorite = TRUE")
} }
if !f.All { if !f.All {
s = s.Where("labels.label_priority >= 0 OR labels.label_favorite = 1") s = s.Where("labels.label_priority >= 0 OR labels.label_favorite = TRUE")
} }
if result := s.Scan(&results); result.Error != nil { if result := s.Scan(&results); result.Error != nil {

View File

@@ -105,13 +105,13 @@ func searchPhotos(f form.SearchPhotos, sess *entity.Session, resultCols string)
return PhotoResults{}, 0, ErrInvalidId return PhotoResults{}, 0, ErrInvalidId
} else if a.AlbumFilter == "" { } else if a.AlbumFilter == "" {
s = s.Joins("JOIN photos_albums ON photos_albums.photo_uid = files.photo_uid"). s = s.Joins("JOIN photos_albums ON photos_albums.photo_uid = files.photo_uid").
Where("photos_albums.hidden = 0 AND photos_albums.album_uid = ?", a.AlbumUID) Where("photos_albums.hidden = FALSE AND photos_albums.album_uid = ?", a.AlbumUID)
} else if formErr := form.Unserialize(&f, a.AlbumFilter); formErr != nil { } else if formErr := form.Unserialize(&f, a.AlbumFilter); formErr != nil {
log.Debugf("search: %s (%s)", clean.Error(formErr), clean.Log(a.AlbumFilter)) log.Debugf("search: %s (%s)", clean.Error(formErr), clean.Log(a.AlbumFilter))
return PhotoResults{}, 0, ErrBadFilter return PhotoResults{}, 0, ErrBadFilter
} else { } else {
f.Filter = a.AlbumFilter f.Filter = a.AlbumFilter
s = s.Where("files.photo_uid NOT IN (SELECT photo_uid FROM photos_albums pa WHERE pa.hidden = 1 AND pa.album_uid = ?)", a.AlbumUID) s = s.Where("files.photo_uid NOT IN (SELECT photo_uid FROM photos_albums pa WHERE pa.hidden = TRUE AND pa.album_uid = ?)", a.AlbumUID)
} }
// Enforce search distance range (km). // Enforce search distance range (km).
@@ -155,7 +155,7 @@ func searchPhotos(f form.SearchPhotos, sess *entity.Session, resultCols string)
// Limit results for external users. // Limit results for external users.
if f.Scope == "" && acl.Rules.DenyAll(acl.ResourcePhotos, aclRole, acl.Permissions{acl.AccessAll, acl.AccessLibrary}) { if f.Scope == "" && acl.Rules.DenyAll(acl.ResourcePhotos, aclRole, acl.Permissions{acl.AccessAll, acl.AccessLibrary}) {
sharedAlbums := "photos.photo_uid IN (SELECT photo_uid FROM photos_albums WHERE hidden = 0 AND missing = 0 AND album_uid IN (?)) OR " sharedAlbums := "photos.photo_uid IN (SELECT photo_uid FROM photos_albums WHERE hidden = FALSE AND missing = FALSE AND album_uid IN (?)) OR "
if sess.IsVisitor() || sess.NotRegistered() { if sess.IsVisitor() || sess.NotRegistered() {
s = s.Where(sharedAlbums+"photos.published_at > ?", sess.SharedUIDs(), entity.TimeStamp()) s = s.Where(sharedAlbums+"photos.published_at > ?", sess.SharedUIDs(), entity.TimeStamp())
@@ -210,14 +210,14 @@ func searchPhotos(f form.SearchPhotos, sess *entity.Session, resultCols string)
// Find primary files only? // Find primary files only?
if f.Primary { if f.Primary {
s = s.Where("files.file_primary = 1") s = s.Where("files.file_primary = TRUE")
} else if f.Order == sortby.Similar { } else if f.Order == sortby.Similar {
s = s.Where("files.file_primary = 1 OR files.media_type = ?", media.Video) s = s.Where("files.file_primary = TRUE OR files.media_type = ?", media.Video)
} else if f.Order == sortby.Random { } else if f.Order == sortby.Random {
s = s.Where("files.file_primary = 1 AND photos.photo_type NOT IN ('live','video') OR photos.photo_type IN ('live','video') AND files.media_type IN ('live','video')") s = s.Where("files.file_primary = TRUE AND photos.photo_type NOT IN ('live','video') OR photos.photo_type IN ('live','video') AND files.media_type IN ('live','video')")
} else { } else {
// Otherwise, find all matching media except sidecar files. // Otherwise, find all matching media except sidecar files.
s = s.Where("files.file_sidecar = 0") s = s.Where("files.file_sidecar = FALSE")
} }
// Find specific UIDs only. // Find specific UIDs only.
@@ -467,9 +467,9 @@ func searchPhotos(f form.SearchPhotos, sess *entity.Session, resultCols string)
s = s.Where("photos.deleted_at IS NULL") s = s.Where("photos.deleted_at IS NULL")
if f.Private { if f.Private {
s = s.Where("photos.photo_private = 1") s = s.Where("photos.photo_private = TRUE")
} else if f.Public { } else if f.Public {
s = s.Where("photos.photo_private = 0") s = s.Where("photos.photo_private = FALSE")
} }
if f.Review { if f.Review {
@@ -564,9 +564,9 @@ func searchPhotos(f form.SearchPhotos, sess *entity.Session, resultCols string)
// Filter by favorite flag. // Filter by favorite flag.
if txt.No(f.Favorite) { if txt.No(f.Favorite) {
s = s.Where("photos.photo_favorite = 0") s = s.Where("photos.photo_favorite = FALSE")
} else if txt.NotEmpty(f.Favorite) { } else if txt.NotEmpty(f.Favorite) {
s = s.Where("photos.photo_favorite = 1") s = s.Where("photos.photo_favorite = TRUE")
} }
// Filter by scan flag. // Filter by scan flag.
@@ -722,13 +722,13 @@ func searchPhotos(f form.SearchPhotos, sess *entity.Session, resultCols string)
// Find photos in albums or not in an album, unless search results are limited to a scope. // Find photos in albums or not in an album, unless search results are limited to a scope.
if f.Scope == "" { if f.Scope == "" {
if f.Unsorted { if f.Unsorted {
s = s.Where("photos.photo_uid NOT IN (SELECT photo_uid FROM photos_albums pa JOIN albums a ON a.album_uid = pa.album_uid WHERE pa.hidden = 0 AND a.deleted_at IS NULL)") s = s.Where("photos.photo_uid NOT IN (SELECT photo_uid FROM photos_albums pa JOIN albums a ON a.album_uid = pa.album_uid WHERE pa.hidden = FALSE AND a.deleted_at IS NULL)")
} else if txt.NotEmpty(f.Album) { } else if txt.NotEmpty(f.Album) {
v := strings.Trim(f.Album, "*%") + "%" v := strings.Trim(f.Album, "*%") + "%"
s = s.Where("photos.photo_uid IN (SELECT pa.photo_uid FROM photos_albums pa JOIN albums a ON a.album_uid = pa.album_uid AND pa.hidden = 0 WHERE (a.album_title LIKE ? OR a.album_slug LIKE ?))", v, v) s = s.Where("photos.photo_uid IN (SELECT pa.photo_uid FROM photos_albums pa JOIN albums a ON a.album_uid = pa.album_uid AND pa.hidden = FALSE WHERE (a.album_title LIKE ? OR a.album_slug LIKE ?))", v, v)
} else if txt.NotEmpty(f.Albums) { } else if txt.NotEmpty(f.Albums) {
for _, where := range LikeAnyWord("a.album_title", f.Albums) { for _, where := range LikeAnyWord("a.album_title", f.Albums) {
s = s.Where("photos.photo_uid IN (SELECT pa.photo_uid FROM photos_albums pa JOIN albums a ON a.album_uid = pa.album_uid AND pa.hidden = 0 WHERE (?))", gorm.Expr(where)) s = s.Where("photos.photo_uid IN (SELECT pa.photo_uid FROM photos_albums pa JOIN albums a ON a.album_uid = pa.album_uid AND pa.hidden = FALSE WHERE (?))", gorm.Expr(where))
} }
} }
} }

View File

@@ -69,7 +69,7 @@ func UserPhotosGeo(f form.SearchPhotosGeo, sess *entity.Session) (results GeoRes
// Specify table names and joins. // Specify table names and joins.
s := UnscopedDb().Table(entity.Photo{}.TableName()).Select(GeoCols). s := UnscopedDb().Table(entity.Photo{}.TableName()).Select(GeoCols).
Joins(`JOIN files ON files.photo_id = photos.id AND files.file_primary = 1 AND files.media_id IS NOT NULL`). Joins(`JOIN files ON files.photo_id = photos.id AND files.file_primary = TRUE AND files.media_id IS NOT NULL`).
Joins("LEFT JOIN places ON photos.place_id = places.id"). Joins("LEFT JOIN places ON photos.place_id = places.id").
Where("photos.deleted_at IS NULL"). Where("photos.deleted_at IS NULL").
Where("photos.photo_lat <> 0") Where("photos.photo_lat <> 0")
@@ -93,13 +93,13 @@ func UserPhotosGeo(f form.SearchPhotosGeo, sess *entity.Session) (results GeoRes
return GeoResults{}, ErrInvalidId return GeoResults{}, ErrInvalidId
} else if a.AlbumFilter == "" { } else if a.AlbumFilter == "" {
s = s.Joins("JOIN photos_albums ON photos_albums.photo_uid = files.photo_uid"). s = s.Joins("JOIN photos_albums ON photos_albums.photo_uid = files.photo_uid").
Where("photos_albums.hidden = 0 AND photos_albums.album_uid = ?", a.AlbumUID) Where("photos_albums.hidden = FALSE AND photos_albums.album_uid = ?", a.AlbumUID)
} else if formErr := form.Unserialize(&f, a.AlbumFilter); formErr != nil { } else if formErr := form.Unserialize(&f, a.AlbumFilter); formErr != nil {
log.Debugf("search: %s (%s)", clean.Error(formErr), clean.Log(a.AlbumFilter)) log.Debugf("search: %s (%s)", clean.Error(formErr), clean.Log(a.AlbumFilter))
return GeoResults{}, ErrBadFilter return GeoResults{}, ErrBadFilter
} else { } else {
f.Filter = a.AlbumFilter f.Filter = a.AlbumFilter
s = s.Where("files.photo_uid NOT IN (SELECT photo_uid FROM photos_albums pa WHERE pa.hidden = 1 AND pa.album_uid = ?)", a.AlbumUID) s = s.Where("files.photo_uid NOT IN (SELECT photo_uid FROM photos_albums pa WHERE pa.hidden = TRUE AND pa.album_uid = ?)", a.AlbumUID)
} }
// Enforce search distance range (km). // Enforce search distance range (km).
@@ -138,7 +138,7 @@ func UserPhotosGeo(f form.SearchPhotosGeo, sess *entity.Session) (results GeoRes
// Limit results for external users. // Limit results for external users.
if f.Scope == "" && acl.Rules.DenyAll(acl.ResourcePlaces, aclRole, acl.Permissions{acl.AccessAll, acl.AccessLibrary}) { if f.Scope == "" && acl.Rules.DenyAll(acl.ResourcePlaces, aclRole, acl.Permissions{acl.AccessAll, acl.AccessLibrary}) {
sharedAlbums := "photos.photo_uid IN (SELECT photo_uid FROM photos_albums WHERE hidden = 0 AND missing = 0 AND album_uid IN (?)) OR " sharedAlbums := "photos.photo_uid IN (SELECT photo_uid FROM photos_albums WHERE hidden = FALSE AND missing = FALSE AND album_uid IN (?)) OR "
if sess.IsVisitor() || sess.NotRegistered() { if sess.IsVisitor() || sess.NotRegistered() {
s = s.Where(sharedAlbums+"photos.published_at > ?", sess.SharedUIDs(), entity.TimeStamp()) s = s.Where(sharedAlbums+"photos.published_at > ?", sess.SharedUIDs(), entity.TimeStamp())
@@ -387,13 +387,13 @@ func UserPhotosGeo(f form.SearchPhotosGeo, sess *entity.Session) (results GeoRes
// Find photos in albums or not in an album, unless search results are limited to a scope. // Find photos in albums or not in an album, unless search results are limited to a scope.
if f.Scope == "" { if f.Scope == "" {
if f.Unsorted { if f.Unsorted {
s = s.Where("photos.photo_uid NOT IN (SELECT photo_uid FROM photos_albums pa JOIN albums a ON a.album_uid = pa.album_uid WHERE pa.hidden = 0 AND a.deleted_at IS NULL)") s = s.Where("photos.photo_uid NOT IN (SELECT photo_uid FROM photos_albums pa JOIN albums a ON a.album_uid = pa.album_uid WHERE pa.hidden = FALSE AND a.deleted_at IS NULL)")
} else if txt.NotEmpty(f.Album) { } else if txt.NotEmpty(f.Album) {
v := strings.Trim(f.Album, "*%") + "%" v := strings.Trim(f.Album, "*%") + "%"
s = s.Where("photos.photo_uid IN (SELECT pa.photo_uid FROM photos_albums pa JOIN albums a ON a.album_uid = pa.album_uid AND pa.hidden = 0 WHERE (a.album_title LIKE ? OR a.album_slug LIKE ?))", v, v) s = s.Where("photos.photo_uid IN (SELECT pa.photo_uid FROM photos_albums pa JOIN albums a ON a.album_uid = pa.album_uid AND pa.hidden = FALSE WHERE (a.album_title LIKE ? OR a.album_slug LIKE ?))", v, v)
} else if txt.NotEmpty(f.Albums) { } else if txt.NotEmpty(f.Albums) {
for _, where := range LikeAnyWord("a.album_title", f.Albums) { for _, where := range LikeAnyWord("a.album_title", f.Albums) {
s = s.Where("photos.photo_uid IN (SELECT pa.photo_uid FROM photos_albums pa JOIN albums a ON a.album_uid = pa.album_uid AND pa.hidden = 0 WHERE (?))", gorm.Expr(where)) s = s.Where("photos.photo_uid IN (SELECT pa.photo_uid FROM photos_albums pa JOIN albums a ON a.album_uid = pa.album_uid AND pa.hidden = FALSE WHERE (?))", gorm.Expr(where))
} }
} }
} }
@@ -473,9 +473,9 @@ func UserPhotosGeo(f form.SearchPhotosGeo, sess *entity.Session) (results GeoRes
// Filter by favorite flag. // Filter by favorite flag.
if txt.No(f.Favorite) { if txt.No(f.Favorite) {
s = s.Where("photos.photo_favorite = 0") s = s.Where("photos.photo_favorite = FALSE")
} else if txt.NotEmpty(f.Favorite) { } else if txt.NotEmpty(f.Favorite) {
s = s.Where("photos.photo_favorite = 1") s = s.Where("photos.photo_favorite = TRUE")
} }
// Filter by scan flag. // Filter by scan flag.
@@ -565,9 +565,9 @@ func UserPhotosGeo(f form.SearchPhotosGeo, sess *entity.Session) (results GeoRes
s = s.Where("photos.deleted_at IS NULL") s = s.Where("photos.deleted_at IS NULL")
if f.Private { if f.Private {
s = s.Where("photos.photo_private = 1") s = s.Where("photos.photo_private = TRUE")
} else if f.Public { } else if f.Public {
s = s.Where("photos.photo_private = 0") s = s.Where("photos.photo_private = FALSE")
} }
if f.Review { if f.Review {

View File

@@ -82,7 +82,7 @@ func Subjects(f form.SearchSubjects) (results SubjectResults, err error) {
} }
if !txt.Yes(f.Hidden) { if !txt.Yes(f.Hidden) {
s = s.Where("subj_hidden = 0") s = s.Where("subj_hidden = FALSE")
} }
if txt.Yes(f.Private) { if txt.Yes(f.Private) {