Replace GORM with GORMv2

This commit is contained in:
Florian Albrecht 2024-04-21 19:08:12 +02:00
parent 8257b82c01
commit 20dad85a8e
119 changed files with 491 additions and 487 deletions

3
.gitignore vendored
View file

@ -66,3 +66,6 @@ Thumbs.db
#Karma Coverage Report
frontend/coverage/
# IDE files from exotic IDEs :-)
.vscode/

26
go.mod
View file

@ -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
View file

@ -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=

View file

@ -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"

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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"

View file

@ -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()
},
}
}

View file

@ -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"

View file

@ -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) {

View file

@ -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)

View file

@ -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)

View file

@ -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)
}
}

View file

@ -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"`
}

View file

@ -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
}

View file

@ -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.

View file

@ -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.

View file

@ -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

View file

@ -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{}

View file

@ -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.

View file

@ -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"

View file

@ -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:"-"`

View file

@ -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)
}

View file

@ -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
}

View file

@ -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"`

View file

@ -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"`

View file

@ -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.

View file

@ -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"`

View file

@ -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
}

View file

@ -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 {

View file

@ -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()
},
}
}

View file

@ -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:"-"`

View file

@ -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)
}
}

View file

@ -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"`

View file

@ -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:"-"`

View file

@ -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)
}

View file

@ -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"
)

View file

@ -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)
}
}
}

View file

@ -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())

View file

@ -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...)

View file

@ -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) {

View file

@ -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"`

View file

@ -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
}

View file

@ -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.

View file

@ -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
}

View file

@ -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
}

View file

@ -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()

View file

@ -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.

View file

@ -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
}

View file

@ -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)
}
}

View file

@ -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)
}
}

View file

@ -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"`

View file

@ -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"`

View file

@ -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.

View file

@ -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.

View file

@ -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)

View file

@ -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:"-"`

View file

@ -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"`

View file

@ -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).

View file

@ -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.

View file

@ -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"

View file

@ -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.

View file

@ -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)
}
}

View file

@ -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

View file

@ -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{}

View file

@ -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())
})

View file

@ -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"`
}

View file

@ -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.

View file

@ -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"`
}

View file

@ -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))
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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 {

View file

@ -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;"},
},

View file

@ -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))
}
}

View file

@ -5,7 +5,7 @@ import "sync"
// Supported database dialects.
const (
MySQL = "mysql"
SQLite3 = "sqlite3"
SQLite3 = "sqlite"
)
var Dialects = map[string]Migrations{

View file

@ -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(`

View file

@ -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.

View file

@ -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)
}

View file

@ -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 {

View file

@ -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 {

View file

@ -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

View file

@ -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