mirror of
https://github.com/photoprism/photoprism.git
synced 2026-07-18 09:05:25 +00:00
Replace GORM with GORMv2
This commit is contained in:
parent
8257b82c01
commit
20dad85a8e
119 changed files with 491 additions and 487 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -66,3 +66,6 @@ Thumbs.db
|
|||
|
||||
#Karma Coverage Report
|
||||
frontend/coverage/
|
||||
|
||||
# IDE files from exotic IDEs :-)
|
||||
.vscode/
|
||||
|
|
|
|||
26
go.mod
26
go.mod
|
|
@ -19,14 +19,12 @@ require (
|
|||
github.com/google/open-location-code/go v0.0.0-20240410091707-7dc3b4c76be0
|
||||
github.com/gorilla/websocket v1.5.1
|
||||
github.com/gosimple/slug v1.14.0
|
||||
github.com/jinzhu/gorm v1.9.16
|
||||
github.com/jinzhu/inflection v1.0.0
|
||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
|
||||
github.com/karrick/godirwalk v1.17.0
|
||||
github.com/klauspost/cpuid/v2 v2.2.7
|
||||
github.com/leandro-lugaresi/hub v1.1.1
|
||||
github.com/leonelquinteros/gotext v1.6.0
|
||||
github.com/lib/pq v1.10.9 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0
|
||||
github.com/mandykoh/prism v0.35.2
|
||||
github.com/manifoldco/promptui v0.9.0
|
||||
|
|
@ -59,10 +57,7 @@ require github.com/olekukonko/tablewriter v0.0.5
|
|||
|
||||
require github.com/google/uuid v1.6.0
|
||||
|
||||
require (
|
||||
github.com/chzyer/readline v1.5.1 // indirect
|
||||
github.com/zitadel/oidc v1.13.5
|
||||
)
|
||||
require github.com/chzyer/readline v1.5.1 // indirect
|
||||
|
||||
require github.com/gabriel-vasile/mimetype v1.4.3
|
||||
|
||||
|
|
@ -71,8 +66,6 @@ require (
|
|||
golang.org/x/time v0.5.0
|
||||
)
|
||||
|
||||
require github.com/go-ldap/ldap/v3 v3.4.8
|
||||
|
||||
require (
|
||||
github.com/prometheus/client_golang v1.19.0
|
||||
github.com/prometheus/common v0.53.0
|
||||
|
|
@ -82,10 +75,14 @@ require github.com/dustinkirkland/golang-petname v0.0.0-20231002161417-6a283f1aa
|
|||
|
||||
require golang.org/x/text v0.14.0
|
||||
|
||||
require github.com/pquerna/otp v1.4.0
|
||||
require (
|
||||
github.com/pquerna/otp v1.4.0
|
||||
gorm.io/driver/mysql v1.5.6
|
||||
gorm.io/driver/sqlite v1.5.5
|
||||
gorm.io/gorm v1.25.9
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/boombuler/barcode v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
|
|
@ -96,15 +93,10 @@ require (
|
|||
github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd // indirect
|
||||
github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-sql-driver/mysql v1.7.1 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/gorilla/mux v1.8.1 // indirect
|
||||
github.com/gorilla/schema v1.2.1 // indirect
|
||||
github.com/gorilla/securecookie v1.1.2 // indirect
|
||||
github.com/gosimple/unidecode v1.0.1 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
|
|
@ -121,13 +113,9 @@ require (
|
|||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
github.com/zitadel/logging v0.5.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect
|
||||
golang.org/x/oauth2 v0.18.0 // indirect
|
||||
golang.org/x/sys v0.19.0 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
|
|
|
|||
97
go.sum
97
go.sum
|
|
@ -15,17 +15,11 @@ cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+
|
|||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||
github.com/abema/go-mp4 v1.2.0 h1:gi4X8xg/m179N/J15Fn5ugywN9vtI6PLk6iLldHGLAk=
|
||||
github.com/abema/go-mp4 v1.2.0/go.mod h1:vPl9t5ZK7K0x68jh12/+ECWBCXoWuIDtNgPtU2f04ws=
|
||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI=
|
||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
|
||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA=
|
||||
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
|
|
@ -64,8 +58,6 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do
|
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||
github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c=
|
||||
|
|
@ -113,8 +105,6 @@ github.com/emersion/go-webdav v0.5.0 h1:Ak/BQLgAihJt/UxJbCsEXDPxS5Uw4nZzgIMOq3rk
|
|||
github.com/emersion/go-webdav v0.5.0/go.mod h1:ycyIzTelG5pHln4t+Y32/zBvmrM7+mV7x+V+Gx4ZQno=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
|
||||
github.com/esimov/pigo v1.4.6 h1:wpB9FstbqeGP/CZP+nTR52tUJe7XErq8buG+k4xCXlw=
|
||||
github.com/esimov/pigo v1.4.6/go.mod h1:uqj9Y3+3IRYhFK071rxz1QYq0ePhA6+R9jrUZavi46M=
|
||||
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||
|
|
@ -126,8 +116,6 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE
|
|||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
|
||||
github.com/go-errors/errors v1.1.1/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
|
||||
|
|
@ -136,8 +124,6 @@ github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8b
|
|||
github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-ldap/ldap/v3 v3.4.8 h1:loKJyspcRezt2Q3ZRMq2p/0v8iOurlmeXDPw6fikSvQ=
|
||||
github.com/go-ldap/ldap/v3 v3.4.8/go.mod h1:qS3Sjlu76eHfHGpUdWkAXQTw4beih+cHsco2jXlIXrk=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
|
|
@ -146,7 +132,7 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
|
|||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4=
|
||||
github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
|
||||
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
|
||||
|
|
@ -154,8 +140,6 @@ github.com/go-xmlfmt/xmlfmt v1.1.2 h1:Nea7b4icn8s57fTx1M5AI4qQT5HEM3rVUO8MuE6g80
|
|||
github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
||||
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
||||
|
|
@ -174,22 +158,15 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
|
|||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/open-location-code/go v0.0.0-20240410091707-7dc3b4c76be0 h1:YIK9r/QyVL/8zvbI5mwpSVgnG8l6h3SzidataCwpbDQ=
|
||||
github.com/google/open-location-code/go v0.0.0-20240410091707-7dc3b4c76be0/go.mod h1:eJfRN6aj+kR/rnua/rw9jAgYhqoMHldQkdTi+sePRKk=
|
||||
|
|
@ -202,48 +179,20 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
|||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||
github.com/gorilla/schema v1.2.1 h1:tjDxcmdb+siIqkTNoV+qRH2mjYdr2hHe5MKXbp61ziM=
|
||||
github.com/gorilla/schema v1.2.1/go.mod h1:Dg5SSm5PV60mhF2NFaTV1xuYYj8tV8NOPRo4FggUMnM=
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
|
||||
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
|
||||
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
||||
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
|
||||
github.com/gosimple/slug v1.14.0 h1:RtTL/71mJNDfpUbCOmnf/XFkzKRtD6wL6Uy+3akm4Es=
|
||||
github.com/gosimple/slug v1.14.0/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ=
|
||||
github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o=
|
||||
github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc=
|
||||
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
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/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
|
||||
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
|
||||
github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=
|
||||
github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
|
||||
github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg=
|
||||
github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo=
|
||||
github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o=
|
||||
github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=
|
||||
github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8=
|
||||
github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs=
|
||||
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
|
||||
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
|
||||
github.com/jdeng/goheif v0.0.0-20200323230657-a0d6a8b3e68f/go.mod h1:G7IyA3/eR9IFmUIPdyP3c0l4ZaqEvXAk876WfaQ8plc=
|
||||
github.com/jeremija/gosubmit v0.2.7 h1:At0OhGCFGPXyjPYAsCchoBUhE099pcBXmsb4iZqROIc=
|
||||
github.com/jeremija/gosubmit v0.2.7/go.mod h1:Ui+HS073lCFREXBbdfrJzMB57OI/bdxTiLtrDHHhFPI=
|
||||
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/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
|
||||
github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
|
|
@ -272,9 +221,6 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
|||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/leonelquinteros/gotext v1.6.0 h1:IYL2+dKsaYYvqGAOafaC7mpAGBhMrD/vKjHUGyp8V64=
|
||||
github.com/leonelquinteros/gotext v1.6.0/go.mod h1:qQRISjoonXYFdRGrTG1LARQ38Gpibad0IPeB4hpvyyM=
|
||||
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/mandykoh/go-parallel v0.1.0 h1:7vJMNMC4dsbgZdkAb2A8tV5ENY1v7VxIO1wzQWZoT8k=
|
||||
|
|
@ -289,7 +235,6 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m
|
|||
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
|
|
@ -331,8 +276,6 @@ github.com/rivo/uniseg v0.4.6/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUc
|
|||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo=
|
||||
github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd h1:CmH9+J6ZSsIjUK3dcGsnCnO41eRBOnY12zwkn5qVwgc=
|
||||
|
|
@ -378,10 +321,6 @@ github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6/go.mod h1:h8272+G
|
|||
github.com/urfave/cli v1.22.14 h1:ebbhrRiGK2i4naQJr+1Xj92HXZCrK7MsyTS/ob3HnAk=
|
||||
github.com/urfave/cli v1.22.14/go.mod h1:X0eDS6pD6Exaclxm99NJ3FiCDRED7vIHpx2mDOHLvkA=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/zitadel/logging v0.5.0 h1:Kunouvqse/efXy4UDvFw5s3vP+Z4AlHo3y8wF7stXHA=
|
||||
github.com/zitadel/logging v0.5.0/go.mod h1:IzP5fzwFhzzyxHkSmfF8dsyqFsQRJLLcQmwhIBzlGsE=
|
||||
github.com/zitadel/oidc v1.13.5 h1:7jhh68NGZitLqwLiVU9Dtwa4IraJPFF1vS+4UupO93U=
|
||||
github.com/zitadel/oidc v1.13.5/go.mod h1:rHs1DhU3Sv3tnI6bQRVlFa3u0lCwtR7S21WHY+yXgPA=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
|
|
@ -393,16 +332,11 @@ golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUu
|
|||
golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
|
||||
golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
|
|
@ -440,7 +374,6 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
|
|||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
|
@ -453,11 +386,9 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR
|
|||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
|
|
@ -467,9 +398,6 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
|
|||
golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
|
|
@ -477,8 +405,6 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr
|
|||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
|
||||
golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
|
@ -518,27 +444,19 @@ golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20191110171634-ad39bd3f0407/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
|
|
@ -590,8 +508,6 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
|
|||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
|
|
@ -612,8 +528,6 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac
|
|||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
|
@ -623,8 +537,6 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV
|
|||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/photoprism/go-tz.v2 v2.1.2 h1:FvfcMZhoTW/NOi0h2W/+7zSktIw6pZ//fPTcG5JLccU=
|
||||
gopkg.in/photoprism/go-tz.v2 v2.1.2/go.mod h1:5nMEBZ864+F7kgqRrXOSrHTephWTHM36nM9/HYQ8i+g=
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
|
||||
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg=
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
|
@ -636,6 +548,13 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
|||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
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/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
|
||||
gorm.io/driver/sqlite v1.5.5 h1:7MDMtUZhV065SilG62E0MquljeArQZNfJnjd9i9gx3E=
|
||||
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.9 h1:wct0gxZIELDk8+ZqF/MVnHLkA1rvYlBWUMv2EdsK1g8=
|
||||
gorm.io/gorm v1.25.9/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-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/dustin/go-humanize/english"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/jinzhu/gorm"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/acl"
|
||||
"github.com/photoprism/photoprism/internal/entity"
|
||||
|
|
|
|||
|
|
@ -54,12 +54,12 @@ func authResetAction(ctx *cli.Context) error {
|
|||
db := conf.Db()
|
||||
|
||||
// Drop existing sessions table.
|
||||
if err := db.DropTableIfExists(entity.Session{}).Error; err != nil {
|
||||
return err
|
||||
if err := db.Migrator().DropTable(entity.Session{}); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
// Re-create auth_sessions.
|
||||
if err := db.CreateTable(entity.Session{}).Error; err != nil {
|
||||
if err := db.Migrator().CreateTable(entity.Session{}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,12 +53,12 @@ func clientsResetAction(ctx *cli.Context) error {
|
|||
db := conf.Db()
|
||||
|
||||
// Drop existing auth_clients table.
|
||||
if err := db.DropTableIfExists(entity.Client{}).Error; err != nil {
|
||||
return err
|
||||
if err := db.Migrator().DropTable(entity.Client{}); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
// Re-create auth_clients.
|
||||
if err := db.CreateTable(entity.Client{}).Error; err != nil {
|
||||
if err := db.Migrator().CreateTable(entity.Client{}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,32 +53,32 @@ func usersResetAction(ctx *cli.Context) error {
|
|||
db := conf.Db()
|
||||
|
||||
// Drop existing user management tables.
|
||||
if err := db.DropTableIfExists(entity.User{}, entity.UserDetails{}, entity.UserSettings{}, entity.UserShare{}, entity.Passcode{}).Error; err != nil {
|
||||
return err
|
||||
if err := db.Migrator().DropTable(entity.User{}, entity.UserDetails{}, entity.UserSettings{}, entity.UserShare{}, entity.Passcode{}); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
// Re-create auth_users.
|
||||
if err := db.CreateTable(entity.User{}).Error; err != nil {
|
||||
if err := db.Migrator().CreateTable(entity.User{}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Re-create auth_users_details.
|
||||
if err := db.CreateTable(entity.UserDetails{}).Error; err != nil {
|
||||
if err := db.Migrator().CreateTable(entity.UserDetails{}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Re-create auth_users_settings.
|
||||
if err := db.CreateTable(entity.UserSettings{}).Error; err != nil {
|
||||
if err := db.Migrator().CreateTable(entity.UserSettings{}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Re-create auth_users_shares.
|
||||
if err := db.CreateTable(entity.UserShare{}).Error; err != nil {
|
||||
if err := db.Migrator().CreateTable(entity.UserShare{}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Re-create passcodes.
|
||||
if err := db.CreateTable(entity.Passcode{}).Error; err != nil {
|
||||
if err := db.Migrator().CreateTable(entity.Passcode{}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,9 +37,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/jinzhu/gorm"
|
||||
_ "github.com/jinzhu/gorm/dialects/mysql"
|
||||
_ "github.com/jinzhu/gorm/dialects/sqlite"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/klauspost/cpuid/v2"
|
||||
"github.com/pbnjay/memory"
|
||||
|
|
|
|||
|
|
@ -10,14 +10,16 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
_ "github.com/jinzhu/gorm/dialects/mysql"
|
||||
_ "github.com/jinzhu/gorm/dialects/sqlite"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/entity"
|
||||
"github.com/photoprism/photoprism/internal/migrate"
|
||||
"github.com/photoprism/photoprism/internal/mutex"
|
||||
"github.com/photoprism/photoprism/pkg/clean"
|
||||
"github.com/photoprism/photoprism/pkg/dummy"
|
||||
"github.com/photoprism/photoprism/pkg/txt"
|
||||
)
|
||||
|
||||
|
|
@ -27,7 +29,7 @@ const (
|
|||
MySQL = "mysql"
|
||||
MariaDB = "mariadb"
|
||||
Postgres = "postgres"
|
||||
SQLite3 = "sqlite3"
|
||||
SQLite3 = "sqlite"
|
||||
)
|
||||
|
||||
// SQLite default DSNs.
|
||||
|
|
@ -36,12 +38,17 @@ const (
|
|||
SQLiteMemoryDSN = ":memory:"
|
||||
)
|
||||
|
||||
var drivers = map[string]func(string) gorm.Dialector{
|
||||
MySQL: mysql.Open,
|
||||
SQLite3: sqlite.Open,
|
||||
}
|
||||
|
||||
// DatabaseDriver returns the database driver name.
|
||||
func (c *Config) DatabaseDriver() string {
|
||||
switch strings.ToLower(c.options.DatabaseDriver) {
|
||||
case MySQL, MariaDB:
|
||||
c.options.DatabaseDriver = MySQL
|
||||
case SQLite3, "sqlite", "sqllite", "test", "file", "":
|
||||
case SQLite3, "sqllite", "test", "file", "":
|
||||
c.options.DatabaseDriver = SQLite3
|
||||
case "tidb":
|
||||
log.Warnf("config: database driver 'tidb' is deprecated, using sqlite")
|
||||
|
|
@ -268,10 +275,12 @@ func (c *Config) Db() *gorm.DB {
|
|||
// CloseDb closes the db connection (if any).
|
||||
func (c *Config) CloseDb() error {
|
||||
if c.db != nil {
|
||||
if err := c.db.Close(); err == nil {
|
||||
sqldb, dberr := c.db.DB()
|
||||
if dberr != nil {
|
||||
sqldb.Close()
|
||||
c.db = nil
|
||||
} else {
|
||||
return err
|
||||
return dberr
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -377,12 +386,12 @@ func (c *Config) connectDb() error {
|
|||
}
|
||||
|
||||
// Open database connection.
|
||||
db, err := gorm.Open(dbDriver, dbDsn)
|
||||
db, err := gorm.Open(drivers[dbDriver](dbDsn), gormConfig())
|
||||
if err != nil || db == nil {
|
||||
log.Infof("config: waiting for the database to become available")
|
||||
|
||||
for i := 1; i <= 12; i++ {
|
||||
db, err = gorm.Open(dbDriver, dbDsn)
|
||||
db, err := gorm.Open(drivers[dbDriver](dbDsn), gormConfig())
|
||||
|
||||
if db != nil && err == nil {
|
||||
break
|
||||
|
|
@ -396,14 +405,11 @@ func (c *Config) connectDb() error {
|
|||
}
|
||||
}
|
||||
|
||||
// Configure database logging.
|
||||
db.LogMode(false)
|
||||
db.SetLogger(log)
|
||||
sqlDB, err := db.DB()
|
||||
|
||||
// Set database connection parameters.
|
||||
db.DB().SetMaxOpenConns(c.DatabaseConns())
|
||||
db.DB().SetMaxIdleConns(c.DatabaseConnsIdle())
|
||||
db.DB().SetConnMaxLifetime(time.Hour)
|
||||
sqlDB.SetMaxIdleConns(4)
|
||||
sqlDB.SetMaxOpenConns(256)
|
||||
sqlDB.SetConnMaxLifetime(time.Hour)
|
||||
|
||||
// Check database server version.
|
||||
if err = c.checkDb(db); err != nil {
|
||||
|
|
@ -443,3 +449,22 @@ func (c *Config) ImportSQL(filename string) {
|
|||
q.Raw(stmt).Scan(&result)
|
||||
}
|
||||
}
|
||||
|
||||
func gormConfig() *gorm.Config {
|
||||
return &gorm.Config{
|
||||
Logger: logger.New(
|
||||
/* log, */ dummy.NewLogger(),
|
||||
logger.Config{
|
||||
SlowThreshold: time.Second, // Slow SQL threshold
|
||||
LogLevel: logger.Silent, // Log level
|
||||
IgnoreRecordNotFoundError: true, // Ignore ErrRecordNotFound error for logger
|
||||
ParameterizedQueries: true, // Don't include params in the SQL log
|
||||
Colorful: false, // Disable color
|
||||
},
|
||||
),
|
||||
// Set UTC as the default for created and updated timestamps.
|
||||
NowFunc: func() time.Time {
|
||||
return time.Now().UTC()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,9 +12,6 @@ import (
|
|||
|
||||
"github.com/urfave/cli"
|
||||
|
||||
_ "github.com/jinzhu/gorm/dialects/mysql"
|
||||
_ "github.com/jinzhu/gorm/dialects/sqlite"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/customize"
|
||||
"github.com/photoprism/photoprism/internal/thumb"
|
||||
"github.com/photoprism/photoprism/pkg/capture"
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ package config
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/photoprism/photoprism/pkg/fs"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/urfave/cli"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func TestConfig_TestdataPath2(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/ulule/deepcopier"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/event"
|
||||
"github.com/photoprism/photoprism/internal/form"
|
||||
|
|
@ -32,8 +32,8 @@ type Albums []Album
|
|||
|
||||
// Album represents a photo album
|
||||
type Album struct {
|
||||
ID uint `gorm:"primary_key" json:"ID" yaml:"-"`
|
||||
AlbumUID string `gorm:"type:VARBINARY(42);unique_index;" json:"UID" yaml:"UID"`
|
||||
ID uint `gorm:"primaryKey;" json:"ID" yaml:"-"`
|
||||
AlbumUID string `gorm:"type:VARBINARY(42);uniqueIndex;" json:"UID" yaml:"UID"`
|
||||
ParentUID string `gorm:"type:VARBINARY(42);default:'';" json:"ParentUID,omitempty" yaml:"ParentUID,omitempty"`
|
||||
AlbumSlug string `gorm:"type:VARBINARY(160);index;" json:"Slug" yaml:"Slug"`
|
||||
AlbumPath string `gorm:"type:VARCHAR(1024);index;" json:"Path,omitempty" yaml:"Path,omitempty"`
|
||||
|
|
@ -61,7 +61,7 @@ type Album struct {
|
|||
UpdatedAt time.Time `json:"UpdatedAt" yaml:"UpdatedAt,omitempty"`
|
||||
PublishedAt *time.Time `sql:"index" json:"PublishedAt,omitempty" yaml:"PublishedAt,omitempty"`
|
||||
DeletedAt *time.Time `sql:"index" json:"DeletedAt" yaml:"DeletedAt,omitempty"`
|
||||
Photos PhotoAlbums `gorm:"foreignkey:AlbumUID;association_foreignkey:AlbumUID;" json:"-" yaml:"Photos,omitempty"`
|
||||
Photos PhotoAlbums `gorm:"foreignKey:AlbumUID" json:"-" yaml:"Photos,omitempty"`
|
||||
}
|
||||
|
||||
// AfterUpdate flushes the album cache.
|
||||
|
|
@ -419,14 +419,14 @@ func (m *Album) Find() *Album {
|
|||
}
|
||||
|
||||
// BeforeCreate creates a random UID if needed before inserting a new row to the database.
|
||||
func (m *Album) BeforeCreate(scope *gorm.Scope) error {
|
||||
func (m *Album) BeforeCreate(scope *gorm.DB) error {
|
||||
if rnd.IsUID(m.AlbumUID, AlbumUID) {
|
||||
return nil
|
||||
}
|
||||
|
||||
m.AlbumUID = rnd.GenerateUID(AlbumUID)
|
||||
|
||||
return scope.SetColumn("AlbumUID", m.AlbumUID)
|
||||
scope.Statement.SetColumn("AlbumUID", m.AlbumUID)
|
||||
return scope.Error
|
||||
}
|
||||
|
||||
// String returns the id or name as string.
|
||||
|
|
@ -753,7 +753,6 @@ func (m *Album) Restore() error {
|
|||
if !m.Deleted() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := UnscopedDb().Model(m).Update("DeletedAt", nil).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -796,7 +795,7 @@ func (m *Album) AddPhotos(UIDs []string) (added PhotoAlbums) {
|
|||
|
||||
entry := PhotoAlbum{AlbumUID: m.AlbumUID, PhotoUID: uid, Hidden: false}
|
||||
|
||||
if err := entry.Save(); err != nil {
|
||||
if err := entry.Create(); err != nil {
|
||||
log.Errorf("album: %s (add to album %s)", err.Error(), m)
|
||||
} else {
|
||||
added = append(added, entry)
|
||||
|
|
|
|||
|
|
@ -32,10 +32,9 @@ func CachedAlbumByUID(uid string) (m Album, err error) {
|
|||
|
||||
// Find in database.
|
||||
m = Album{}
|
||||
r := Db().First(&m, "album_uid = ?", uid)
|
||||
|
||||
if r := Db().First(&m, "album_uid = ?", uid); r.RecordNotFound() {
|
||||
return m, fmt.Errorf("album not found")
|
||||
} else if r.Error != nil {
|
||||
if r.Error != nil {
|
||||
return m, r.Error
|
||||
} else {
|
||||
albumCache.SetDefault(m.AlbumUID, m)
|
||||
|
|
|
|||
|
|
@ -748,6 +748,6 @@ var AlbumFixtures = AlbumMap{
|
|||
// CreateAlbumFixtures inserts known entities into the database for testing.
|
||||
func CreateAlbumFixtures() {
|
||||
for _, entity := range AlbumFixtures {
|
||||
Db().Create(&entity)
|
||||
Db().Save(&entity)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import "github.com/photoprism/photoprism/internal/event"
|
|||
|
||||
// AlbumUser represents the user and group ownership of an Album and the corresponding permissions.
|
||||
type AlbumUser struct {
|
||||
UID string `gorm:"type:VARBINARY(42);primary_key;auto_increment:false" json:"UID" yaml:"UID"`
|
||||
UserUID string `gorm:"type:VARBINARY(42);primary_key;auto_increment:false;index" json:"UserUID,omitempty" yaml:"UserUID,omitempty"`
|
||||
UID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false" json:"UID" yaml:"UID"`
|
||||
UserUID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false;index" json:"UserUID,omitempty" yaml:"UserUID,omitempty"`
|
||||
TeamUID string `gorm:"type:VARBINARY(42);index" json:"TeamUID,omitempty" yaml:"TeamUID,omitempty"`
|
||||
Perm uint `json:"Perm,omitempty" yaml:"Perm,omitempty"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ func (m *Album) Yaml() (out []byte, err error) {
|
|||
m.CreatedAt = m.CreatedAt.UTC().Truncate(time.Second)
|
||||
m.UpdatedAt = m.UpdatedAt.UTC().Truncate(time.Second)
|
||||
|
||||
if err := Db().Model(m).Association("Photos").Find(&m.Photos).Error; err != nil {
|
||||
if err := Db().Model(m).Association("Photos").Find(&m.Photos); err != nil {
|
||||
log.Errorf("album: %s (yaml)", err)
|
||||
return out, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import (
|
|||
|
||||
"github.com/dustin/go-humanize/english"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/jinzhu/gorm"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/acl"
|
||||
"github.com/photoprism/photoprism/internal/event"
|
||||
|
|
@ -29,7 +29,7 @@ type Clients []Client
|
|||
|
||||
// Client represents a client application.
|
||||
type Client struct {
|
||||
ClientUID string `gorm:"type:VARBINARY(42);primary_key;auto_increment:false;" json:"-" yaml:"ClientUID"`
|
||||
ClientUID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false;" json:"-" yaml:"ClientUID"`
|
||||
UserUID string `gorm:"type:VARBINARY(42);index;default:'';" json:"UserUID" yaml:"UserUID,omitempty"`
|
||||
UserName string `gorm:"size:200;index;" json:"UserName" yaml:"UserName,omitempty"`
|
||||
user *User `gorm:"-" yaml:"-"`
|
||||
|
|
@ -74,14 +74,14 @@ func NewClient() *Client {
|
|||
}
|
||||
|
||||
// BeforeCreate creates a random UID if needed before inserting a new row to the database.
|
||||
func (m *Client) BeforeCreate(scope *gorm.Scope) error {
|
||||
func (m *Client) BeforeCreate(scope *gorm.DB) error {
|
||||
if rnd.IsUID(m.ClientUID, ClientUID) {
|
||||
return nil
|
||||
}
|
||||
|
||||
m.ClientUID = rnd.GenerateUID(ClientUID)
|
||||
|
||||
return scope.SetColumn("ClientUID", m.ClientUID)
|
||||
scope.Statement.SetColumn("ClientUID", m.ClientUID)
|
||||
return scope.Error
|
||||
}
|
||||
|
||||
// FindClientByUID returns the matching client or nil if it was not found.
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import (
|
|||
|
||||
"github.com/dustin/go-humanize/english"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/jinzhu/gorm"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/acl"
|
||||
"github.com/photoprism/photoprism/internal/event"
|
||||
|
|
@ -36,7 +36,7 @@ type Sessions []Session
|
|||
|
||||
// Session represents a User session.
|
||||
type Session struct {
|
||||
ID string `gorm:"type:VARBINARY(2048);primary_key;auto_increment:false;" json:"-" yaml:"ID"`
|
||||
ID string `gorm:"type:VARBINARY(2048);primaryKey;autoIncrement:false;" json:"-" yaml:"ID"`
|
||||
authToken string `gorm:"-" yaml:"-"`
|
||||
UserUID string `gorm:"type:VARBINARY(42);index;default:'';" json:"UserUID" yaml:"UserUID,omitempty"`
|
||||
UserName string `gorm:"size:200;index;" json:"UserName" yaml:"UserName,omitempty"`
|
||||
|
|
@ -226,10 +226,9 @@ func (m *Session) Updates(values interface{}) error {
|
|||
}
|
||||
|
||||
// BeforeCreate creates a random UID if needed before inserting a new row to the database.
|
||||
func (m *Session) BeforeCreate(scope *gorm.Scope) error {
|
||||
func (m *Session) BeforeCreate(scope *gorm.DB) error {
|
||||
if rnd.InvalidRefID(m.RefID) {
|
||||
m.RefID = rnd.RefID(SessionPrefix)
|
||||
Log("session", "set ref id", scope.SetColumn("RefID", m.RefID))
|
||||
}
|
||||
|
||||
if rnd.IsSessionID(m.ID) {
|
||||
|
|
@ -237,8 +236,8 @@ func (m *Session) BeforeCreate(scope *gorm.Scope) error {
|
|||
}
|
||||
|
||||
m.Regenerate()
|
||||
|
||||
return scope.SetColumn("ID", m.ID)
|
||||
scope.Statement.SetColumn("ID", m.ID)
|
||||
return scope.Error
|
||||
}
|
||||
|
||||
// SetClient updates the client of this session.
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ func FindSession(id string) (*Session, error) {
|
|||
} else if err := cached.Delete(); err != nil {
|
||||
event.AuditErr([]string{cached.IP(), "session %s", "failed to delete after expiration", "%s"}, cached.RefID, err)
|
||||
}
|
||||
} else if res := Db().First(&found, "id = ?", id); res.RecordNotFound() {
|
||||
} else if res := Db().First(&found, "id = ?", id); res.RowsAffected == 0 {
|
||||
return found, fmt.Errorf("invalid session")
|
||||
} else if res.Error != nil {
|
||||
return found, res.Error
|
||||
|
|
|
|||
|
|
@ -90,7 +90,8 @@ func DeleteClientSessions(client *Client, authMethod authn.MethodType, limit int
|
|||
q = q.Where("auth_method = ?", authMethod.String())
|
||||
}
|
||||
|
||||
q = q.Order("created_at DESC").Limit(1000000000).Offset(limit)
|
||||
// NOTE: this loses precision of the token limit. But I think int64 does not make sense for that limit type anyway.
|
||||
q = q.Order("created_at DESC").Limit(1000000000).Offset(int(limit))
|
||||
|
||||
found := Sessions{}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/ulule/deepcopier"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/acl"
|
||||
"github.com/photoprism/photoprism/internal/event"
|
||||
|
|
@ -44,9 +44,9 @@ type Users []User
|
|||
|
||||
// User represents a person that may optionally log in as user.
|
||||
type User struct {
|
||||
ID int `gorm:"primary_key" 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"`
|
||||
UserUID string `gorm:"type:VARBINARY(42);column:user_uid;unique_index;" json:"UID" yaml:"UID"`
|
||||
UserUID string `gorm:"type:VARBINARY(42);column:user_uid;uniqueIndex;" json:"UID" yaml:"UID"`
|
||||
AuthProvider string `gorm:"type:VARBINARY(128);default:'';" json:"AuthProvider" yaml:"AuthProvider,omitempty"`
|
||||
AuthMethod string `gorm:"type:VARBINARY(128);default:'';" json:"AuthMethod" yaml:"AuthMethod,omitempty"`
|
||||
AuthID string `gorm:"type:VARBINARY(255);index;default:'';" json:"AuthID" yaml:"AuthID,omitempty"`
|
||||
|
|
@ -70,8 +70,8 @@ type User struct {
|
|||
VerifiedAt *time.Time `json:"VerifiedAt,omitempty" yaml:"VerifiedAt,omitempty"`
|
||||
ConsentAt *time.Time `json:"ConsentAt,omitempty" yaml:"ConsentAt,omitempty"`
|
||||
BornAt *time.Time `sql:"index" json:"BornAt,omitempty" yaml:"BornAt,omitempty"`
|
||||
UserDetails *UserDetails `gorm:"PRELOAD:true;foreignkey:UserUID;association_foreignkey:UserUID;" json:"Details,omitempty" yaml:"Details,omitempty"`
|
||||
UserSettings *UserSettings `gorm:"PRELOAD:true;foreignkey:UserUID;association_foreignkey:UserUID;" json:"Settings,omitempty" yaml:"Settings,omitempty"`
|
||||
UserDetails *UserDetails `gorm:"foreignKey:UserUID;references:UserUID;" json:"Details,omitempty" yaml:"Details,omitempty"`
|
||||
UserSettings *UserSettings `gorm:"foreignKey:UserUID;references:UserUID" json:"Settings,omitempty" yaml:"Settings,omitempty"`
|
||||
UserShares UserShares `gorm:"-" json:"Shares,omitempty" yaml:"Shares,omitempty"`
|
||||
ResetToken string `gorm:"type:VARBINARY(64);" json:"-" yaml:"-"`
|
||||
PreviewToken string `gorm:"type:VARBINARY(64);column:preview_token;" json:"-" yaml:"-"`
|
||||
|
|
@ -338,7 +338,7 @@ func (m *User) Updates(values interface{}) error {
|
|||
}
|
||||
|
||||
// BeforeCreate sets a random UID if needed before inserting a new row to the database.
|
||||
func (m *User) BeforeCreate(scope *gorm.Scope) error {
|
||||
func (m *User) BeforeCreate(db *gorm.DB) (err error) {
|
||||
if m.UserSettings != nil {
|
||||
m.UserSettings.UserUID = m.UserUID
|
||||
}
|
||||
|
|
@ -351,7 +351,6 @@ func (m *User) BeforeCreate(scope *gorm.Scope) error {
|
|||
|
||||
if rnd.InvalidRefID(m.RefID) {
|
||||
m.RefID = rnd.RefID(UserPrefix)
|
||||
Log("user", "set ref id", scope.SetColumn("RefID", m.RefID))
|
||||
}
|
||||
|
||||
if rnd.IsUnique(m.UserUID, UserUID) {
|
||||
|
|
@ -359,7 +358,8 @@ func (m *User) BeforeCreate(scope *gorm.Scope) error {
|
|||
}
|
||||
|
||||
m.UserUID = rnd.GenerateUID(UserUID)
|
||||
return scope.SetColumn("UserUID", m.UserUID)
|
||||
db.Statement.SetColumn("UserUID", m.UserUID)
|
||||
return db.Error
|
||||
}
|
||||
|
||||
// IsExpired checks if the user account has expired.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package entity
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/form"
|
||||
"github.com/photoprism/photoprism/pkg/clean"
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ const (
|
|||
|
||||
// UserDetails represents user profile information.
|
||||
type UserDetails struct {
|
||||
UserUID string `gorm:"type:VARBINARY(42);primary_key;auto_increment:false;" json:"-" yaml:"-"`
|
||||
UserUID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false;" json:"-" yaml:"-"`
|
||||
SubjUID string `gorm:"type:VARBINARY(42);index;" json:"SubjUID,omitempty" yaml:"SubjUID,omitempty"`
|
||||
SubjSrc string `gorm:"type:VARBINARY(8);default:'';" json:"-" yaml:"SubjSrc,omitempty"`
|
||||
PlaceID string `gorm:"type:VARBINARY(42);index;default:'zz'" json:"-" yaml:"-"`
|
||||
|
|
|
|||
|
|
@ -15,12 +15,12 @@ func TestFindLegacyUser(t *testing.T) {
|
|||
|
||||
// t.Logf("Legacy Admin: %#v", notFound)
|
||||
|
||||
if err := Db().AutoMigrate(legacy.User{}).Error; err != nil {
|
||||
if err := Db().AutoMigrate(legacy.User{}); err != nil {
|
||||
log.Debugf("TestFindLegacyUser: %s (waiting 1s)", err.Error())
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
if err = Db().AutoMigrate(legacy.User{}).Error; err != nil {
|
||||
if err = Db().AutoMigrate(legacy.User{}); err != nil {
|
||||
log.Errorf("TestFindLegacyUser: failed migrating legacy.User")
|
||||
t.Error(err)
|
||||
}
|
||||
|
|
@ -33,7 +33,7 @@ func TestFindLegacyUser(t *testing.T) {
|
|||
|
||||
// t.Logf("Legacy Admin: %#v", found)
|
||||
|
||||
if err := Db().DropTable(legacy.User{}).Error; err != nil {
|
||||
if err := Db().Migrator().DropTable(legacy.User{}); err != nil {
|
||||
log.Errorf("TestFindLegacyUser: failed dropping legacy.User")
|
||||
t.Error(err)
|
||||
}
|
||||
|
|
@ -45,12 +45,12 @@ func TestFindLegacyUsers(t *testing.T) {
|
|||
|
||||
// t.Logf("Legacy Users: %#v", notFound)
|
||||
|
||||
if err := Db().AutoMigrate(legacy.User{}).Error; err != nil {
|
||||
if err := Db().AutoMigrate(legacy.User{}); err != nil {
|
||||
log.Debugf("TestFindLegacyUser: %s (waiting 1s)", err.Error())
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
if err = Db().AutoMigrate(legacy.User{}).Error; err != nil {
|
||||
if err = Db().AutoMigrate(legacy.User{}); err != nil {
|
||||
log.Errorf("TestFindLegacyUser: failed migrating legacy.User")
|
||||
t.Error(err)
|
||||
}
|
||||
|
|
@ -65,7 +65,7 @@ func TestFindLegacyUsers(t *testing.T) {
|
|||
|
||||
// t.Logf("Legacy Users: %#v", found)
|
||||
|
||||
if err := Db().DropTable(legacy.User{}).Error; err != nil {
|
||||
if err := Db().Migrator().DropTable(legacy.User{}); err != nil {
|
||||
log.Errorf("TestFindLegacyUser: failed dropping legacy.User")
|
||||
t.Error(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import (
|
|||
|
||||
// UserSettings represents user preferences.
|
||||
type UserSettings struct {
|
||||
UserUID string `gorm:"type:VARBINARY(42);primary_key;auto_increment:false;" json:"-" yaml:"UserUID"`
|
||||
UserUID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false" json:"-" yaml:"UserUID"`
|
||||
UITheme string `gorm:"type:VARBINARY(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"`
|
||||
UITimeZone string `gorm:"type:VARBINARY(64);column:ui_time_zone;" json:"UITimeZone,omitempty" yaml:"UITimeZone,omitempty"`
|
||||
|
|
@ -49,7 +49,9 @@ func CreateUserSettings(user *User) error {
|
|||
return fmt.Errorf("empty user uid")
|
||||
}
|
||||
|
||||
user.UserSettings = &UserSettings{}
|
||||
user.UserSettings = &UserSettings{
|
||||
UserUID: user.UserUID,
|
||||
}
|
||||
|
||||
if err := Db().Where("user_uid = ?", user.UID()).First(user.UserSettings).Error; err == nil {
|
||||
return nil
|
||||
|
|
@ -70,6 +72,9 @@ func (m *UserSettings) Create() error {
|
|||
|
||||
// Save updates the record in the database or inserts a new record if it does not already exist.
|
||||
func (m *UserSettings) Save() error {
|
||||
if m.UserUID == "" {
|
||||
return fmt.Errorf("Cannot save user settings without UserUID")
|
||||
}
|
||||
return Db().Save(m).Error
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -63,8 +63,8 @@ func (m UserShares) Contains(uid string) bool {
|
|||
|
||||
// UserShare represents content shared with a user.
|
||||
type UserShare struct {
|
||||
UserUID string `gorm:"type:VARBINARY(42);primary_key;auto_increment:false;" json:"-" yaml:"UserUID"`
|
||||
ShareUID string `gorm:"type:VARBINARY(42);primary_key;index;" json:"ShareUID" yaml:"ShareUID"`
|
||||
UserUID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false;" json:"-" yaml:"UserUID"`
|
||||
ShareUID string `gorm:"type:VARBINARY(42);primaryKey;index;" json:"ShareUID" yaml:"ShareUID"`
|
||||
LinkUID string `gorm:"type:VARBINARY(42);" json:"LinkUID,omitempty" yaml:"LinkUID,omitempty"`
|
||||
ExpiresAt *time.Time `sql:"index" json:"ExpiresAt,omitempty" yaml:"ExpiresAt,omitempty"`
|
||||
Comment string `gorm:"size:512;" json:"Comment,omitempty" yaml:"Comment,omitempty"`
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ type Cameras []Camera
|
|||
|
||||
// Camera model and make (as extracted from UpdateExif metadata)
|
||||
type Camera struct {
|
||||
ID uint `gorm:"primary_key" json:"ID" yaml:"ID"`
|
||||
CameraSlug string `gorm:"type:VARBINARY(160);unique_index;" json:"Slug" yaml:"-"`
|
||||
ID uint `gorm:"primaryKey" json:"ID" yaml:"ID"`
|
||||
CameraSlug string `gorm:"type:VARBINARY(160);uniqueIndex;" json:"Slug" yaml:"-"`
|
||||
CameraName string `gorm:"type:VARCHAR(160);" json:"Name" yaml:"Name"`
|
||||
CameraMake string `gorm:"type:VARCHAR(160);" json:"Make" yaml:"Make,omitempty"`
|
||||
CameraModel string `gorm:"type:VARCHAR(160);" json:"Model" yaml:"Model,omitempty"`
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ package entity
|
|||
|
||||
// Category of labels regroups labels with the same or a similar meaning using a main/root label
|
||||
type Category struct {
|
||||
LabelID uint `gorm:"primary_key;auto_increment:false"`
|
||||
CategoryID uint `gorm:"primary_key;auto_increment:false"`
|
||||
Label *Label
|
||||
Category *Label
|
||||
LabelID uint `gorm:"primaryKey;autoIncrement:false"`
|
||||
CategoryID uint `gorm:"primaryKey;autoIncrement:false"`
|
||||
Label *Label `gorm:"foreignKey:LabelID"`
|
||||
Category *Label `gorm:"foreignKey:CategoryID"`
|
||||
}
|
||||
|
||||
// TableName returns the entity table name.
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ var cellMutex = sync.Mutex{}
|
|||
|
||||
// Cell represents an S2 cell with metadata and reference to a place.
|
||||
type Cell struct {
|
||||
ID string `gorm:"type:VARBINARY(42);primary_key;auto_increment:false;" json:"ID" yaml:"ID"`
|
||||
ID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false;" json:"ID" yaml:"ID"`
|
||||
CellName string `gorm:"type:VARCHAR(200);" json:"Name" yaml:"Name,omitempty"`
|
||||
CellStreet string `gorm:"type:VARCHAR(100);" json:"Street" yaml:"Street,omitempty"`
|
||||
CellPostcode string `gorm:"type:VARCHAR(50);" json:"Postcode" yaml:"Postcode,omitempty"`
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
package entity
|
||||
|
||||
import (
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/photoprism/photoprism/internal/event"
|
||||
"github.com/photoprism/photoprism/internal/maps"
|
||||
"github.com/photoprism/photoprism/pkg/txt"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// altCountryNames defines mapping between different names for the same country
|
||||
|
|
@ -19,8 +19,8 @@ type Countries []Country
|
|||
|
||||
// Country represents a country location, used for labeling photos.
|
||||
type Country struct {
|
||||
ID string `gorm:"type:VARBINARY(2);primary_key" json:"ID" yaml:"ID"`
|
||||
CountrySlug string `gorm:"type:VARBINARY(160);unique_index;" json:"Slug" yaml:"-"`
|
||||
ID string `gorm:"type:VARBINARY(2);primaryKey" json:"ID" yaml:"ID"`
|
||||
CountrySlug string `gorm:"type:VARBINARY(160);uniqueIndex;" json:"Slug" yaml:"-"`
|
||||
CountryName string `gorm:"type:VARCHAR(160);" json:"Name" yaml:"Name,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"`
|
||||
|
|
@ -104,7 +104,7 @@ func FirstOrCreateCountry(m *Country) *Country {
|
|||
}
|
||||
|
||||
// AfterCreate sets the New column used for database callback
|
||||
func (m *Country) AfterCreate(scope *gorm.Scope) error {
|
||||
func (m *Country) AfterCreate(scope *gorm.DB) error {
|
||||
m.New = true
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,9 @@
|
|||
package entity
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Set UTC as the default for created and updated timestamps.
|
||||
func init() {
|
||||
gorm.NowFunc = func() time.Time {
|
||||
return UTC()
|
||||
}
|
||||
}
|
||||
|
||||
// Db returns the default *gorm.DB connection.
|
||||
func Db() *gorm.DB {
|
||||
if dbConn == nil {
|
||||
|
|
|
|||
|
|
@ -5,19 +5,25 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
_ "github.com/jinzhu/gorm/dialects/mysql"
|
||||
_ "github.com/jinzhu/gorm/dialects/sqlite"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
)
|
||||
|
||||
// Supported test databases.
|
||||
const (
|
||||
MySQL = "mysql"
|
||||
SQLite3 = "sqlite3"
|
||||
SQLite3 = "sqlite"
|
||||
SQLiteTestDB = ".test.db"
|
||||
SQLiteMemoryDSN = ":memory:?cache=shared"
|
||||
)
|
||||
|
||||
var drivers = map[string]func(string) gorm.Dialector{
|
||||
MySQL: mysql.Open,
|
||||
SQLite3: sqlite.Open,
|
||||
}
|
||||
|
||||
// dbConn is the global gorm.DB connection provider.
|
||||
var dbConn Gorm
|
||||
|
||||
|
|
@ -48,12 +54,14 @@ func (g *DbConn) Db() *gorm.DB {
|
|||
|
||||
// Open creates a new gorm db connection.
|
||||
func (g *DbConn) Open() {
|
||||
db, err := gorm.Open(g.Driver, g.Dsn)
|
||||
log.Infof("Opening DB connection with driver %s", g.Driver)
|
||||
db, err := gorm.Open(drivers[g.Driver](g.Dsn), gormConfig())
|
||||
log.Info("DB connection established successfully")
|
||||
|
||||
if err != nil || db == nil {
|
||||
for i := 1; i <= 12; i++ {
|
||||
fmt.Printf("gorm.Open(%s, %s) %d\n", g.Driver, g.Dsn, i)
|
||||
db, err = gorm.Open(g.Driver, g.Dsn)
|
||||
db, err = gorm.Open(drivers[g.Driver](g.Dsn), gormConfig())
|
||||
|
||||
if db != nil && err == nil {
|
||||
break
|
||||
|
|
@ -68,10 +76,10 @@ func (g *DbConn) Open() {
|
|||
}
|
||||
}
|
||||
|
||||
db.LogMode(false)
|
||||
db.SetLogger(log)
|
||||
db.DB().SetMaxIdleConns(4)
|
||||
db.DB().SetMaxOpenConns(256)
|
||||
sqlDB, err := db.DB()
|
||||
|
||||
sqlDB.SetMaxIdleConns(4)
|
||||
sqlDB.SetMaxOpenConns(256)
|
||||
|
||||
g.db = db
|
||||
}
|
||||
|
|
@ -79,7 +87,8 @@ func (g *DbConn) Open() {
|
|||
// Close closes the gorm db connection.
|
||||
func (g *DbConn) Close() {
|
||||
if g.db != nil {
|
||||
if err := g.db.Close(); err != nil {
|
||||
sqlDB, _ := g.db.DB()
|
||||
if err := sqlDB.Close(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
|
|
@ -89,12 +98,12 @@ func (g *DbConn) Close() {
|
|||
|
||||
// IsDialect returns true if the given sql dialect is used.
|
||||
func IsDialect(name string) bool {
|
||||
return name == Db().Dialect().GetName()
|
||||
return name == Db().Dialector.Name()
|
||||
}
|
||||
|
||||
// DbDialect returns the sql dialect name.
|
||||
func DbDialect() string {
|
||||
return Db().Dialect().GetName()
|
||||
return Db().Dialector.Name()
|
||||
}
|
||||
|
||||
// SetDbProvider sets the Gorm database connection provider.
|
||||
|
|
@ -106,3 +115,22 @@ func SetDbProvider(conn Gorm) {
|
|||
func HasDbProvider() bool {
|
||||
return dbConn != nil
|
||||
}
|
||||
|
||||
func gormConfig() *gorm.Config {
|
||||
return &gorm.Config{
|
||||
Logger: logger.New(
|
||||
log,
|
||||
logger.Config{
|
||||
SlowThreshold: time.Second, // Slow SQL threshold
|
||||
LogLevel: logger.Error, // Log level
|
||||
IgnoreRecordNotFoundError: true, // Ignore ErrRecordNotFound error for logger
|
||||
ParameterizedQueries: false, // Don't include params in the SQL log
|
||||
Colorful: false, // Disable color
|
||||
},
|
||||
),
|
||||
// Set UTC as the default for created and updated timestamps.
|
||||
NowFunc: func() time.Time {
|
||||
return UTC()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import (
|
|||
|
||||
// TestEntity is an entity dedicated to test database management functionality.
|
||||
type TestEntity struct {
|
||||
ID string `gorm:"type:VARBINARY(42);primary_key;auto_increment:false;" json:"TestID" yaml:"TestID"`
|
||||
TestLabel string `gorm:"type:VARCHAR(400);unique_index;" json:"Label" yaml:"Label"`
|
||||
ID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false;" json:"TestID" yaml:"TestID"`
|
||||
TestLabel string `gorm:"type:VARCHAR(400);uniqueIndex;" json:"Label" yaml:"Label"`
|
||||
TestCount int `gorm:"default:1" json:"Count" yaml:"-"`
|
||||
CreatedAt time.Time `json:"CreatedAt" yaml:"-"`
|
||||
UpdatedAt time.Time `json:"UpdatedAt" yaml:"-"`
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package entity
|
||||
|
||||
import "github.com/jinzhu/gorm"
|
||||
import "gorm.io/gorm"
|
||||
|
||||
// Deprecated represents a list of deprecated database tables.
|
||||
type Deprecated []string
|
||||
|
|
@ -8,7 +8,7 @@ type Deprecated []string
|
|||
// Drop drops all deprecated tables.
|
||||
func (list Deprecated) Drop(db *gorm.DB) {
|
||||
for _, tableName := range list {
|
||||
if err := db.DropTableIfExists(tableName).Error; err != nil {
|
||||
if err := db.Migrator().DropTable(tableName); err != nil {
|
||||
log.Debugf("drop %s: %s", tableName, err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ var photoDetailsMutex = sync.Mutex{}
|
|||
|
||||
// Details stores additional metadata fields for each photo to improve search performance.
|
||||
type Details struct {
|
||||
PhotoID uint `gorm:"primary_key;auto_increment:false" yaml:"-"`
|
||||
PhotoID uint `gorm:"primaryKey;autoIncrement:false" yaml:"-"`
|
||||
Keywords string `gorm:"type:VARCHAR(2048);" json:"Keywords" yaml:"Keywords"`
|
||||
KeywordsSrc string `gorm:"type:VARBINARY(8);" json:"KeywordsSrc" yaml:"KeywordsSrc,omitempty"`
|
||||
Notes string `gorm:"type:VARCHAR(2048);" json:"Notes" yaml:"Notes,omitempty"`
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ type DuplicatesMap map[string]Duplicate
|
|||
|
||||
// Duplicate represents an exact file duplicate.
|
||||
type Duplicate struct {
|
||||
FileName string `gorm:"type:VARBINARY(755);primary_key;" json:"Name" yaml:"Name"`
|
||||
FileRoot string `gorm:"type:VARBINARY(16);primary_key;default:'/';" json:"Root" yaml:"Root,omitempty"`
|
||||
FileName string `gorm:"type:VARBINARY(755);primaryKey;" json:"Name" yaml:"Name"`
|
||||
FileRoot string `gorm:"type:VARBINARY(16);primaryKey;default:'/';" json:"Root" yaml:"Root,omitempty"`
|
||||
FileHash string `gorm:"type:VARBINARY(128);default:'';index" json:"Hash" yaml:"Hash,omitempty"`
|
||||
FileSize int64 `json:"Size" yaml:"Size,omitempty"`
|
||||
ModTime int64 `json:"ModTime" yaml:"-"`
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package entity
|
||||
|
||||
import (
|
||||
"github.com/jinzhu/gorm"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Count returns the number of records for a given a model and key values.
|
||||
|
|
@ -11,7 +11,7 @@ func Count(m interface{}, keys []string, values []interface{}) int {
|
|||
return -1
|
||||
}
|
||||
|
||||
db, count := UnscopedDb(), 0
|
||||
db, count := UnscopedDb(), int64(0)
|
||||
|
||||
stmt := db.Model(m)
|
||||
|
||||
|
|
@ -26,5 +26,5 @@ func Count(m interface{}, keys []string, values []interface{}) int {
|
|||
return -1
|
||||
}
|
||||
|
||||
return count
|
||||
return int(count)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/dustin/go-humanize/english"
|
||||
"github.com/jinzhu/gorm"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/mutex"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/migrate"
|
||||
"github.com/photoprism/photoprism/pkg/clean"
|
||||
|
|
@ -123,12 +123,12 @@ func (list Tables) Migrate(db *gorm.DB, opt migrate.Options) {
|
|||
// Run ORM auto migrations.
|
||||
if opt.AutoMigrate {
|
||||
for name, entity = range list {
|
||||
if err := db.AutoMigrate(entity).Error; err != nil {
|
||||
if err := db.AutoMigrate(entity); err != nil {
|
||||
log.Debugf("migrate: %s (waiting 1s)", err.Error())
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
if err = db.AutoMigrate(entity).Error; err != nil {
|
||||
if err = db.AutoMigrate(entity); err != nil {
|
||||
log.Errorf("migrate: failed migrating %s", clean.Log(name))
|
||||
panic(err)
|
||||
}
|
||||
|
|
@ -145,8 +145,9 @@ func (list Tables) Migrate(db *gorm.DB, opt migrate.Options) {
|
|||
// Drop drops all database tables of registered entities.
|
||||
func (list Tables) Drop(db *gorm.DB) {
|
||||
for _, entity := range list {
|
||||
if err := db.DropTableIfExists(entity).Error; err != nil {
|
||||
panic(err)
|
||||
if err := db.Migrator().DropTable(entity); err != nil {
|
||||
// As there is no DropTableIfExists anymore, we just accept and log errors
|
||||
log.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
package entity
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
|
@ -19,8 +19,12 @@ func TestUTC(t *testing.T) {
|
|||
}
|
||||
})
|
||||
t.Run("RunGorm", func(t *testing.T) {
|
||||
db := InitTestDb(
|
||||
os.Getenv("PHOTOPRISM_TEST_DRIVER"),
|
||||
os.Getenv("PHOTOPRISM_TEST_DSN"))
|
||||
|
||||
utc := UTC()
|
||||
utcGorm := gorm.NowFunc()
|
||||
utcGorm := db.db.Config.NowFunc()
|
||||
|
||||
t.Logf("NOW: %s, %s", utc.String(), utcGorm.String())
|
||||
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ func Update(m interface{}, keyNames ...string) (err error) {
|
|||
// Unscoped so soft-deleted records can still be updated.
|
||||
db := UnscopedDb()
|
||||
|
||||
// New entity?
|
||||
if db.NewRecord(m) {
|
||||
return fmt.Errorf("new record")
|
||||
}
|
||||
// We now let this fallthrough and fail in the .Updates() call (no NewRecord() anymore)
|
||||
// if db.NewRecord(m) {
|
||||
// return fmt.Errorf("new record")
|
||||
// }
|
||||
|
||||
// Extract interface slice with all values including zero.
|
||||
values, keys, err := ModelValues(m, keyNames...)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import (
|
|||
)
|
||||
|
||||
// Map is an alias for map[string]interface{}.
|
||||
type Map map[string]interface{}
|
||||
type Map = map[string]interface{}
|
||||
|
||||
// ModelValues extracts Values from an entity model.
|
||||
func ModelValues(m interface{}, omit ...string) (result Map, omitted []interface{}, err error) {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import (
|
|||
|
||||
// Error represents an error message log.
|
||||
type Error struct {
|
||||
ID uint `gorm:"primary_key" json:"ID" yaml:"ID"`
|
||||
ID uint `gorm:"primaryKey" json:"ID" yaml:"ID"`
|
||||
ErrorTime time.Time `sql:"index" json:"Time" yaml:"Time"`
|
||||
ErrorLevel string `gorm:"type:VARBINARY(32)" json:"Level" yaml:"Level"`
|
||||
ErrorMessage string `gorm:"type:VARBINARY(2048)" json:"Message" yaml:"Message"`
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ var UpdateFaces = atomic.Bool{}
|
|||
|
||||
// Face represents the face of a Subject.
|
||||
type Face struct {
|
||||
ID string `gorm:"type:VARBINARY(64);primary_key;auto_increment:false;" json:"ID" yaml:"ID"`
|
||||
ID string `gorm:"type:VARBINARY(64);primaryKey;autoIncrement:false;" json:"ID" yaml:"ID"`
|
||||
FaceSrc string `gorm:"type:VARBINARY(8);" json:"Src" yaml:"Src,omitempty"`
|
||||
FaceKind int `json:"Kind" yaml:"Kind,omitempty"`
|
||||
FaceHidden bool `json:"Hidden" yaml:"Hidden,omitempty"`
|
||||
|
|
@ -432,7 +432,7 @@ func FindFace(id string) *Face {
|
|||
}
|
||||
|
||||
// ValidFaceCount counts the number of valid face markers for a file uid.
|
||||
func ValidFaceCount(fileUid string) (c int) {
|
||||
func ValidFaceCount(fileUid string) (c int64) {
|
||||
if !rnd.IsUID(fileUid, FileUID) {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,8 +11,9 @@ import (
|
|||
|
||||
"github.com/dustin/go-humanize/english"
|
||||
"github.com/gosimple/slug"
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/ulule/deepcopier"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/customize"
|
||||
"github.com/photoprism/photoprism/internal/face"
|
||||
|
|
@ -38,7 +39,7 @@ var filePrimaryMutex = sync.Mutex{}
|
|||
|
||||
// File represents an image or sidecar file that belongs to a photo.
|
||||
type File struct {
|
||||
ID uint `gorm:"primary_key" json:"-" yaml:"-"`
|
||||
ID uint `gorm:"primaryKey" json:"-" yaml:"-"`
|
||||
Photo *Photo `json:"-" yaml:"-"`
|
||||
PhotoID uint `gorm:"index:idx_files_photo_id;" json:"-" yaml:"-"`
|
||||
PhotoUID string `gorm:"type:VARBINARY(42);index;" json:"PhotoUID" yaml:"PhotoUID"`
|
||||
|
|
@ -47,9 +48,9 @@ type File struct {
|
|||
MediaID *string `gorm:"type:VARBINARY(32);" json:"MediaID" yaml:"MediaID"`
|
||||
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"`
|
||||
FileUID string `gorm:"type:VARBINARY(42);unique_index;" json:"UID" yaml:"UID"`
|
||||
FileName string `gorm:"type:VARBINARY(1024);unique_index:idx_files_name_root;" json:"Name" yaml:"Name"`
|
||||
FileRoot string `gorm:"type:VARBINARY(16);default:'/';unique_index:idx_files_name_root;" json:"Root" yaml:"Root,omitempty"`
|
||||
FileUID string `gorm:"type:VARBINARY(42);uniqueIndex;" json:"UID" yaml:"UID"`
|
||||
FileName string `gorm:"type:VARBINARY(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"`
|
||||
OriginalName string `gorm:"type:VARBINARY(755);" json:"OriginalName" yaml:"OriginalName,omitempty"`
|
||||
FileHash string `gorm:"type:VARBINARY(128);index" json:"Hash" yaml:"Hash,omitempty"`
|
||||
FileSize int64 `json:"Size" yaml:"Size,omitempty"`
|
||||
|
|
@ -107,7 +108,7 @@ func (m File) RegenerateIndex() {
|
|||
|
||||
photosTable := Photo{}.TableName()
|
||||
|
||||
var updateWhere *gorm.SqlExpr
|
||||
var updateWhere clause.Expr
|
||||
var scope string
|
||||
|
||||
if m.PhotoID > 0 {
|
||||
|
|
@ -175,7 +176,7 @@ func PrimaryFile(photoUid string) (*File, error) {
|
|||
}
|
||||
|
||||
// BeforeCreate creates a random UID if needed before inserting a new row to the database.
|
||||
func (m *File) BeforeCreate(scope *gorm.Scope) error {
|
||||
func (m *File) BeforeCreate(scope *gorm.DB) error {
|
||||
// Set MediaType based on FileName if empty.
|
||||
if m.MediaType == "" && m.FileName != "" {
|
||||
m.MediaType = media.FromName(m.FileName).String()
|
||||
|
|
@ -191,7 +192,9 @@ func (m *File) BeforeCreate(scope *gorm.Scope) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
return scope.SetColumn("FileUID", rnd.GenerateUID(FileUID))
|
||||
m.FileUID = rnd.GenerateUID(FileUID)
|
||||
scope.Statement.SetColumn("FileUID", m.FileUID)
|
||||
return scope.Error
|
||||
}
|
||||
|
||||
// DownloadName returns the download file name.
|
||||
|
|
@ -378,7 +381,7 @@ func (m *File) Found() error {
|
|||
|
||||
// AllFilesMissing returns true, if all files for the photo of this file are missing.
|
||||
func (m *File) AllFilesMissing() bool {
|
||||
count := 0
|
||||
count := int64(0)
|
||||
|
||||
if err := Db().Model(&File{}).
|
||||
Where("photo_id = ? AND file_missing = 0", m.PhotoID).
|
||||
|
|
@ -548,7 +551,7 @@ func (m *File) RelatedPhoto() *Photo {
|
|||
|
||||
photo := Photo{}
|
||||
|
||||
UnscopedDb().Model(m).Related(&photo)
|
||||
UnscopedDb().Model(m).Find(&photo)
|
||||
|
||||
return &photo
|
||||
}
|
||||
|
|
@ -766,7 +769,7 @@ func (m *File) AddFace(f face.Face, subjUid string) {
|
|||
|
||||
// ValidFaceCount returns the number of valid face markers.
|
||||
func (m *File) ValidFaceCount() (c int) {
|
||||
return ValidFaceCount(m.FileUID)
|
||||
return int(ValidFaceCount(m.FileUID))
|
||||
}
|
||||
|
||||
// UpdatePhotoFaceCount updates the faces count in the index and returns it if the file is primary.
|
||||
|
|
|
|||
|
|
@ -13,14 +13,14 @@ const (
|
|||
|
||||
// FileShare represents a one-to-many relation between File and Account for pushing files to remote services.
|
||||
type FileShare struct {
|
||||
FileID uint `gorm:"primary_key;auto_increment:false"`
|
||||
ServiceID uint `gorm:"primary_key;auto_increment:false"`
|
||||
RemoteName string `gorm:"primary_key;auto_increment:false;type:VARBINARY(255)"`
|
||||
FileID uint `gorm:"primaryKey;autoIncrement:false"`
|
||||
ServiceID uint `gorm:"primaryKey;autoIncrement:false"`
|
||||
RemoteName string `gorm:"primaryKey;autoIncrement:false;type:VARBINARY(255)"`
|
||||
Status string `gorm:"type:VARBINARY(16);"`
|
||||
Error string `gorm:"type:VARBINARY(512);"`
|
||||
Errors int
|
||||
File *File
|
||||
Account *Service
|
||||
Account *Service `gorm:"foreignKey:ServiceID"`
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,16 +14,16 @@ const (
|
|||
|
||||
// FileSync represents a one-to-many relation between File and Account for syncing with remote services.
|
||||
type FileSync struct {
|
||||
RemoteName string `gorm:"primary_key;auto_increment:false;type:VARBINARY(255)"`
|
||||
ServiceID uint `gorm:"primary_key;auto_increment:false"`
|
||||
RemoteName string `gorm:"primaryKey;autoIncrement:false;type:VARBINARY(255)"`
|
||||
ServiceID uint `gorm:"primaryKey;autoIncrement:false"`
|
||||
FileID uint `gorm:"index;"`
|
||||
RemoteDate time.Time
|
||||
RemoteSize int64
|
||||
Status string `gorm:"type:VARBINARY(16);"`
|
||||
Error string `gorm:"type:VARBINARY(512);"`
|
||||
Errors int
|
||||
File *File
|
||||
Account *Service
|
||||
File *File `gorm:"foreignKey:FileID"`
|
||||
Account *Service `gorm:"foreignKey:ServiceID"`
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package entity
|
|||
// CreateTestFixtures inserts all known entities into the database for testing.
|
||||
func CreateTestFixtures() {
|
||||
if err := Admin.SetPassword("photoprism"); err != nil {
|
||||
log.Error(err)
|
||||
log.Errorf("create fixtures: cannot set admin password: %s", err)
|
||||
}
|
||||
|
||||
CreateLabelFixtures()
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/ulule/deepcopier"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/form"
|
||||
"github.com/photoprism/photoprism/pkg/clean"
|
||||
|
|
@ -23,9 +23,9 @@ type Folders []Folder
|
|||
|
||||
// Folder represents a file system directory.
|
||||
type Folder struct {
|
||||
Path string `gorm:"type:VARBINARY(1024);unique_index:idx_folders_path_root;" json:"Path" yaml:"Path"`
|
||||
Root string `gorm:"type:VARBINARY(16);default:'';unique_index:idx_folders_path_root;" json:"Root" yaml:"Root,omitempty"`
|
||||
FolderUID string `gorm:"type:VARBINARY(42);primary_key;" json:"UID,omitempty" yaml:"UID,omitempty"`
|
||||
Path string `gorm:"type:VARBINARY(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"`
|
||||
FolderUID string `gorm:"type:VARBINARY(42);primaryKey;" json:"UID,omitempty" yaml:"UID,omitempty"`
|
||||
FolderType string `gorm:"type:VARBINARY(16);" json:"Type" yaml:"Type,omitempty"`
|
||||
FolderTitle string `gorm:"type:VARCHAR(200);" json:"Title" yaml:"Title,omitempty"`
|
||||
FolderCategory string `gorm:"type:VARCHAR(100);index;" json:"Category" yaml:"Category,omitempty"`
|
||||
|
|
@ -53,12 +53,14 @@ func (Folder) TableName() string {
|
|||
}
|
||||
|
||||
// BeforeCreate creates a random UID if needed before inserting a new row to the database.
|
||||
func (m *Folder) BeforeCreate(scope *gorm.Scope) error {
|
||||
func (m *Folder) BeforeCreate(scope *gorm.DB) (err error) {
|
||||
if rnd.IsUnique(m.FolderUID, 'd') {
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
return scope.SetColumn("FolderUID", rnd.GenerateUID('d'))
|
||||
m.FolderUID = rnd.GenerateUID('d')
|
||||
scope.Statement.SetColumn("FolderUID", m.FolderUID)
|
||||
return scope.Error
|
||||
}
|
||||
|
||||
// NewFolder creates a new file system directory entity.
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ var keywordMutex = sync.Mutex{}
|
|||
|
||||
// Keyword used for full text search
|
||||
type Keyword struct {
|
||||
ID uint `gorm:"primary_key"`
|
||||
ID uint `gorm:"primaryKey"`
|
||||
Keyword string `gorm:"type:VARCHAR(64);index;"`
|
||||
Skip bool
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,6 +154,6 @@ var KeywordFixtures = KeywordMap{
|
|||
// CreateKeywordFixtures inserts known entities into the database for testing.
|
||||
func CreateKeywordFixtures() {
|
||||
for _, entity := range KeywordFixtures {
|
||||
Db().Create(&entity)
|
||||
Db().Save(&entity)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/classify"
|
||||
"github.com/photoprism/photoprism/internal/event"
|
||||
|
|
@ -25,16 +25,16 @@ type Labels []Label
|
|||
|
||||
// Label is used for photo, album and location categorization
|
||||
type Label struct {
|
||||
ID uint `gorm:"primary_key" json:"ID" yaml:"-"`
|
||||
LabelUID string `gorm:"type:VARBINARY(42);unique_index;" json:"UID" yaml:"UID"`
|
||||
LabelSlug string `gorm:"type:VARBINARY(160);unique_index;" json:"Slug" yaml:"-"`
|
||||
ID uint `gorm:"primaryKey" json:"ID" yaml:"-"`
|
||||
LabelUID string `gorm:"type:VARBINARY(42);uniqueIndex;" json:"UID" yaml:"UID"`
|
||||
LabelSlug string `gorm:"type:VARBINARY(160);uniqueIndex;" json:"Slug" yaml:"-"`
|
||||
CustomSlug string `gorm:"type:VARBINARY(160);index;" json:"CustomSlug" yaml:"-"`
|
||||
LabelName string `gorm:"type:VARCHAR(160);" json:"Name" yaml:"Name"`
|
||||
LabelPriority int `json:"Priority" yaml:"Priority,omitempty"`
|
||||
LabelFavorite bool `json:"Favorite" yaml:"Favorite,omitempty"`
|
||||
LabelDescription string `gorm:"type:VARCHAR(2048);" json:"Description" yaml:"Description,omitempty"`
|
||||
LabelNotes string `gorm:"type:VARCHAR(1024);" json:"Notes" yaml:"Notes,omitempty"`
|
||||
LabelCategories []*Label `gorm:"many2many:categories;association_jointable_foreignkey:category_id" json:"-" yaml:"-"`
|
||||
LabelCategories []*Label `gorm:"many2many:categories;joinForeignKey:category_id" json:"-" yaml:"-"`
|
||||
PhotoCount int `gorm:"default:1" json:"PhotoCount" yaml:"-"`
|
||||
Thumb string `gorm:"type:VARBINARY(128);index;default:''" json:"Thumb" yaml:"Thumb,omitempty"`
|
||||
ThumbSrc string `gorm:"type:VARBINARY(8);default:''" json:"ThumbSrc,omitempty" yaml:"ThumbSrc,omitempty"`
|
||||
|
|
@ -51,12 +51,14 @@ func (Label) TableName() string {
|
|||
}
|
||||
|
||||
// BeforeCreate creates a random UID if needed before inserting a new row to the database.
|
||||
func (m *Label) BeforeCreate(scope *gorm.Scope) error {
|
||||
func (m *Label) BeforeCreate(scope *gorm.DB) error {
|
||||
if rnd.IsUnique(m.LabelUID, LabelUID) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return scope.SetColumn("LabelUID", rnd.GenerateUID(LabelUID))
|
||||
m.LabelUID = rnd.GenerateUID(LabelUID)
|
||||
scope.Statement.SetColumn("LabelUID", m.LabelUID)
|
||||
return scope.Error
|
||||
}
|
||||
|
||||
// NewLabel returns a new label.
|
||||
|
|
@ -166,7 +168,7 @@ func FindLabel(s string) *Label {
|
|||
}
|
||||
|
||||
// AfterCreate sets the New column used for database callback
|
||||
func (m *Label) AfterCreate(scope *gorm.Scope) error {
|
||||
func (m *Label) AfterCreate(scope *gorm.DB) error {
|
||||
m.New = true
|
||||
return nil
|
||||
}
|
||||
|
|
@ -229,7 +231,7 @@ func (m *Label) UpdateClassify(label classify.Label) error {
|
|||
continue
|
||||
}
|
||||
|
||||
if err := db.Model(m).Association("LabelCategories").Append(sn).Error; err != nil {
|
||||
if err := db.Model(m).Association("LabelCategories").Append(sn); err != nil {
|
||||
log.Debugf("index: failed saving label category %s (%s)", clean.Log(category), err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ type Users []User
|
|||
|
||||
// User represents a person that may optionally log in as user.
|
||||
type User struct {
|
||||
ID int `gorm:"primary_key" json:"-" yaml:"-"`
|
||||
ID int `gorm:"primaryKey" json:"-" yaml:"-"`
|
||||
AddressID int `gorm:"default:1" json:"-" yaml:"-"`
|
||||
UserUID string `gorm:"type:VARBINARY(42);unique_index;" json:"UID" yaml:"UID"`
|
||||
UserUID string `gorm:"type:VARBINARY(42);uniqueIndex;" json:"UID" yaml:"UID"`
|
||||
MotherUID string `gorm:"type:VARBINARY(42);" json:"MotherUID" yaml:"MotherUID,omitempty"`
|
||||
FatherUID string `gorm:"type:VARBINARY(42);" json:"FatherUID" yaml:"FatherUID,omitempty"`
|
||||
GlobalUID string `gorm:"type:VARBINARY(42);index;" json:"GlobalUID" yaml:"GlobalUID,omitempty"`
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ type Lenses []Lens
|
|||
|
||||
// Lens represents camera lens (as extracted from UpdateExif metadata)
|
||||
type Lens struct {
|
||||
ID uint `gorm:"primary_key" json:"ID" yaml:"ID"`
|
||||
LensSlug string `gorm:"type:VARBINARY(160);unique_index;" json:"Slug" yaml:"Slug,omitempty"`
|
||||
ID uint `gorm:"primaryKey" json:"ID" yaml:"ID"`
|
||||
LensSlug string `gorm:"type:VARBINARY(160);uniqueIndex;" json:"Slug" yaml:"Slug,omitempty"`
|
||||
LensName string `gorm:"type:VARCHAR(160);" json:"Name" yaml:"Name"`
|
||||
LensMake string `gorm:"type:VARCHAR(160);" json:"Make" yaml:"Make,omitempty"`
|
||||
LensModel string `gorm:"type:VARCHAR(160);" json:"Model" yaml:"Model,omitempty"`
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/event"
|
||||
"github.com/photoprism/photoprism/pkg/clean"
|
||||
|
|
@ -22,10 +22,10 @@ type Links []Link
|
|||
|
||||
// Link represents a link to share content.
|
||||
type Link struct {
|
||||
LinkUID string `gorm:"type:VARBINARY(42);primary_key;" json:"UID,omitempty" yaml:"UID,omitempty"`
|
||||
ShareUID string `gorm:"type:VARBINARY(42);unique_index:idx_links_uid_token;" json:"ShareUID" yaml:"ShareUID"`
|
||||
LinkUID string `gorm:"type:VARBINARY(42);primaryKey;" json:"UID,omitempty" yaml:"UID,omitempty"`
|
||||
ShareUID string `gorm:"type:VARBINARY(42);uniqueIndex:idx_links_uid_token;" json:"ShareUID" yaml:"ShareUID"`
|
||||
ShareSlug string `gorm:"type:VARBINARY(160);index;" json:"Slug" yaml:"Slug,omitempty"`
|
||||
LinkToken string `gorm:"type:VARBINARY(160);unique_index:idx_links_uid_token;" json:"Token" yaml:"Token,omitempty"`
|
||||
LinkToken string `gorm:"type:VARBINARY(160);uniqueIndex:idx_links_uid_token;" json:"Token" yaml:"Token,omitempty"`
|
||||
LinkExpires int `json:"Expires" yaml:"Expires,omitempty"`
|
||||
LinkViews uint `json:"Views" yaml:"-"`
|
||||
MaxViews uint `json:"MaxViews" yaml:"-"`
|
||||
|
|
@ -44,17 +44,18 @@ func (Link) TableName() string {
|
|||
}
|
||||
|
||||
// BeforeCreate creates a random UID if needed before inserting a new row to the database.
|
||||
func (m *Link) BeforeCreate(scope *gorm.Scope) error {
|
||||
func (m *Link) BeforeCreate(scope *gorm.DB) error {
|
||||
if rnd.InvalidRefID(m.RefID) {
|
||||
m.RefID = rnd.RefID(LinkPrefix)
|
||||
Log("link", "set ref id", scope.SetColumn("RefID", m.RefID))
|
||||
}
|
||||
|
||||
if rnd.IsUnique(m.LinkUID, LinkUID) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return scope.SetColumn("LinkUID", rnd.GenerateUID(LinkUID))
|
||||
m.LinkUID = rnd.GenerateUID(LinkUID)
|
||||
scope.Statement.SetColumn("LinkUID", m.LinkUID)
|
||||
return scope.Error
|
||||
}
|
||||
|
||||
// NewLink creates a sharing link.
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/dustin/go-humanize/english"
|
||||
"github.com/jinzhu/gorm"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/crop"
|
||||
"github.com/photoprism/photoprism/internal/face"
|
||||
|
|
@ -25,7 +25,7 @@ const (
|
|||
|
||||
// Marker represents an image marker point.
|
||||
type Marker struct {
|
||||
MarkerUID string `gorm:"type:VARBINARY(42);primary_key;auto_increment:false;" json:"UID" yaml:"UID"`
|
||||
MarkerUID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false;" json:"UID" yaml:"UID"`
|
||||
FileUID string `gorm:"type:VARBINARY(42);index;default:'';" json:"FileUID" yaml:"FileUID"`
|
||||
MarkerType string `gorm:"type:VARBINARY(8);default:'';" json:"Type" yaml:"Type"`
|
||||
MarkerSrc string `gorm:"type:VARBINARY(8);default:'';" json:"Src" yaml:"Src,omitempty"`
|
||||
|
|
@ -34,10 +34,10 @@ type Marker struct {
|
|||
MarkerInvalid bool `json:"Invalid" yaml:"Invalid,omitempty"`
|
||||
SubjUID string `gorm:"type:VARBINARY(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"`
|
||||
subject *Subject `gorm:"foreignkey:SubjUID;association_foreignkey:SubjUID;association_autoupdate:false;association_autocreate:false;association_save_reference:false"`
|
||||
subject *Subject `gorm:"foreignKey:SubjUID;"`
|
||||
FaceID string `gorm:"type:VARBINARY(64);index;" json:"FaceID" yaml:"FaceID,omitempty"`
|
||||
FaceDist float64 `gorm:"default:-1;" json:"FaceDist" yaml:"FaceDist,omitempty"`
|
||||
face *Face `gorm:"foreignkey:FaceID;association_foreignkey:ID;association_autoupdate:false;association_autocreate:false;association_save_reference:false"`
|
||||
face *Face `gorm:"foreignKey:FaceID;"`
|
||||
EmbeddingsJSON json.RawMessage `gorm:"type:MEDIUMBLOB;" json:"-" yaml:"EmbeddingsJSON,omitempty"`
|
||||
embeddings face.Embeddings `gorm:"-" yaml:"-"`
|
||||
LandmarksJSON json.RawMessage `gorm:"type:MEDIUMBLOB;" json:"-" yaml:"LandmarksJSON,omitempty"`
|
||||
|
|
@ -60,12 +60,14 @@ func (Marker) TableName() string {
|
|||
}
|
||||
|
||||
// BeforeCreate creates a random UID if needed before inserting a new row to the database.
|
||||
func (m *Marker) BeforeCreate(scope *gorm.Scope) error {
|
||||
func (m *Marker) BeforeCreate(scope *gorm.DB) error {
|
||||
if rnd.IsUnique(m.MarkerUID, 'm') {
|
||||
return nil
|
||||
}
|
||||
|
||||
return scope.SetColumn("MarkerUID", rnd.GenerateUID('m'))
|
||||
m.MarkerUID = rnd.GenerateUID('m')
|
||||
scope.Statement.SetColumn("MarkerUID", m.MarkerUID)
|
||||
return scope.Error
|
||||
}
|
||||
|
||||
// NewMarker creates a new entity.
|
||||
|
|
@ -585,7 +587,7 @@ func (m *Marker) RefreshPhotos() error {
|
|||
// Matched updates the match timestamp.
|
||||
func (m *Marker) Matched() error {
|
||||
m.MatchedAt = TimePointer()
|
||||
return UnscopedDb().Model(m).UpdateColumns(Map{"MatchedAt": m.MatchedAt}).Error
|
||||
return UnscopedDb().Model(m).Save(m).Error
|
||||
}
|
||||
|
||||
// Top returns the top Y coordinate as float64.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ import (
|
|||
|
||||
"github.com/photoprism/photoprism/internal/migrate"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func TestMySQL8(t *testing.T) {
|
||||
|
|
@ -17,12 +18,11 @@ func TestMySQL8(t *testing.T) {
|
|||
t.Skip("skipping MySQL 8 test: PHOTOPRISM_TEST_DSN_MYSQL8 is not set")
|
||||
}
|
||||
|
||||
dbDriver := MySQL
|
||||
db, err := gorm.Open(dbDriver, dbDsn)
|
||||
db, err := gorm.Open(mysql.Open(dbDsn))
|
||||
|
||||
if err != nil || db == nil {
|
||||
for i := 1; i <= 5; i++ {
|
||||
db, err = gorm.Open(dbDriver, dbDsn)
|
||||
db, err = gorm.Open(mysql.Open(dbDsn))
|
||||
|
||||
if db != nil && err == nil {
|
||||
break
|
||||
|
|
@ -36,9 +36,8 @@ func TestMySQL8(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
defer db.Close()
|
||||
|
||||
db.LogMode(false)
|
||||
sqldb, _ := db.DB()
|
||||
defer sqldb.Close()
|
||||
|
||||
DeprecatedTables.Drop(db)
|
||||
Entities.Drop(db)
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ import (
|
|||
|
||||
// Passcode represents a two-factor authentication key.
|
||||
type Passcode struct {
|
||||
UID string `gorm:"type:VARBINARY(255);primary_key;" json:"UID"`
|
||||
KeyType string `gorm:"size:64;default:'';primary_key;" json:"Type" yaml:"Type"`
|
||||
UID string `gorm:"type:VARBINARY(255);primaryKey;" json:"UID"`
|
||||
KeyType string `gorm:"size:64;default:'';primaryKey;" json:"Type" yaml:"Type"`
|
||||
KeyURL string `gorm:"size:2048;default:'';column:key_url;" json:"-" yaml:"-"`
|
||||
key *otp.Key `gorm:"-" yaml:"-"`
|
||||
RecoveryCode string `gorm:"size:255;default:'';" json:"-" yaml:"-"`
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ var DefaultPasswordCost = 12
|
|||
|
||||
// Password represents a password hash.
|
||||
type Password struct {
|
||||
UID string `gorm:"type:VARBINARY(255);primary_key;" json:"UID"`
|
||||
UID string `gorm:"type:VARBINARY(255);primaryKey;" json:"UID"`
|
||||
Hash string `deepcopier:"skip" gorm:"type:VARBINARY(255);" json:"Hash"`
|
||||
CreatedAt time.Time `deepcopier:"skip" json:"CreatedAt"`
|
||||
UpdatedAt time.Time `deepcopier:"skip" json:"UpdatedAt"`
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/ulule/deepcopier"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/classify"
|
||||
"github.com/photoprism/photoprism/internal/event"
|
||||
|
|
@ -52,12 +52,12 @@ func MapKey(takenAt time.Time, cellId string) string {
|
|||
|
||||
// Photo represents a photo, all its properties, and link to all its images and sidecar files.
|
||||
type Photo struct {
|
||||
ID uint `gorm:"primary_key" yaml:"-"`
|
||||
ID uint `gorm:"primaryKey" yaml:"-"`
|
||||
UUID string `gorm:"type:VARBINARY(64);index;" json:"DocumentID,omitempty" yaml:"DocumentID,omitempty"`
|
||||
TakenAt time.Time `gorm:"type:DATETIME;index:idx_photos_taken_uid;" json:"TakenAt" yaml:"TakenAt"`
|
||||
TakenAtLocal time.Time `gorm:"type:DATETIME;" json:"TakenAtLocal" yaml:"TakenAtLocal"`
|
||||
TakenSrc string `gorm:"type:VARBINARY(8);" json:"TakenSrc" yaml:"TakenSrc,omitempty"`
|
||||
PhotoUID string `gorm:"type:VARBINARY(42);unique_index;index:idx_photos_taken_uid;" json:"UID" yaml:"UID"`
|
||||
PhotoUID string `gorm:"type:VARBINARY(42);uniqueIndex;index:idx_photos_taken_uid;" json:"UID" yaml:"UID"`
|
||||
PhotoType string `gorm:"type:VARBINARY(8);default:'image';" json:"Type" yaml:"Type"`
|
||||
TypeSrc string `gorm:"type:VARBINARY(8);" json:"TypeSrc" yaml:"TypeSrc,omitempty"`
|
||||
PhotoTitle string `gorm:"type:VARCHAR(200);" json:"Title" yaml:"Title"`
|
||||
|
|
@ -97,15 +97,15 @@ type Photo struct {
|
|||
CameraSerial string `gorm:"type:VARBINARY(160);" json:"CameraSerial" yaml:"CameraSerial,omitempty"`
|
||||
CameraSrc string `gorm:"type:VARBINARY(8);" json:"CameraSrc" yaml:"-"`
|
||||
LensID uint `gorm:"index:idx_photos_camera_lens;default:1" json:"LensID" yaml:"-"`
|
||||
Details *Details `gorm:"association_autoupdate:false;association_autocreate:false;association_save_reference:false" json:"Details" yaml:"Details"`
|
||||
Camera *Camera `gorm:"association_autoupdate:false;association_autocreate:false;association_save_reference:false" json:"Camera" yaml:"-"`
|
||||
Lens *Lens `gorm:"association_autoupdate:false;association_autocreate:false;association_save_reference:false" json:"Lens" yaml:"-"`
|
||||
Cell *Cell `gorm:"association_autoupdate:false;association_autocreate:false;association_save_reference:false" json:"Cell" yaml:"-"`
|
||||
Place *Place `gorm:"association_autoupdate:false;association_autocreate:false;association_save_reference:false" json:"Place" yaml:"-"`
|
||||
Keywords []Keyword `json:"-" yaml:"-"`
|
||||
Albums []Album `json:"Albums" yaml:"-"`
|
||||
Details *Details `json:"Details" yaml:"Details"`
|
||||
Camera *Camera `json:"Camera" yaml:"-"`
|
||||
Lens *Lens `json:"Lens" yaml:"-"`
|
||||
Cell *Cell `json:"Cell" yaml:"-"`
|
||||
Place *Place `json:"Place" 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:"-"`
|
||||
Files []File `yaml:"-"`
|
||||
Labels []PhotoLabel `yaml:"-"`
|
||||
Labels []PhotoLabel `gorm:"foreignKey:PhotoID" yaml:"-"`
|
||||
CreatedBy string `gorm:"type:VARBINARY(42);index" json:"CreatedBy,omitempty" yaml:"CreatedBy,omitempty"`
|
||||
CreatedAt time.Time `yaml:"CreatedAt,omitempty"`
|
||||
UpdatedAt time.Time `yaml:"UpdatedAt,omitempty"`
|
||||
|
|
@ -378,17 +378,12 @@ func (m *Photo) ClassifyLabels() classify.Labels {
|
|||
}
|
||||
|
||||
// BeforeCreate creates a random UID if needed before inserting a new row to the database.
|
||||
func (m *Photo) BeforeCreate(scope *gorm.Scope) error {
|
||||
func (m *Photo) BeforeCreate(scope *gorm.DB) error {
|
||||
if m.TakenAt.IsZero() || m.TakenAtLocal.IsZero() {
|
||||
now := TimeStamp()
|
||||
|
||||
if err := scope.SetColumn("TakenAt", now); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := scope.SetColumn("TakenAtLocal", now); err != nil {
|
||||
return err
|
||||
}
|
||||
m.TakenAt = now
|
||||
m.TakenAtLocal = now
|
||||
}
|
||||
|
||||
if rnd.IsUnique(m.PhotoUID, PhotoUID) {
|
||||
|
|
@ -396,22 +391,17 @@ func (m *Photo) BeforeCreate(scope *gorm.Scope) error {
|
|||
}
|
||||
|
||||
m.PhotoUID = rnd.GenerateUID(PhotoUID)
|
||||
|
||||
return scope.SetColumn("PhotoUID", m.PhotoUID)
|
||||
scope.Statement.SetColumn("PhotoUID", m.PhotoUID)
|
||||
return scope.Error
|
||||
}
|
||||
|
||||
// BeforeSave ensures the existence of TakenAt properties before indexing or updating a photo
|
||||
func (m *Photo) BeforeSave(scope *gorm.Scope) error {
|
||||
func (m *Photo) BeforeSave(scope *gorm.DB) error {
|
||||
if m.TakenAt.IsZero() || m.TakenAtLocal.IsZero() {
|
||||
now := TimeStamp()
|
||||
|
||||
if err := scope.SetColumn("TakenAt", now); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := scope.SetColumn("TakenAtLocal", now); err != nil {
|
||||
return err
|
||||
}
|
||||
m.TakenAt = now
|
||||
m.TakenAtLocal = now
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
@ -499,7 +489,7 @@ func (m *Photo) PreloadFiles() {
|
|||
|
||||
// PreloadKeywords prepares gorm scope to retrieve photo keywords
|
||||
func (m *Photo) PreloadKeywords() {
|
||||
q := Db().NewScope(nil).DB().
|
||||
q := Db().
|
||||
Table("keywords").
|
||||
Select(`keywords.*`).
|
||||
Joins("JOIN photos_keywords pk ON pk.keyword_id = keywords.id AND pk.photo_id = ?", m.ID).
|
||||
|
|
@ -510,7 +500,7 @@ func (m *Photo) PreloadKeywords() {
|
|||
|
||||
// PreloadAlbums prepares gorm scope to retrieve photo albums
|
||||
func (m *Photo) PreloadAlbums() {
|
||||
q := Db().NewScope(nil).DB().
|
||||
q := Db().
|
||||
Table("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).
|
||||
|
|
@ -620,7 +610,7 @@ func (m *Photo) AddLabels(labels classify.Labels) {
|
|||
}
|
||||
}
|
||||
|
||||
Db().Set("gorm:auto_preload", true).Model(m).Related(&m.Labels)
|
||||
Db().Model(m).Find(&m.Labels)
|
||||
}
|
||||
|
||||
// SetDescription changes the photo description if not empty and from the same source.
|
||||
|
|
@ -709,7 +699,7 @@ func (m *Photo) SetExposure(focalLength int, fNumber float32, iso int, exposure,
|
|||
|
||||
// AllFilesMissing returns true, if all files for this photo are missing.
|
||||
func (m *Photo) AllFilesMissing() bool {
|
||||
count := 0
|
||||
count := int64(0)
|
||||
|
||||
if err := Db().Model(&File{}).
|
||||
Where("photo_id = ? AND file_missing = 0", m.ID).
|
||||
|
|
|
|||
|
|
@ -8,15 +8,15 @@ type PhotoAlbums []PhotoAlbum
|
|||
|
||||
// PhotoAlbum represents the many_to_many relation between Photo and Album
|
||||
type PhotoAlbum struct {
|
||||
PhotoUID string `gorm:"type:VARBINARY(42);primary_key;auto_increment:false" json:"PhotoUID" yaml:"UID"`
|
||||
AlbumUID string `gorm:"type:VARBINARY(42);primary_key;auto_increment:false;index" json:"AlbumUID" yaml:"-"`
|
||||
PhotoUID string `gorm:"type:VARBINARY(42);primaryKey;" json:"PhotoUID" yaml:"UID"`
|
||||
AlbumUID string `gorm:"type:VARBINARY(42);primaryKey;" json:"AlbumUID" yaml:"-"`
|
||||
Order int `json:"Order" yaml:"Order,omitempty"`
|
||||
Hidden bool `json:"Hidden" yaml:"Hidden,omitempty"`
|
||||
Missing bool `json:"Missing" yaml:"Missing,omitempty"`
|
||||
CreatedAt time.Time `json:"CreatedAt" yaml:"CreatedAt,omitempty"`
|
||||
UpdatedAt time.Time `json:"UpdatedAt" yaml:"-"`
|
||||
Photo *Photo `gorm:"PRELOAD:false" yaml:"-"`
|
||||
Album *Album `gorm:"PRELOAD:true" yaml:"-"`
|
||||
Photo *Photo `gorm:"foreignKey:PhotoUID;references:PhotoUID;" yaml:"-"`
|
||||
Album *Album `gorm:"foreignKey:AlbumUID;references:AlbumUID;" yaml:"-"`
|
||||
}
|
||||
|
||||
// TableName returns the entity table name.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package entity
|
|||
import (
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/photoprism/photoprism/pkg/clean"
|
||||
"github.com/photoprism/photoprism/pkg/fs"
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ package entity
|
|||
|
||||
// PhotoKeyword represents the many-to-many relation between Photo and Keyword
|
||||
type PhotoKeyword struct {
|
||||
PhotoID uint `gorm:"primary_key;auto_increment:false"`
|
||||
KeywordID uint `gorm:"primary_key;auto_increment:false;index"`
|
||||
PhotoID uint `gorm:"primaryKey;autoIncrement:false"`
|
||||
KeywordID uint `gorm:"primaryKey;autoIncrement:false"`
|
||||
}
|
||||
|
||||
// TableName returns the entity table name.
|
||||
|
|
|
|||
|
|
@ -136,6 +136,6 @@ var PhotoKeywordFixtures = PhotoKeywordMap{
|
|||
// CreatePhotoKeywordFixtures inserts known entities into the database for testing.
|
||||
func CreatePhotoKeywordFixtures() {
|
||||
for _, entity := range PhotoKeywordFixtures {
|
||||
Db().Create(&entity)
|
||||
Db().Save(&entity)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,12 +9,12 @@ type PhotoLabels []PhotoLabel
|
|||
// PhotoLabel represents the many-to-many relation between Photo and label.
|
||||
// Labels are weighted by uncertainty (100 - confidence)
|
||||
type PhotoLabel struct {
|
||||
PhotoID uint `gorm:"primary_key;auto_increment:false"`
|
||||
LabelID uint `gorm:"primary_key;auto_increment:false;index"`
|
||||
PhotoID uint `gorm:"primaryKey;autoIncrement:false"`
|
||||
LabelID uint `gorm:"primaryKey;autoIncrement:false"`
|
||||
LabelSrc string `gorm:"type:VARBINARY(8);"`
|
||||
Uncertainty int `gorm:"type:SMALLINT"`
|
||||
Photo *Photo `gorm:"PRELOAD:false"`
|
||||
Label *Label `gorm:"PRELOAD:true"`
|
||||
Photo *Photo
|
||||
Label *Label
|
||||
}
|
||||
|
||||
// TableName returns the entity table name.
|
||||
|
|
@ -52,6 +52,9 @@ func (m *PhotoLabel) Save() error {
|
|||
|
||||
if m.Label != nil {
|
||||
m.Label.SetName(m.Label.LabelName)
|
||||
if err := m.Label.Save(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return Db().Save(m).Error
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ package entity
|
|||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/photoprism/photoprism/pkg/rnd"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var photoMergeMutex = sync.Mutex{}
|
||||
|
|
|
|||
|
|
@ -125,13 +125,13 @@ func TestPhoto_SaveLabels(t *testing.T) {
|
|||
func TestPhoto_ClassifyLabels(t *testing.T) {
|
||||
t.Run("NewPhoto", func(t *testing.T) {
|
||||
m := PhotoFixtures.Get("Photo19")
|
||||
Db().Set("gorm:auto_preload", true).Model(&m).Related(&m.Labels)
|
||||
Db().Set("gorm:auto_preload", true).Model(&m).Find(&m.Labels)
|
||||
labels := m.ClassifyLabels()
|
||||
assert.Empty(t, labels)
|
||||
})
|
||||
t.Run("ExistingPhoto", func(t *testing.T) {
|
||||
m := PhotoFixtures.Get("19800101_000002_D640C559")
|
||||
Db().Set("gorm:auto_preload", true).Model(&m).Related(&m.Labels)
|
||||
Db().Set("gorm:auto_preload", true).Model(&m).Find(&m.Labels)
|
||||
labels := m.ClassifyLabels()
|
||||
assert.LessOrEqual(t, 2, labels.Len())
|
||||
})
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import "github.com/photoprism/photoprism/internal/event"
|
|||
|
||||
// PhotoUser represents the user and group ownership of a Photo and the corresponding permissions.
|
||||
type PhotoUser struct {
|
||||
UID string `gorm:"type:VARBINARY(42);primary_key;auto_increment:false" json:"UID" yaml:"UID"`
|
||||
UserUID string `gorm:"type:VARBINARY(42);primary_key;auto_increment:false;index" json:"UserUID,omitempty" yaml:"UserUID,omitempty"`
|
||||
UID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false" json:"UID" yaml:"UID"`
|
||||
UserUID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false;index" json:"UserUID,omitempty" yaml:"UserUID,omitempty"`
|
||||
TeamUID string `gorm:"type:VARBINARY(42);index" json:"TeamUID,omitempty" yaml:"TeamUID,omitempty"`
|
||||
Perm uint `json:"Perm,omitempty" yaml:"Perm,omitempty"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ var placeMutex = sync.Mutex{}
|
|||
|
||||
// Place represents a distinct region identified by city, district, state, and country.
|
||||
type Place struct {
|
||||
ID string `gorm:"type:VARBINARY(42);primary_key;auto_increment:false;" json:"PlaceID" yaml:"PlaceID"`
|
||||
ID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false;" json:"PlaceID" yaml:"PlaceID"`
|
||||
PlaceLabel string `gorm:"type:VARCHAR(400);" json:"Label" yaml:"Label"`
|
||||
PlaceDistrict string `gorm:"type:VARCHAR(100);index;" json:"District" yaml:"District,omitempty"`
|
||||
PlaceCity string `gorm:"type:VARCHAR(100);index;" json:"City" yaml:"City,omitempty"`
|
||||
|
|
@ -46,7 +46,10 @@ var UnknownPlace = Place{
|
|||
|
||||
// CreateUnknownPlace creates the default place if not exists.
|
||||
func CreateUnknownPlace() {
|
||||
UnknownPlace = *FirstOrCreatePlace(&UnknownPlace)
|
||||
pRef := FirstOrCreatePlace(&UnknownPlace)
|
||||
if pRef != nil {
|
||||
UnknownPlace = *pRef
|
||||
}
|
||||
}
|
||||
|
||||
// FindPlace finds a matching place or returns nil.
|
||||
|
|
|
|||
|
|
@ -4,16 +4,16 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/photoprism/photoprism/pkg/react"
|
||||
)
|
||||
|
||||
// Reaction represents a human response to content such as photos and albums.
|
||||
type Reaction struct {
|
||||
UID string `gorm:"type:VARBINARY(42);primary_key;auto_increment:false" json:"UID,omitempty" yaml:"UID,omitempty"`
|
||||
UserUID string `gorm:"type:VARBINARY(42);primary_key;auto_increment:false" json:"UserUID,omitempty" yaml:"UserUID,omitempty"`
|
||||
Reaction string `gorm:"type:VARBINARY(64);primary_key;auto_increment:false" json:"Reaction,omitempty" yaml:"Reaction,omitempty"`
|
||||
UID string `gorm:"type:VARBINARY(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"`
|
||||
Reaction string `gorm:"type:VARBINARY(64);primaryKey;autoIncrement:false" json:"Reaction,omitempty" yaml:"Reaction,omitempty"`
|
||||
Reacted int `json:"Reacted,omitempty" yaml:"Reacted,omitempty"`
|
||||
ReactedAt *time.Time `sql:"index" json:"ReactedAt,omitempty" yaml:"ReactedAt,omitempty"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ type Services []Service
|
|||
// - AccSync enables automatic file synchronization, see SyncDownload and SyncUpload.
|
||||
// - RetryLimit specifies the number of retry attempts, a negative value disables the limit.
|
||||
type Service struct {
|
||||
ID uint `gorm:"primary_key"`
|
||||
ID uint `gorm:"primaryKey"`
|
||||
AccName string `gorm:"type:VARCHAR(160);"`
|
||||
AccOwner string `gorm:"type:VARCHAR(160);"`
|
||||
AccURL string `gorm:"type:VARCHAR(255);"`
|
||||
|
|
@ -83,6 +83,10 @@ func AddService(form form.Service) (model *Service, err error) {
|
|||
return model, err
|
||||
}
|
||||
|
||||
func (m *Service) IsNew() bool {
|
||||
return m.CreatedAt.IsZero()
|
||||
}
|
||||
|
||||
// LogErr updates the service error count and message.
|
||||
func (m *Service) LogErr(err error) error {
|
||||
if err == nil {
|
||||
|
|
@ -104,7 +108,7 @@ func (m *Service) LogErr(err error) error {
|
|||
|
||||
// ResetErrors resets the service and related file error messages and counters.
|
||||
func (m *Service) ResetErrors(share, sync bool) error {
|
||||
if !share && !sync || Db().NewRecord(m) {
|
||||
if !share && !sync || m.IsNew() {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -173,7 +177,7 @@ func (m *Service) SaveForm(form form.Service) error {
|
|||
}
|
||||
|
||||
// Reset error counters if account already exists.
|
||||
if !Db().NewRecord(m) {
|
||||
if !m.IsNew() {
|
||||
Log("service", "reset errors", m.ResetErrors(m.AccShare, m.AccSync))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/event"
|
||||
"github.com/photoprism/photoprism/internal/form"
|
||||
|
|
@ -19,11 +19,11 @@ var subjectMutex = sync.Mutex{}
|
|||
|
||||
// Subject represents a named photo subject, typically a person.
|
||||
type Subject struct {
|
||||
SubjUID string `gorm:"type:VARBINARY(42);primary_key;auto_increment:false;" json:"UID" yaml:"UID"`
|
||||
SubjUID string `gorm:"type:VARBINARY(42);primaryKey;autoIncrement:false;" json:"UID" yaml:"UID"`
|
||||
SubjType string `gorm:"type:VARBINARY(8);default:'';" json:"Type,omitempty" yaml:"Type,omitempty"`
|
||||
SubjSrc string `gorm:"type:VARBINARY(8);default:'';" json:"Src,omitempty" yaml:"Src,omitempty"`
|
||||
SubjSlug string `gorm:"type:VARBINARY(160);index;default:'';" json:"Slug" yaml:"-"`
|
||||
SubjName string `gorm:"size:160;unique_index;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"`
|
||||
SubjAbout string `gorm:"size:512;" json:"About" yaml:"About,omitempty"`
|
||||
SubjBio string `gorm:"size:2048;" json:"Bio" yaml:"Bio,omitempty"`
|
||||
|
|
@ -47,22 +47,24 @@ func (Subject) TableName() string {
|
|||
}
|
||||
|
||||
// BeforeCreate creates a random uid if needed before inserting a new row to the database.
|
||||
func (m *Subject) BeforeCreate(scope *gorm.Scope) error {
|
||||
func (m *Subject) BeforeCreate(scope *gorm.DB) error {
|
||||
if rnd.IsUnique(m.SubjUID, 'j') {
|
||||
return nil
|
||||
}
|
||||
|
||||
return scope.SetColumn("SubjUID", rnd.GenerateUID('j'))
|
||||
m.SubjUID = rnd.GenerateUID('j')
|
||||
scope.Statement.SetColumn("SubjUID", m.SubjUID)
|
||||
return scope.Error
|
||||
}
|
||||
|
||||
// AfterSave is a hook that updates the name cache after saving.
|
||||
func (m *Subject) AfterSave() (err error) {
|
||||
func (m *Subject) AfterSave(db *gorm.DB) (err error) {
|
||||
SubjNames.Set(m.SubjUID, m.SubjName)
|
||||
return
|
||||
}
|
||||
|
||||
// AfterFind is a hook that updates the name cache after querying.
|
||||
func (m *Subject) AfterFind() (err error) {
|
||||
func (m *Subject) AfterFind(db *gorm.DB) (err error) {
|
||||
SubjNames.Set(m.SubjUID, m.SubjName)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"encoding/json"
|
||||
|
||||
"github.com/photoprism/photoprism/pkg/txt"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -23,7 +24,7 @@ type Person struct {
|
|||
}
|
||||
|
||||
// AfterFind is a hook that updates the name cache after querying.
|
||||
func (m *Person) AfterFind() (err error) {
|
||||
func (m *Person) AfterFind(db *gorm.DB) (err error) {
|
||||
SubjNames.Set(m.SubjUID, m.SubjName)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,14 +4,15 @@ import (
|
|||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
_ "github.com/jinzhu/gorm/dialects/mysql"
|
||||
_ "github.com/jinzhu/gorm/dialects/sqlite"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
)
|
||||
|
||||
func TestDialectMysql(t *testing.T) {
|
||||
|
|
@ -25,9 +26,20 @@ func TestDialectMysql(t *testing.T) {
|
|||
log = logrus.StandardLogger()
|
||||
log.SetLevel(logrus.TraceLevel)
|
||||
|
||||
db, err := gorm.Open(
|
||||
"mysql",
|
||||
"migrate:migrate@tcp(mariadb:4001)/migrate?charset=utf8mb4,utf8&collation=utf8mb4_unicode_ci&parseTime=true",
|
||||
db, err := gorm.Open(mysql.Open(
|
||||
"migrate:migrate@tcp(mariadb:4001)/migrate?charset=utf8mb4,utf8&collation=utf8mb4_unicode_ci&parseTime=true"),
|
||||
&gorm.Config{
|
||||
Logger: logger.New(
|
||||
log,
|
||||
logger.Config{
|
||||
SlowThreshold: time.Second, // Slow SQL threshold
|
||||
LogLevel: logger.Error, // Log level
|
||||
IgnoreRecordNotFoundError: true, // Ignore ErrRecordNotFound error for logger
|
||||
ParameterizedQueries: true, // Don't include params in the SQL log
|
||||
Colorful: false, // Disable color
|
||||
},
|
||||
),
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil || db == nil {
|
||||
|
|
@ -38,10 +50,8 @@ func TestDialectMysql(t *testing.T) {
|
|||
return
|
||||
}
|
||||
|
||||
defer db.Close()
|
||||
|
||||
db.LogMode(false)
|
||||
db.SetLogger(log)
|
||||
sqldb, _ := db.DB()
|
||||
defer sqldb.Close()
|
||||
|
||||
opt := Opt(true, true, nil)
|
||||
|
||||
|
|
@ -57,7 +67,7 @@ func TestDialectMysql(t *testing.T) {
|
|||
|
||||
stmt := db.Table("photos").Where("photo_description = '' OR photo_description IS NULL")
|
||||
|
||||
count := 0
|
||||
count := int64(0)
|
||||
|
||||
// Fetch count from database.
|
||||
if err = stmt.Count(&count).Error; err != nil {
|
||||
|
|
|
|||
|
|
@ -5,97 +5,97 @@ package migrate
|
|||
var DialectSQLite3 = Migrations{
|
||||
{
|
||||
ID: "20211121-094727",
|
||||
Dialect: "sqlite3",
|
||||
Dialect: "sqlite",
|
||||
Stage: "main",
|
||||
Statements: []string{"DROP INDEX IF EXISTS idx_places_place_label;"},
|
||||
},
|
||||
{
|
||||
ID: "20211124-120008",
|
||||
Dialect: "sqlite3",
|
||||
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: "sqlite3",
|
||||
Dialect: "sqlite",
|
||||
Stage: "main",
|
||||
Statements: []string{"DROP INDEX IF EXISTS idx_albums_album_filter;"},
|
||||
},
|
||||
{
|
||||
ID: "20220329-050000",
|
||||
Dialect: "sqlite3",
|
||||
Dialect: "sqlite",
|
||||
Stage: "main",
|
||||
Statements: []string{"CREATE INDEX IF NOT EXISTS idx_albums_album_filter ON albums (album_filter);"},
|
||||
},
|
||||
{
|
||||
ID: "20220329-061000",
|
||||
Dialect: "sqlite3",
|
||||
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: "sqlite3",
|
||||
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: "sqlite3",
|
||||
Dialect: "sqlite",
|
||||
Stage: "main",
|
||||
Statements: []string{"CREATE UNIQUE INDEX IF NOT EXISTS idx_files_search_media ON files (media_id);"},
|
||||
},
|
||||
{
|
||||
ID: "20220329-083000",
|
||||
Dialect: "sqlite3",
|
||||
Dialect: "sqlite",
|
||||
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;"},
|
||||
},
|
||||
{
|
||||
ID: "20220329-091000",
|
||||
Dialect: "sqlite3",
|
||||
Dialect: "sqlite",
|
||||
Stage: "main",
|
||||
Statements: []string{"CREATE UNIQUE INDEX IF NOT EXISTS idx_files_search_timeline ON files (time_index);"},
|
||||
},
|
||||
{
|
||||
ID: "20220329-093000",
|
||||
Dialect: "sqlite3",
|
||||
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: "sqlite3",
|
||||
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: "sqlite3",
|
||||
Dialect: "sqlite",
|
||||
Stage: "pre",
|
||||
Statements: []string{"ALTER TABLE accounts RENAME TO services;"},
|
||||
},
|
||||
{
|
||||
ID: "20221015-100100",
|
||||
Dialect: "sqlite3",
|
||||
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: "sqlite3",
|
||||
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: "sqlite3",
|
||||
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: "sqlite3",
|
||||
Dialect: "sqlite",
|
||||
Stage: "main",
|
||||
Statements: []string{"DELETE FROM auth_sessions;"},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -4,13 +4,14 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
_ "github.com/jinzhu/gorm/dialects/mysql"
|
||||
_ "github.com/jinzhu/gorm/dialects/sqlite"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
|
||||
"github.com/photoprism/photoprism/pkg/fs"
|
||||
)
|
||||
|
|
@ -34,9 +35,19 @@ func TestDialectSQLite3(t *testing.T) {
|
|||
log = logrus.StandardLogger()
|
||||
log.SetLevel(logrus.TraceLevel)
|
||||
|
||||
db, err := gorm.Open(
|
||||
"sqlite3",
|
||||
dumpName,
|
||||
db, err := gorm.Open(sqlite.Open(dumpName),
|
||||
&gorm.Config{
|
||||
Logger: logger.New(
|
||||
log,
|
||||
logger.Config{
|
||||
SlowThreshold: time.Second, // Slow SQL threshold
|
||||
LogLevel: logger.Error, // Log level
|
||||
IgnoreRecordNotFoundError: true, // Ignore ErrRecordNotFound error for logger
|
||||
ParameterizedQueries: true, // Don't include params in the SQL log
|
||||
Colorful: false, // Disable color
|
||||
},
|
||||
),
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil || db == nil {
|
||||
|
|
@ -47,10 +58,8 @@ func TestDialectSQLite3(t *testing.T) {
|
|||
return
|
||||
}
|
||||
|
||||
defer db.Close()
|
||||
|
||||
db.LogMode(false)
|
||||
db.SetLogger(log)
|
||||
sqldb, _ := db.DB()
|
||||
defer sqldb.Close()
|
||||
|
||||
opt := Opt(true, true, nil)
|
||||
|
||||
|
|
@ -66,12 +75,12 @@ func TestDialectSQLite3(t *testing.T) {
|
|||
|
||||
stmt := db.Table("photos").Where("photo_description = '' OR photo_description IS NULL")
|
||||
|
||||
count := 0
|
||||
count := int64(0)
|
||||
|
||||
// Fetch count from database.
|
||||
if err = stmt.Count(&count).Error; err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
assert.Equal(t, 0, count)
|
||||
assert.Equal(t, 0, int(count))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import "sync"
|
|||
// Supported database dialects.
|
||||
const (
|
||||
MySQL = "mysql"
|
||||
SQLite3 = "sqlite3"
|
||||
SQLite3 = "sqlite"
|
||||
)
|
||||
|
||||
var Dialects = map[string]Migrations{
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ func gen_migrations(name string) {
|
|||
|
||||
func main() {
|
||||
gen_migrations("MySQL")
|
||||
gen_migrations("SQLite3")
|
||||
gen_migrations("SQLite")
|
||||
}
|
||||
|
||||
var migrationsTemplate = template.Must(template.New("").Parse(`
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Migration represents a database schema migration.
|
||||
type Migration struct {
|
||||
ID string `gorm:"size:16;primary_key;auto_increment:false;" json:"ID" yaml:"ID"`
|
||||
ID string `gorm:"size:16;primaryKey;autoIncrement:false;" json:"ID" yaml:"ID"`
|
||||
Dialect string `gorm:"size:16;" json:"Dialect" yaml:"Dialect,omitempty"`
|
||||
Stage string `gorm:"size:16;" json:"Stage" yaml:"Stage,omitempty"`
|
||||
Error string `gorm:"size:255;" json:"Error" yaml:"Error,omitempty"`
|
||||
|
|
@ -111,7 +111,7 @@ func (m *Migration) Finish(db *gorm.DB) error {
|
|||
finished := time.Now().UTC().Truncate(time.Second)
|
||||
m.FinishedAt = &finished
|
||||
m.Error = ""
|
||||
return db.Model(m).Updates(Map{"FinishedAt": m.FinishedAt, "Error": m.Error}).Error
|
||||
return db.Model(m).Save(m).Error
|
||||
}
|
||||
|
||||
// Execute runs the migration.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import (
|
|||
"github.com/photoprism/photoprism/pkg/list"
|
||||
|
||||
"github.com/dustin/go-humanize/english"
|
||||
"github.com/jinzhu/gorm"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Migrations represents a sorted list of migrations.
|
||||
|
|
@ -25,7 +25,7 @@ func Existing(db *gorm.DB, stage string) MigrationMap {
|
|||
}
|
||||
|
||||
// Get SQL dialect name.
|
||||
name := db.Dialect().GetName()
|
||||
name := db.Dialector.Name()
|
||||
|
||||
if name == "" {
|
||||
return make(MigrationMap)
|
||||
|
|
@ -33,10 +33,11 @@ func Existing(db *gorm.DB, stage string) MigrationMap {
|
|||
|
||||
// Make sure a "migrations" table exists.
|
||||
once[name].Do(func() {
|
||||
err = db.AutoMigrate(&Migration{}).Error
|
||||
err = db.AutoMigrate(&Migration{})
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("migrate: Cannot create / update migrations table: %s", err)
|
||||
return make(MigrationMap)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,17 +3,17 @@ package migrate
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Run automatically migrates the schema of the database passed as argument.
|
||||
func Run(db *gorm.DB, opt Options) (err error) {
|
||||
if db == nil {
|
||||
if db == nil || db.Dialector == nil {
|
||||
return fmt.Errorf("migrate: no database connection")
|
||||
}
|
||||
|
||||
// Get SQL dialect name.
|
||||
name := db.Dialect().GetName()
|
||||
name := db.Dialector.Name()
|
||||
|
||||
if name == "" {
|
||||
return fmt.Errorf("migrate: failed to determine sql dialect")
|
||||
|
|
@ -21,7 +21,7 @@ func Run(db *gorm.DB, opt Options) (err error) {
|
|||
|
||||
// Make sure a "migrations" table exists.
|
||||
once[name].Do(func() {
|
||||
err = db.AutoMigrate(&Migration{}).Error
|
||||
err = db.AutoMigrate(&Migration{})
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/dustin/go-humanize/english"
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/photoprism/photoprism/pkg/list"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Status returns the current status of schema migrations.
|
||||
|
|
@ -17,7 +17,7 @@ func Status(db *gorm.DB, ids []string) (status Migrations, err error) {
|
|||
}
|
||||
|
||||
// Get SQL dialect name.
|
||||
name := db.Dialect().GetName()
|
||||
name := db.Dialector.Name()
|
||||
|
||||
if name == "" {
|
||||
return status, fmt.Errorf("migrate: failed to determine sql dialect")
|
||||
|
|
@ -25,7 +25,7 @@ func Status(db *gorm.DB, ids []string) (status Migrations, err error) {
|
|||
|
||||
// Make sure a "migrations" table exists.
|
||||
once[name].Do(func() {
|
||||
err = db.AutoMigrate(&Migration{}).Error
|
||||
err = db.AutoMigrate(&Migration{})
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/photoprism/photoprism/pkg/clean"
|
||||
"github.com/photoprism/photoprism/pkg/txt"
|
||||
|
|
@ -16,9 +16,9 @@ var versionMutex = sync.Mutex{}
|
|||
|
||||
// Version represents the application version.
|
||||
type Version struct {
|
||||
ID uint `gorm:"primary_key" yaml:"-"`
|
||||
Version string `gorm:"size:255;unique_index:idx_version_edition;" json:"Version" yaml:"Version,omitempty"`
|
||||
Edition string `gorm:"size:255;unique_index:idx_version_edition;" json:"Edition" yaml:"Edition,omitempty"`
|
||||
ID uint `gorm:"primaryKey" yaml:"-"`
|
||||
Version string `gorm:"size:255;uniqueIndex:idx_version_edition;" json:"Version" yaml:"Version,omitempty"`
|
||||
Edition string `gorm:"size:255;uniqueIndex:idx_version_edition;" json:"Edition" yaml:"Edition,omitempty"`
|
||||
Error string `gorm:"size:255;" json:"Error" yaml:"Error,omitempty"`
|
||||
CreatedAt time.Time `yaml:"CreatedAt,omitempty"`
|
||||
UpdatedAt time.Time `yaml:"UpdatedAt,omitempty"`
|
||||
|
|
@ -161,7 +161,7 @@ func (m *Version) CreateTable(db *gorm.DB) (err error) {
|
|||
}
|
||||
|
||||
versionOnce.Do(func() {
|
||||
err = db.AutoMigrate(&Version{}).Error
|
||||
err = db.AutoMigrate(&Version{})
|
||||
})
|
||||
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/classify"
|
||||
"github.com/photoprism/photoprism/internal/entity"
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue