mirror of
https://github.com/gogs/gogs.git
synced 2026-02-28 17:20:59 +01:00
Compare commits
29 Commits
latest-com
...
copilot/re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
074714d61f | ||
|
|
68f049ad15 | ||
|
|
ec5eede78f | ||
|
|
06b85ac5ba | ||
|
|
c74b48bd2d | ||
|
|
e89db8393d | ||
|
|
653c95c842 | ||
|
|
dfc768b968 | ||
|
|
63221dfec3 | ||
|
|
d2ff1fa978 | ||
|
|
748ecbfdf3 | ||
|
|
04d063c65d | ||
|
|
eebe4065c6 | ||
|
|
de9f03d533 | ||
|
|
8d43893af2 | ||
|
|
233f0fb18d | ||
|
|
aba381e7f8 | ||
|
|
1a285ca5ce | ||
|
|
b74ce2f6bc | ||
|
|
5469f017bc | ||
|
|
cddfd5fbb9 | ||
|
|
9bd5123bcf | ||
|
|
589bf5f532 | ||
|
|
9d9175df80 | ||
|
|
e3e107f95d | ||
|
|
36833b135e | ||
|
|
d5954c42eb | ||
|
|
f9478a3f76 | ||
|
|
9bfb9a719b |
12
go.mod
12
go.mod
@@ -57,13 +57,11 @@ require (
|
|||||||
gorm.io/gorm v1.25.12
|
gorm.io/gorm v1.25.12
|
||||||
modernc.org/sqlite v1.38.2
|
modernc.org/sqlite v1.38.2
|
||||||
unknwon.dev/clog/v2 v2.2.0
|
unknwon.dev/clog/v2 v2.2.0
|
||||||
xorm.io/builder v0.3.6
|
|
||||||
xorm.io/core v0.7.2
|
|
||||||
xorm.io/xorm v0.8.0
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
bitbucket.org/creachadair/shell v0.0.7 // indirect
|
bitbucket.org/creachadair/shell v0.0.7 // indirect
|
||||||
|
filippo.io/edwards25519 v1.1.0 // indirect
|
||||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
||||||
github.com/aymerick/douceur v0.2.0 // indirect
|
github.com/aymerick/douceur v0.2.0 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
@@ -74,7 +72,6 @@ require (
|
|||||||
github.com/cockroachdb/redact v1.1.5 // indirect
|
github.com/cockroachdb/redact v1.1.5 // indirect
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/denisenkom/go-mssqldb v0.12.0 // indirect
|
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
github.com/djherbis/buffer v1.2.0 // indirect
|
github.com/djherbis/buffer v1.2.0 // indirect
|
||||||
github.com/djherbis/nio/v3 v3.0.1 // indirect
|
github.com/djherbis/nio/v3 v3.0.1 // indirect
|
||||||
@@ -86,7 +83,7 @@ require (
|
|||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-macaron/inject v0.0.0-20200308113650-138e5925c53b // indirect
|
github.com/go-macaron/inject v0.0.0-20200308113650-138e5925c53b // indirect
|
||||||
github.com/go-redis/redis/v8 v8.11.5 // indirect
|
github.com/go-redis/redis/v8 v8.11.5 // indirect
|
||||||
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
github.com/go-sql-driver/mysql v1.8.1 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
||||||
github.com/golang-sql/sqlexp v0.1.0 // indirect
|
github.com/golang-sql/sqlexp v0.1.0 // indirect
|
||||||
@@ -104,13 +101,12 @@ require (
|
|||||||
github.com/klauspost/compress v1.18.0 // indirect
|
github.com/klauspost/compress v1.18.0 // indirect
|
||||||
github.com/kr/pretty v0.3.1 // indirect
|
github.com/kr/pretty v0.3.1 // indirect
|
||||||
github.com/kr/text v0.2.0 // indirect
|
github.com/kr/text v0.2.0 // indirect
|
||||||
github.com/lib/pq v1.10.2 // indirect
|
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||||
github.com/mattn/go-sqlite3 v1.14.24 // indirect
|
github.com/mattn/go-sqlite3 v1.14.32 // indirect
|
||||||
github.com/mcuadros/go-version v0.0.0-20190830083331-035f6764e8d2 // indirect
|
github.com/mcuadros/go-version v0.0.0-20190830083331-035f6764e8d2 // indirect
|
||||||
github.com/microsoft/go-mssqldb v0.17.0 // indirect
|
github.com/microsoft/go-mssqldb v1.8.2 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
|
|||||||
141
go.sum
141
go.sum
@@ -1,33 +1,35 @@
|
|||||||
bitbucket.org/creachadair/shell v0.0.7 h1:Z96pB6DkSb7F3Y3BBnJeOZH2gazyMTWlvecSD4vDqfk=
|
bitbucket.org/creachadair/shell v0.0.7 h1:Z96pB6DkSb7F3Y3BBnJeOZH2gazyMTWlvecSD4vDqfk=
|
||||||
bitbucket.org/creachadair/shell v0.0.7/go.mod h1:oqtXSSvSYr4624lnnabXHaBsYW6RD80caLi2b3hJk0U=
|
bitbucket.org/creachadair/shell v0.0.7/go.mod h1:oqtXSSvSYr4624lnnabXHaBsYW6RD80caLi2b3hJk0U=
|
||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||||
cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
|
|
||||||
gitea.com/lunny/log v0.0.0-20190322053110-01b5df579c4e/go.mod h1:uJEsN4LQpeGYRCjuPXPZBClU7N5pWzGuyF4uqLpE/e0=
|
gitea.com/lunny/log v0.0.0-20190322053110-01b5df579c4e/go.mod h1:uJEsN4LQpeGYRCjuPXPZBClU7N5pWzGuyF4uqLpE/e0=
|
||||||
gitea.com/lunny/nodb v0.0.0-20200923032308-3238c4655727/go.mod h1:h0OwsgcpJLSYtHcM5+Xciw9OEeuxi6ty4HDiO8C7aIY=
|
gitea.com/lunny/nodb v0.0.0-20200923032308-3238c4655727/go.mod h1:h0OwsgcpJLSYtHcM5+Xciw9OEeuxi6ty4HDiO8C7aIY=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw=
|
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.0.0/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U=
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.0.0/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0=
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 h1:E+OJmp2tPvt1W+amx48v1eqbjDYsgN+RzP4q16yV5eM=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1/go.mod h1:a6xsAQUZg+VsS3TJ05SRp524Hs4pZ/AeFSr5ENf0Yjo=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.0.0/go.mod h1:+6sju8gk8FRmSajX3Oz4G5Gm7P+mbqE9FVaXXFYTkCM=
|
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.0.0/go.mod h1:+6sju8gk8FRmSajX3Oz4G5Gm7P+mbqE9FVaXXFYTkCM=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8=
|
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0 h1:U2rTu3Ef+7w9FHKIAXM6ZyqF3UOWJZ12zIm8zECAFfg=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
|
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0 h1:jBQA3cKT4L2rWMpgE7Yt3Hwh2aUj8KXjIGLxjHeYNNo=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0/go.mod h1:4OG6tQ9EOP/MT0NMjDlRzWoVFxfu9rN9B2X+tlSVktg=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1 h1:MyVTgWR8qd/Jw1Le0NZebGBUCLbtak3bJ3z1OlqZBpw=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1/go.mod h1:GpPjLhVR9dnUoJMyHWSPy71xY9/lcmpzIPZXmF0FCVY=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occbWoio4EBLkbkevetNMAVX197GkzbUMtqjGWn80=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI=
|
||||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
|
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/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
||||||
github.com/AzureAD/microsoft-authentication-library-for-go v0.4.0/go.mod h1:Vt9sXTKwMyGcOxSmLDMnGPgqsUg7m8pe215qMLrDXw4=
|
github.com/AzureAD/microsoft-authentication-library-for-go v0.4.0/go.mod h1:Vt9sXTKwMyGcOxSmLDMnGPgqsUg7m8pe215qMLrDXw4=
|
||||||
|
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU=
|
||||||
|
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
|
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
|
||||||
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
|
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
|
||||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
|
||||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
|
||||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI=
|
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/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
|
||||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
|
||||||
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
||||||
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
|
||||||
@@ -40,7 +42,6 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
|
|||||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
|
||||||
github.com/cockroachdb/errors v1.12.0 h1:d7oCs6vuIMUQRVbi6jWWWEJZahLCfJpnJSVobd1/sUo=
|
github.com/cockroachdb/errors v1.12.0 h1:d7oCs6vuIMUQRVbi6jWWWEJZahLCfJpnJSVobd1/sUo=
|
||||||
github.com/cockroachdb/errors v1.12.0/go.mod h1:SvzfYNNBshAVbZ8wzNc/UPK3w1vf0dKDUP41ucAIf7g=
|
github.com/cockroachdb/errors v1.12.0/go.mod h1:SvzfYNNBshAVbZ8wzNc/UPK3w1vf0dKDUP41ucAIf7g=
|
||||||
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE=
|
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE=
|
||||||
@@ -60,9 +61,6 @@ github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGii
|
|||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
|
|
||||||
github.com/denisenkom/go-mssqldb v0.12.0 h1:VtrkII767ttSPNRfFekePK3sctr+joXgO58stqQbtUA=
|
|
||||||
github.com/denisenkom/go-mssqldb v0.12.0/go.mod h1:iiK0YP1ZeepvmBQk/QpLEhhTNJgfzrpArPY/aFvc9yU=
|
|
||||||
github.com/derision-test/go-mockgen/v2 v2.1.1 h1:MXG9rzyvsrDBfa1a1GatvHjCrbmEug3hVt0rSOXipCw=
|
github.com/derision-test/go-mockgen/v2 v2.1.1 h1:MXG9rzyvsrDBfa1a1GatvHjCrbmEug3hVt0rSOXipCw=
|
||||||
github.com/derision-test/go-mockgen/v2 v2.1.1/go.mod h1:cDK2Y9IF5roTJgugWV23IvlOJsllhDN5zxRDN+g4cZo=
|
github.com/derision-test/go-mockgen/v2 v2.1.1/go.mod h1:cDK2Y9IF5roTJgugWV23IvlOJsllhDN5zxRDN+g4cZo=
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||||
@@ -76,9 +74,6 @@ github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/
|
|||||||
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
|
||||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
|
||||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
|
||||||
github.com/editorconfig/editorconfig-core-go/v2 v2.6.3 h1:XVUp6qW3BIkmM3/1EkrHpa6bL56APOynfXcZEmIgOhs=
|
github.com/editorconfig/editorconfig-core-go/v2 v2.6.3 h1:XVUp6qW3BIkmM3/1EkrHpa6bL56APOynfXcZEmIgOhs=
|
||||||
github.com/editorconfig/editorconfig-core-go/v2 v2.6.3/go.mod h1:ThHVc+hqbUsmE1wmK/MASpQEhCleWu1JDJDNhUOMy0c=
|
github.com/editorconfig/editorconfig-core-go/v2 v2.6.3/go.mod h1:ThHVc+hqbUsmE1wmK/MASpQEhCleWu1JDJDNhUOMy0c=
|
||||||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||||
@@ -96,10 +91,8 @@ github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ
|
|||||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||||
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
||||||
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
|
||||||
github.com/go-ldap/ldap/v3 v3.4.11 h1:4k0Yxweg+a3OyBLjdYn5OKglv18JNvfDykSoI8bW0gU=
|
github.com/go-ldap/ldap/v3 v3.4.11 h1:4k0Yxweg+a3OyBLjdYn5OKglv18JNvfDykSoI8bW0gU=
|
||||||
github.com/go-ldap/ldap/v3 v3.4.11/go.mod h1:bY7t0FLK8OAVpp/vV6sSlpz3EQDGcQwc8pF0ujLgKvM=
|
github.com/go-ldap/ldap/v3 v3.4.11/go.mod h1:bY7t0FLK8OAVpp/vV6sSlpz3EQDGcQwc8pF0ujLgKvM=
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
|
||||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
||||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
@@ -128,14 +121,10 @@ github.com/go-macaron/toolbox v0.0.0-20190813233741-94defb8383c6/go.mod h1:YFNJ/
|
|||||||
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
||||||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||||
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
|
|
||||||
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||||
|
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y=
|
|
||||||
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
|
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
|
||||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/gogs/chardet v0.0.0-20150115103509-2404f7772561 h1:aBzukfDxQlCTVS0NBUjI5YA3iVeaZ9Tb5PxNrrIP1xs=
|
github.com/gogs/chardet v0.0.0-20150115103509-2404f7772561 h1:aBzukfDxQlCTVS0NBUjI5YA3iVeaZ9Tb5PxNrrIP1xs=
|
||||||
@@ -151,17 +140,16 @@ github.com/gogs/go-libravatar v0.0.0-20191106065024-33a75213d0a0/go.mod h1:Zas3B
|
|||||||
github.com/gogs/minwinsvc v0.0.0-20170301035411-95be6356811a h1:8DZwxETOVWIinYxDK+i6L+rMb7eGATGaakD6ZucfHVk=
|
github.com/gogs/minwinsvc v0.0.0-20170301035411-95be6356811a h1:8DZwxETOVWIinYxDK+i6L+rMb7eGATGaakD6ZucfHVk=
|
||||||
github.com/gogs/minwinsvc v0.0.0-20170301035411-95be6356811a/go.mod h1:TUIZ+29jodWQ8Gk6Pvtg4E09aMsc3C/VLZiVYfUhWQU=
|
github.com/gogs/minwinsvc v0.0.0-20170301035411-95be6356811a/go.mod h1:TUIZ+29jodWQ8Gk6Pvtg4E09aMsc3C/VLZiVYfUhWQU=
|
||||||
github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||||
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
|
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
|
||||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||||
github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188/go.mod h1:vXjM/+wXQnTPR4KqTKDgJukSZ6amVRtWMPEjE6sQoK8=
|
|
||||||
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
|
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
|
||||||
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
|
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
|
||||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
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.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
@@ -175,8 +163,6 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS
|
|||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/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.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.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.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
@@ -189,8 +175,6 @@ github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+u
|
|||||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
|
||||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
|
||||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
|
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
|
||||||
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||||
@@ -198,18 +182,14 @@ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
|
|||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
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/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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4=
|
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
|
||||||
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
|
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
|
||||||
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
|
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
|
||||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
|
||||||
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
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/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/hexops/autogold v1.3.1 h1:YgxF9OHWbEIUjhDbpnLhgVsjUDsiHDTyDfy2lrfdlzo=
|
github.com/hexops/autogold v1.3.1 h1:YgxF9OHWbEIUjhDbpnLhgVsjUDsiHDTyDfy2lrfdlzo=
|
||||||
github.com/hexops/autogold v1.3.1/go.mod h1:sQO+mQUCVfxOKPht+ipDSkJ2SCJ7BNJVHZexsXqWMx4=
|
github.com/hexops/autogold v1.3.1/go.mod h1:sQO+mQUCVfxOKPht+ipDSkJ2SCJ7BNJVHZexsXqWMx4=
|
||||||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||||
@@ -255,17 +235,13 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
|||||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
|
||||||
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
@@ -275,10 +251,7 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
|||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
|
||||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
|
|
||||||
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
|
||||||
github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de/go.mod h1:3q8WtuPQsoRbatJuy3nvq/hRSvuBJrHHr+ybPPiNvHQ=
|
github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de/go.mod h1:3q8WtuPQsoRbatJuy3nvq/hRSvuBJrHHr+ybPPiNvHQ=
|
||||||
github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af/go.mod h1:Cqz6pqow14VObJ7peltM+2n3PWOz7yTrfUuGbVFkzN0=
|
github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af/go.mod h1:Cqz6pqow14VObJ7peltM+2n3PWOz7yTrfUuGbVFkzN0=
|
||||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
@@ -298,16 +271,16 @@ github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh
|
|||||||
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||||
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||||
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||||
github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
|
github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs=
|
||||||
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
|
||||||
github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75/go.mod h1:76rfSfYPWj01Z85hUf/ituArm797mNKcvINh1OlsZKo=
|
github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75/go.mod h1:76rfSfYPWj01Z85hUf/ituArm797mNKcvINh1OlsZKo=
|
||||||
github.com/mcuadros/go-version v0.0.0-20190830083331-035f6764e8d2 h1:YocNLcTBdEdvY3iDK6jfWXvEaM5OCKkjxPKoJRdB3Gg=
|
github.com/mcuadros/go-version v0.0.0-20190830083331-035f6764e8d2 h1:YocNLcTBdEdvY3iDK6jfWXvEaM5OCKkjxPKoJRdB3Gg=
|
||||||
github.com/mcuadros/go-version v0.0.0-20190830083331-035f6764e8d2/go.mod h1:76rfSfYPWj01Z85hUf/ituArm797mNKcvINh1OlsZKo=
|
github.com/mcuadros/go-version v0.0.0-20190830083331-035f6764e8d2/go.mod h1:76rfSfYPWj01Z85hUf/ituArm797mNKcvINh1OlsZKo=
|
||||||
github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
|
github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
|
||||||
github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
|
github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
|
||||||
github.com/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE=
|
|
||||||
github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ=
|
github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ=
|
||||||
|
github.com/microsoft/go-mssqldb v1.8.2 h1:236sewazvC8FvG6Dr3bszrVhMkAl4KYImryLkRMCd0I=
|
||||||
|
github.com/microsoft/go-mssqldb v1.8.2/go.mod h1:vp38dT33FGfVotRiTmDo3bFyaHq+p3LektQrjTULowo=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
@@ -319,7 +292,6 @@ github.com/msteinert/pam v1.2.0 h1:mYfjlvN2KYs2Pb9G6nb/1f/nPfAttT/Jee5Sq9r3bGE=
|
|||||||
github.com/msteinert/pam v1.2.0/go.mod h1:d2n0DCUK8rGecChV3JzvmsDjOY4R7AYbsNxAT+ftQl0=
|
github.com/msteinert/pam v1.2.0/go.mod h1:d2n0DCUK8rGecChV3JzvmsDjOY4R7AYbsNxAT+ftQl0=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
|
||||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||||
@@ -349,17 +321,15 @@ github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAl
|
|||||||
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
|
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
|
||||||
github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
|
github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
|
||||||
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
|
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
|
||||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
|
||||||
github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
|
github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
|
||||||
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
|
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
|
||||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
|
||||||
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
|
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
|
||||||
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
|
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
|
||||||
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
|
|
||||||
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
|
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
|
||||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
||||||
|
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
||||||
|
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
||||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
@@ -367,22 +337,14 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
|||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/pquerna/otp v1.5.0 h1:NMMR+WrmaqXU4EzdGJEE1aUUI0AMRzsp96fFFWNPwxs=
|
github.com/pquerna/otp v1.5.0 h1:NMMR+WrmaqXU4EzdGJEE1aUUI0AMRzsp96fFFWNPwxs=
|
||||||
github.com/pquerna/otp v1.5.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
github.com/pquerna/otp v1.5.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
||||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
|
||||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
|
||||||
github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc=
|
github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc=
|
||||||
github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE=
|
github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE=
|
||||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
|
||||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
|
||||||
github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
|
github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
|
||||||
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
|
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
|
||||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
|
||||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
|
||||||
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
|
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
|
||||||
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
|
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||||
@@ -404,7 +366,6 @@ github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBf
|
|||||||
github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d/go.mod h1:vq0tzqLRu6TS7Id0wMo2N5QzJoKedVeovOpHjnykSzY=
|
github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d/go.mod h1:vq0tzqLRu6TS7Id0wMo2N5QzJoKedVeovOpHjnykSzY=
|
||||||
github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg=
|
github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg=
|
||||||
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
|
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w=
|
github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w=
|
||||||
@@ -418,11 +379,9 @@ github.com/sourcegraph/run v0.12.0/go.mod h1:PwaP936BTnAJC1cqR5rSbG5kOs/EWStTK3l
|
|||||||
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo=
|
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo=
|
||||||
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM=
|
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
@@ -448,11 +407,8 @@ github.com/urfave/cli v1.22.17 h1:SYzXoiPfQjHBbkYxbew5prZHS1TOLT3ierW8SYLqtVQ=
|
|||||||
github.com/urfave/cli v1.22.17/go.mod h1:b0ht0aqgH/6pBYzzxURyrM4xXNgsoT/n2ZzwQiEhNVo=
|
github.com/urfave/cli v1.22.17/go.mod h1:b0ht0aqgH/6pBYzzxURyrM4xXNgsoT/n2ZzwQiEhNVo=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
|
|
||||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
|
||||||
go.bobheadxi.dev/streamline v1.2.1 h1:IqKSA1TbeuDqCzYNAwtlh8sqf3tsQus8XgJdkCWFT8c=
|
go.bobheadxi.dev/streamline v1.2.1 h1:IqKSA1TbeuDqCzYNAwtlh8sqf3tsQus8XgJdkCWFT8c=
|
||||||
go.bobheadxi.dev/streamline v1.2.1/go.mod h1:yJsVXOSBFLgAKvsnf6WmIzmB2A65nWqkR/sRNxJPa74=
|
go.bobheadxi.dev/streamline v1.2.1/go.mod h1:yJsVXOSBFLgAKvsnf6WmIzmB2A65nWqkR/sRNxJPa74=
|
||||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
|
||||||
go.opentelemetry.io/otel v1.11.0 h1:kfToEGMDq6TrVrJ9Vht84Y8y9enykSZzDDZglV0kIEk=
|
go.opentelemetry.io/otel v1.11.0 h1:kfToEGMDq6TrVrJ9Vht84Y8y9enykSZzDDZglV0kIEk=
|
||||||
go.opentelemetry.io/otel v1.11.0/go.mod h1:H2KtuEphyMvlhZ+F7tg9GRhAOe60moNx61Ex+WmiKkk=
|
go.opentelemetry.io/otel v1.11.0/go.mod h1:H2KtuEphyMvlhZ+F7tg9GRhAOe60moNx61Ex+WmiKkk=
|
||||||
go.opentelemetry.io/otel/sdk v1.11.0 h1:ZnKIL9V9Ztaq+ME43IUi/eo22mNsb6a7tGfzaOWB5fo=
|
go.opentelemetry.io/otel/sdk v1.11.0 h1:ZnKIL9V9Ztaq+ME43IUi/eo22mNsb6a7tGfzaOWB5fo=
|
||||||
@@ -461,9 +417,7 @@ go.opentelemetry.io/otel/trace v1.11.0 h1:20U/Vj42SX+mASlXLmSGBg6jpI1jQtv682lZtT
|
|||||||
go.opentelemetry.io/otel/trace v1.11.0/go.mod h1:nyYjis9jy0gytE9LXGU+/m1sHTKbRY0fX0hulNNDP1U=
|
go.opentelemetry.io/otel/trace v1.11.0/go.mod h1:nyYjis9jy0gytE9LXGU+/m1sHTKbRY0fX0hulNNDP1U=
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
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-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
@@ -474,23 +428,13 @@ golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88/go.mod h1:IxCIyHEi3zRg3s0
|
|||||||
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
|
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
|
||||||
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
|
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
|
||||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
|
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
|
||||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
|
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
|
||||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
||||||
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
||||||
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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
@@ -501,28 +445,18 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/
|
|||||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||||
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
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=
|
|
||||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -557,19 +491,13 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX
|
|||||||
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
|
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
|
||||||
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
|
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
|
||||||
golang.org/x/text v0.3.0/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.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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/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.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
|
||||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
|
||||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20190802220118-1d1727260058/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
golang.org/x/tools v0.0.0-20190802220118-1d1727260058/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
||||||
@@ -583,17 +511,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
|||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
google.golang.org/appengine v1.6.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.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
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-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
@@ -606,7 +525,6 @@ google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9x
|
|||||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||||
gopkg.in/DATA-DOG/go-sqlmock.v2 v2.0.0-20180914054222-c19298f520d0 h1:/21c4hNFgj8A1D54vgJZwQlywp64/RUBHzlPdpy5h4s=
|
gopkg.in/DATA-DOG/go-sqlmock.v2 v2.0.0-20180914054222-c19298f520d0 h1:/21c4hNFgj8A1D54vgJZwQlywp64/RUBHzlPdpy5h4s=
|
||||||
gopkg.in/DATA-DOG/go-sqlmock.v2 v2.0.0-20180914054222-c19298f520d0/go.mod h1:0uueny64T996pN6bez2N3S8HWyPcpyfTPma8Wc1Awx4=
|
gopkg.in/DATA-DOG/go-sqlmock.v2 v2.0.0-20180914054222-c19298f520d0/go.mod h1:0uueny64T996pN6bez2N3S8HWyPcpyfTPma8Wc1Awx4=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
|
||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||||
gopkg.in/bufio.v1 v1.0.0-20140618132640-567b2bfa514e h1:wGA78yza6bu/mWcc4QfBuIEHEtc06xdiU0X8sY36yUU=
|
gopkg.in/bufio.v1 v1.0.0-20140618132640-567b2bfa514e h1:wGA78yza6bu/mWcc4QfBuIEHEtc06xdiU0X8sY36yUU=
|
||||||
@@ -656,9 +574,6 @@ gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
|
|||||||
gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
|
gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
|
||||||
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
|
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
|
||||||
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
modernc.org/cc/v4 v4.26.2 h1:991HMkLjJzYBIfha6ECZdjrIYz2/1ayr+FL8GN+CNzM=
|
modernc.org/cc/v4 v4.26.2 h1:991HMkLjJzYBIfha6ECZdjrIYz2/1ayr+FL8GN+CNzM=
|
||||||
modernc.org/cc/v4 v4.26.2/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
|
modernc.org/cc/v4 v4.26.2/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
|
||||||
modernc.org/ccgo/v4 v4.28.0 h1:rjznn6WWehKq7dG4JtLRKxb52Ecv8OUGah8+Z/SfpNU=
|
modernc.org/ccgo/v4 v4.28.0 h1:rjznn6WWehKq7dG4JtLRKxb52Ecv8OUGah8+Z/SfpNU=
|
||||||
@@ -689,9 +604,3 @@ mvdan.cc/gofumpt v0.4.0 h1:JVf4NN1mIpHogBj7ABpgOyZc65/UUOkKQFkoURsz4MM=
|
|||||||
mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ=
|
mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ=
|
||||||
unknwon.dev/clog/v2 v2.2.0 h1:jkPdsxux0MC04BT/9NHbT75z4prK92SH10VBNmIpVCc=
|
unknwon.dev/clog/v2 v2.2.0 h1:jkPdsxux0MC04BT/9NHbT75z4prK92SH10VBNmIpVCc=
|
||||||
unknwon.dev/clog/v2 v2.2.0/go.mod h1:zvUlyibDHI4mykYdWyWje2G9nF/nBzfDOqRo2my4mWc=
|
unknwon.dev/clog/v2 v2.2.0/go.mod h1:zvUlyibDHI4mykYdWyWje2G9nF/nBzfDOqRo2my4mWc=
|
||||||
xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8=
|
|
||||||
xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU=
|
|
||||||
xorm.io/core v0.7.2 h1:mEO22A2Z7a3fPaZMk6gKL/jMD80iiyNwRrX5HOv3XLw=
|
|
||||||
xorm.io/core v0.7.2/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM=
|
|
||||||
xorm.io/xorm v0.8.0 h1:iALxgJrX8O00f8Jk22GbZwPmxJNgssV5Mv4uc2HL9PM=
|
|
||||||
xorm.io/xorm v0.8.0/go.mod h1:ZkJLEYLoVyg7amJK/5r779bHyzs2AU8f8VMiP6BM7uY=
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
|
|
||||||
"github.com/cockroachdb/errors"
|
"github.com/cockroachdb/errors"
|
||||||
gouuid "github.com/satori/go.uuid"
|
gouuid "github.com/satori/go.uuid"
|
||||||
"xorm.io/xorm"
|
"gorm.io/gorm"
|
||||||
|
|
||||||
"gogs.io/gogs/internal/conf"
|
"gogs.io/gogs/internal/conf"
|
||||||
"gogs.io/gogs/internal/errutil"
|
"gogs.io/gogs/internal/errutil"
|
||||||
@@ -19,25 +19,26 @@ import (
|
|||||||
// Attachment represent a attachment of issue/comment/release.
|
// Attachment represent a attachment of issue/comment/release.
|
||||||
type Attachment struct {
|
type Attachment struct {
|
||||||
ID int64
|
ID int64
|
||||||
UUID string `xorm:"uuid UNIQUE"`
|
UUID string `gorm:"column:uuid;type:varchar(191);uniqueIndex"`
|
||||||
IssueID int64 `xorm:"INDEX"`
|
IssueID int64 `gorm:"index"`
|
||||||
CommentID int64
|
CommentID int64
|
||||||
ReleaseID int64 `xorm:"INDEX"`
|
ReleaseID int64 `gorm:"index"`
|
||||||
Name string
|
Name string
|
||||||
|
|
||||||
Created time.Time `xorm:"-" json:"-" gorm:"-"`
|
Created time.Time `gorm:"-" json:"-"`
|
||||||
CreatedUnix int64
|
CreatedUnix int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Attachment) BeforeInsert() {
|
func (a *Attachment) BeforeCreate(tx *gorm.DB) error {
|
||||||
a.CreatedUnix = time.Now().Unix()
|
if a.CreatedUnix == 0 {
|
||||||
|
a.CreatedUnix = tx.NowFunc().Unix()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Attachment) AfterSet(colName string, _ xorm.Cell) {
|
func (a *Attachment) AfterFind(tx *gorm.DB) error {
|
||||||
switch colName {
|
a.Created = time.Unix(a.CreatedUnix, 0).Local()
|
||||||
case "created_unix":
|
return nil
|
||||||
a.Created = time.Unix(a.CreatedUnix, 0).Local()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AttachmentLocalPath returns where attachment is stored in local file system based on given UUID.
|
// AttachmentLocalPath returns where attachment is stored in local file system based on given UUID.
|
||||||
@@ -74,7 +75,7 @@ func NewAttachment(name string, buf []byte, file multipart.File) (_ *Attachment,
|
|||||||
return nil, errors.Newf("copy: %v", err)
|
return nil, errors.Newf("copy: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := x.Insert(attach); err != nil {
|
if err := db.Create(attach).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,60 +101,60 @@ func (ErrAttachmentNotExist) NotFound() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAttachmentByUUID(e Engine, uuid string) (*Attachment, error) {
|
func getAttachmentByUUID(e *gorm.DB, uuid string) (*Attachment, error) {
|
||||||
attach := &Attachment{UUID: uuid}
|
attach := &Attachment{}
|
||||||
has, err := e.Get(attach)
|
err := e.Where("uuid = ?", uuid).First(attach).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, ErrAttachmentNotExist{args: map[string]any{"uuid": uuid}}
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
|
||||||
return nil, ErrAttachmentNotExist{args: map[string]any{"uuid": uuid}}
|
|
||||||
}
|
}
|
||||||
return attach, nil
|
return attach, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAttachmentsByUUIDs(e Engine, uuids []string) ([]*Attachment, error) {
|
func getAttachmentsByUUIDs(e *gorm.DB, uuids []string) ([]*Attachment, error) {
|
||||||
if len(uuids) == 0 {
|
if len(uuids) == 0 {
|
||||||
return []*Attachment{}, nil
|
return []*Attachment{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Silently drop invalid uuids.
|
|
||||||
attachments := make([]*Attachment, 0, len(uuids))
|
attachments := make([]*Attachment, 0, len(uuids))
|
||||||
return attachments, e.In("uuid", uuids).Find(&attachments)
|
return attachments, e.Where("uuid IN ?", uuids).Find(&attachments).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAttachmentByUUID returns attachment by given UUID.
|
// GetAttachmentByUUID returns attachment by given UUID.
|
||||||
func GetAttachmentByUUID(uuid string) (*Attachment, error) {
|
func GetAttachmentByUUID(uuid string) (*Attachment, error) {
|
||||||
return getAttachmentByUUID(x, uuid)
|
return getAttachmentByUUID(db, uuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAttachmentsByIssueID(e Engine, issueID int64) ([]*Attachment, error) {
|
func getAttachmentsByIssueID(e *gorm.DB, issueID int64) ([]*Attachment, error) {
|
||||||
attachments := make([]*Attachment, 0, 5)
|
attachments := make([]*Attachment, 0, 5)
|
||||||
return attachments, e.Where("issue_id = ? AND comment_id = 0", issueID).Find(&attachments)
|
return attachments, e.Where("issue_id = ? AND comment_id = 0", issueID).Find(&attachments).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAttachmentsByIssueID returns all attachments of an issue.
|
// GetAttachmentsByIssueID returns all attachments of an issue.
|
||||||
func GetAttachmentsByIssueID(issueID int64) ([]*Attachment, error) {
|
func GetAttachmentsByIssueID(issueID int64) ([]*Attachment, error) {
|
||||||
return getAttachmentsByIssueID(x, issueID)
|
return getAttachmentsByIssueID(db, issueID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAttachmentsByCommentID(e Engine, commentID int64) ([]*Attachment, error) {
|
func getAttachmentsByCommentID(e *gorm.DB, commentID int64) ([]*Attachment, error) {
|
||||||
attachments := make([]*Attachment, 0, 5)
|
attachments := make([]*Attachment, 0, 5)
|
||||||
return attachments, e.Where("comment_id=?", commentID).Find(&attachments)
|
return attachments, e.Where("comment_id = ?", commentID).Find(&attachments).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAttachmentsByCommentID returns all attachments of a comment.
|
// GetAttachmentsByCommentID returns all attachments of a comment.
|
||||||
func GetAttachmentsByCommentID(commentID int64) ([]*Attachment, error) {
|
func GetAttachmentsByCommentID(commentID int64) ([]*Attachment, error) {
|
||||||
return getAttachmentsByCommentID(x, commentID)
|
return getAttachmentsByCommentID(db, commentID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAttachmentsByReleaseID(e Engine, releaseID int64) ([]*Attachment, error) {
|
func getAttachmentsByReleaseID(e *gorm.DB, releaseID int64) ([]*Attachment, error) {
|
||||||
attachments := make([]*Attachment, 0, 10)
|
attachments := make([]*Attachment, 0, 10)
|
||||||
return attachments, e.Where("release_id = ?", releaseID).Find(&attachments)
|
return attachments, e.Where("release_id = ?", releaseID).Find(&attachments).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAttachmentsByReleaseID returns all attachments of a release.
|
// GetAttachmentsByReleaseID returns all attachments of a release.
|
||||||
func GetAttachmentsByReleaseID(releaseID int64) ([]*Attachment, error) {
|
func GetAttachmentsByReleaseID(releaseID int64) ([]*Attachment, error) {
|
||||||
return getAttachmentsByReleaseID(x, releaseID)
|
return getAttachmentsByReleaseID(db, releaseID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteAttachment deletes the given attachment and optionally the associated file.
|
// DeleteAttachment deletes the given attachment and optionally the associated file.
|
||||||
@@ -171,7 +172,7 @@ func DeleteAttachments(attachments []*Attachment, remove bool) (int, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := x.Delete(a); err != nil {
|
if err := db.Delete(a).Error; err != nil {
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ import (
|
|||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"gorm.io/gorm/schema"
|
"gorm.io/gorm/schema"
|
||||||
log "unknwon.dev/clog/v2"
|
log "unknwon.dev/clog/v2"
|
||||||
"xorm.io/core"
|
|
||||||
"xorm.io/xorm"
|
|
||||||
|
|
||||||
"gogs.io/gogs/internal/conf"
|
"gogs.io/gogs/internal/conf"
|
||||||
"gogs.io/gogs/internal/osutil"
|
"gogs.io/gogs/internal/osutil"
|
||||||
@@ -122,19 +120,19 @@ func dumpLegacyTables(ctx context.Context, dirPath string, verbose bool) error {
|
|||||||
log.Trace("Dumping table %q...", tableName)
|
log.Trace("Dumping table %q...", tableName)
|
||||||
}
|
}
|
||||||
|
|
||||||
tableFile := filepath.Join(dirPath, tableName+".json")
|
err := func() error {
|
||||||
f, err := os.Create(tableFile)
|
tableFile := filepath.Join(dirPath, tableName+".json")
|
||||||
if err != nil {
|
f, err := os.Create(tableFile)
|
||||||
return errors.Newf("create JSON file: %v", err)
|
if err != nil {
|
||||||
}
|
return errors.Wrap(err, "create JSON file")
|
||||||
|
}
|
||||||
|
defer func() { _ = f.Close() }()
|
||||||
|
|
||||||
if err = x.Context(ctx).Asc("id").Iterate(table, func(idx int, bean any) (err error) {
|
return dumpTable(ctx, db, table, f)
|
||||||
return jsoniter.NewEncoder(f).Encode(bean)
|
}()
|
||||||
}); err != nil {
|
if err != nil {
|
||||||
_ = f.Close()
|
return errors.Wrapf(err, "dump table %q", tableName)
|
||||||
return errors.Newf("dump table '%s': %v", tableName, err)
|
|
||||||
}
|
}
|
||||||
_ = f.Close()
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -229,8 +227,6 @@ func importTable(ctx context.Context, db *gorm.DB, table any, r io.Reader) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
func importLegacyTables(ctx context.Context, dirPath string, verbose bool) error {
|
func importLegacyTables(ctx context.Context, dirPath string, verbose bool) error {
|
||||||
snakeMapper := core.SnakeMapper{}
|
|
||||||
|
|
||||||
skipInsertProcessors := map[string]bool{
|
skipInsertProcessors := map[string]bool{
|
||||||
"mirror": true,
|
"mirror": true,
|
||||||
"milestone": true,
|
"milestone": true,
|
||||||
@@ -255,9 +251,9 @@ func importLegacyTables(ctx context.Context, dirPath string, verbose bool) error
|
|||||||
log.Trace("Importing table %q...", tableName)
|
log.Trace("Importing table %q...", tableName)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := x.DropTables(table); err != nil {
|
if err := db.WithContext(ctx).Migrator().DropTable(table); err != nil {
|
||||||
return errors.Newf("drop table %q: %v", tableName, err)
|
return errors.Newf("drop table %q: %v", tableName, err)
|
||||||
} else if err = x.Sync2(table); err != nil {
|
} else if err = db.WithContext(ctx).Migrator().AutoMigrate(table); err != nil {
|
||||||
return errors.Newf("sync table %q: %v", tableName, err)
|
return errors.Newf("sync table %q: %v", tableName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,16 +261,28 @@ func importLegacyTables(ctx context.Context, dirPath string, verbose bool) error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Newf("open JSON file: %v", err)
|
return errors.Newf("open JSON file: %v", err)
|
||||||
}
|
}
|
||||||
rawTableName := x.TableName(table)
|
|
||||||
_, isInsertProcessor := table.(xorm.BeforeInsertProcessor)
|
s, err := schema.Parse(table, &sync.Map{}, db.NamingStrategy)
|
||||||
|
if err != nil {
|
||||||
|
_ = f.Close()
|
||||||
|
return errors.Wrap(err, "parse schema")
|
||||||
|
}
|
||||||
|
rawTableName := s.Table
|
||||||
|
|
||||||
|
_, isInsertProcessor := table.(interface{ BeforeCreate(*gorm.DB) error })
|
||||||
scanner := bufio.NewScanner(f)
|
scanner := bufio.NewScanner(f)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
if err = jsoniter.Unmarshal(scanner.Bytes(), table); err != nil {
|
// PostgreSQL does not like the null characters (U+0000)
|
||||||
|
cleaned := bytes.ReplaceAll(scanner.Bytes(), []byte("\\u0000"), []byte(""))
|
||||||
|
|
||||||
|
if err = jsoniter.Unmarshal(cleaned, table); err != nil {
|
||||||
|
_ = f.Close()
|
||||||
return errors.Newf("unmarshal to struct: %v", err)
|
return errors.Newf("unmarshal to struct: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = x.Insert(table); err != nil {
|
if err = db.WithContext(ctx).Create(table).Error; err != nil {
|
||||||
return errors.Newf("insert strcut: %v", err)
|
_ = f.Close()
|
||||||
|
return errors.Newf("insert struct: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var meta struct {
|
var meta struct {
|
||||||
@@ -283,30 +291,30 @@ func importLegacyTables(ctx context.Context, dirPath string, verbose bool) error
|
|||||||
DeadlineUnix int64
|
DeadlineUnix int64
|
||||||
ClosedDateUnix int64
|
ClosedDateUnix int64
|
||||||
}
|
}
|
||||||
if err = jsoniter.Unmarshal(scanner.Bytes(), &meta); err != nil {
|
if err = jsoniter.Unmarshal(cleaned, &meta); err != nil {
|
||||||
log.Error("Failed to unmarshal to map: %v", err)
|
log.Error("Failed to unmarshal to map: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset created_unix back to the date save in archive because Insert method updates its value
|
// Reset created_unix back to the date saved in archive because Create method updates its value
|
||||||
if isInsertProcessor && !skipInsertProcessors[rawTableName] {
|
if isInsertProcessor && !skipInsertProcessors[rawTableName] {
|
||||||
if _, err = x.Exec("UPDATE `"+rawTableName+"` SET created_unix=? WHERE id=?", meta.CreatedUnix, meta.ID); err != nil {
|
if err = db.WithContext(ctx).Exec("UPDATE `"+rawTableName+"` SET created_unix=? WHERE id=?", meta.CreatedUnix, meta.ID).Error; err != nil {
|
||||||
log.Error("Failed to reset '%s.created_unix': %v", rawTableName, err)
|
log.Error("Failed to reset '%s.created_unix': %v", rawTableName, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch rawTableName {
|
switch rawTableName {
|
||||||
case "milestone":
|
case "milestone":
|
||||||
if _, err = x.Exec("UPDATE `"+rawTableName+"` SET deadline_unix=?, closed_date_unix=? WHERE id=?", meta.DeadlineUnix, meta.ClosedDateUnix, meta.ID); err != nil {
|
if err = db.WithContext(ctx).Exec("UPDATE `"+rawTableName+"` SET deadline_unix=?, closed_date_unix=? WHERE id=?", meta.DeadlineUnix, meta.ClosedDateUnix, meta.ID).Error; err != nil {
|
||||||
log.Error("Failed to reset 'milestone.deadline_unix', 'milestone.closed_date_unix': %v", err)
|
log.Error("Failed to reset 'milestone.deadline_unix', 'milestone.closed_date_unix': %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ = f.Close()
|
||||||
|
|
||||||
// PostgreSQL needs manually reset table sequence for auto increment keys
|
// PostgreSQL needs manually reset table sequence for auto increment keys
|
||||||
if conf.UsePostgreSQL {
|
if conf.UsePostgreSQL {
|
||||||
rawTableName := snakeMapper.Obj2Table(tableName)
|
|
||||||
seqName := rawTableName + "_id_seq"
|
seqName := rawTableName + "_id_seq"
|
||||||
if _, err = x.Exec(fmt.Sprintf(`SELECT setval('%s', COALESCE((SELECT MAX(id)+1 FROM "%s"), 1), false);`, seqName, rawTableName)); err != nil {
|
if err = db.WithContext(ctx).Exec(fmt.Sprintf(`SELECT setval('%s', COALESCE((SELECT MAX(id)+1 FROM "%s"), 1), false);`, seqName, rawTableName)).Error; err != nil {
|
||||||
return errors.Newf("reset table %q' sequence: %v", rawTableName, err)
|
return errors.Newf("reset table %q' sequence: %v", rawTableName, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,10 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cockroachdb/errors"
|
"github.com/cockroachdb/errors"
|
||||||
"github.com/unknwon/com"
|
|
||||||
log "unknwon.dev/clog/v2"
|
|
||||||
"xorm.io/xorm"
|
|
||||||
|
|
||||||
api "github.com/gogs/go-gogs-client"
|
api "github.com/gogs/go-gogs-client"
|
||||||
|
"github.com/unknwon/com"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
log "unknwon.dev/clog/v2"
|
||||||
|
|
||||||
"gogs.io/gogs/internal/errutil"
|
"gogs.io/gogs/internal/errutil"
|
||||||
"gogs.io/gogs/internal/markup"
|
"gogs.io/gogs/internal/markup"
|
||||||
@@ -50,47 +49,50 @@ type Comment struct {
|
|||||||
ID int64
|
ID int64
|
||||||
Type CommentType
|
Type CommentType
|
||||||
PosterID int64
|
PosterID int64
|
||||||
Poster *User `xorm:"-" json:"-" gorm:"-"`
|
Poster *User `gorm:"-" json:"-"`
|
||||||
IssueID int64 `xorm:"INDEX"`
|
IssueID int64 `gorm:"index"`
|
||||||
Issue *Issue `xorm:"-" json:"-" gorm:"-"`
|
Issue *Issue `gorm:"-" json:"-"`
|
||||||
CommitID int64
|
CommitID int64
|
||||||
Line int64
|
Line int64
|
||||||
Content string `xorm:"TEXT"`
|
Content string `gorm:"type:text"`
|
||||||
RenderedContent string `xorm:"-" json:"-" gorm:"-"`
|
RenderedContent string `gorm:"-" json:"-"`
|
||||||
|
|
||||||
Created time.Time `xorm:"-" json:"-" gorm:"-"`
|
Created time.Time `gorm:"-" json:"-"`
|
||||||
CreatedUnix int64
|
CreatedUnix int64
|
||||||
Updated time.Time `xorm:"-" json:"-" gorm:"-"`
|
Updated time.Time `gorm:"-" json:"-"`
|
||||||
UpdatedUnix int64
|
UpdatedUnix int64
|
||||||
|
|
||||||
// Reference issue in commit message
|
// Reference issue in commit message
|
||||||
CommitSHA string `xorm:"VARCHAR(40)"`
|
CommitSHA string `gorm:"type:varchar(40)"`
|
||||||
|
|
||||||
Attachments []*Attachment `xorm:"-" json:"-" gorm:"-"`
|
Attachments []*Attachment `gorm:"-" json:"-"`
|
||||||
|
|
||||||
// For view issue page.
|
// For view issue page.
|
||||||
ShowTag CommentTag `xorm:"-" json:"-" gorm:"-"`
|
ShowTag CommentTag `gorm:"-" json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Comment) BeforeInsert() {
|
func (c *Comment) BeforeCreate(tx *gorm.DB) error {
|
||||||
c.CreatedUnix = time.Now().Unix()
|
if c.CreatedUnix == 0 {
|
||||||
c.UpdatedUnix = c.CreatedUnix
|
c.CreatedUnix = tx.NowFunc().Unix()
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Comment) BeforeUpdate() {
|
|
||||||
c.UpdatedUnix = time.Now().Unix()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Comment) AfterSet(colName string, _ xorm.Cell) {
|
|
||||||
switch colName {
|
|
||||||
case "created_unix":
|
|
||||||
c.Created = time.Unix(c.CreatedUnix, 0).Local()
|
|
||||||
case "updated_unix":
|
|
||||||
c.Updated = time.Unix(c.UpdatedUnix, 0).Local()
|
|
||||||
}
|
}
|
||||||
|
if c.UpdatedUnix == 0 {
|
||||||
|
c.UpdatedUnix = c.CreatedUnix
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Comment) loadAttributes(e Engine) (err error) {
|
func (c *Comment) BeforeUpdate(tx *gorm.DB) error {
|
||||||
|
c.UpdatedUnix = tx.NowFunc().Unix()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Comment) AfterFind(tx *gorm.DB) error {
|
||||||
|
c.Created = time.Unix(c.CreatedUnix, 0).Local()
|
||||||
|
c.Updated = time.Unix(c.UpdatedUnix, 0).Local()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Comment) loadAttributes(tx *gorm.DB) (err error) {
|
||||||
if c.Poster == nil {
|
if c.Poster == nil {
|
||||||
c.Poster, err = Handle.Users().GetByID(context.TODO(), c.PosterID)
|
c.Poster, err = Handle.Users().GetByID(context.TODO(), c.PosterID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -104,12 +106,12 @@ func (c *Comment) loadAttributes(e Engine) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if c.Issue == nil {
|
if c.Issue == nil {
|
||||||
c.Issue, err = getRawIssueByID(e, c.IssueID)
|
c.Issue, err = getRawIssueByID(tx, c.IssueID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Newf("getIssueByID [%d]: %v", c.IssueID, err)
|
return errors.Newf("getIssueByID [%d]: %v", c.IssueID, err)
|
||||||
}
|
}
|
||||||
if c.Issue.Repo == nil {
|
if c.Issue.Repo == nil {
|
||||||
c.Issue.Repo, err = getRepositoryByID(e, c.Issue.RepoID)
|
c.Issue.Repo, err = getRepositoryByID(tx, c.Issue.RepoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Newf("getRepositoryByID [%d]: %v", c.Issue.RepoID, err)
|
return errors.Newf("getRepositoryByID [%d]: %v", c.Issue.RepoID, err)
|
||||||
}
|
}
|
||||||
@@ -117,7 +119,7 @@ func (c *Comment) loadAttributes(e Engine) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if c.Attachments == nil {
|
if c.Attachments == nil {
|
||||||
c.Attachments, err = getAttachmentsByCommentID(e, c.ID)
|
c.Attachments, err = getAttachmentsByCommentID(tx, c.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Newf("getAttachmentsByCommentID [%d]: %v", c.ID, err)
|
return errors.Newf("getAttachmentsByCommentID [%d]: %v", c.ID, err)
|
||||||
}
|
}
|
||||||
@@ -127,7 +129,7 @@ func (c *Comment) loadAttributes(e Engine) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Comment) LoadAttributes() error {
|
func (c *Comment) LoadAttributes() error {
|
||||||
return c.loadAttributes(x)
|
return c.loadAttributes(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Comment) HTMLURL() string {
|
func (c *Comment) HTMLURL() string {
|
||||||
@@ -163,9 +165,9 @@ func (c *Comment) EventTag() string {
|
|||||||
|
|
||||||
// mailParticipants sends new comment emails to repository watchers
|
// mailParticipants sends new comment emails to repository watchers
|
||||||
// and mentioned people.
|
// and mentioned people.
|
||||||
func (c *Comment) mailParticipants(e Engine, opType ActionType, issue *Issue) (err error) {
|
func (c *Comment) mailParticipants(tx *gorm.DB, opType ActionType, issue *Issue) (err error) {
|
||||||
mentions := markup.FindAllMentions(c.Content)
|
mentions := markup.FindAllMentions(c.Content)
|
||||||
if err = updateIssueMentions(e, c.IssueID, mentions); err != nil {
|
if err = updateIssueMentions(tx, c.IssueID, mentions); err != nil {
|
||||||
return errors.Newf("UpdateIssueMentions [%d]: %v", c.IssueID, err)
|
return errors.Newf("UpdateIssueMentions [%d]: %v", c.IssueID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,7 +186,7 @@ func (c *Comment) mailParticipants(e Engine, opType ActionType, issue *Issue) (e
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err error) {
|
func createComment(tx *gorm.DB, opts *CreateCommentOptions) (_ *Comment, err error) {
|
||||||
comment := &Comment{
|
comment := &Comment{
|
||||||
Type: opts.Type,
|
Type: opts.Type,
|
||||||
PosterID: opts.Doer.ID,
|
PosterID: opts.Doer.ID,
|
||||||
@@ -195,7 +197,7 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err
|
|||||||
Line: opts.LineNum,
|
Line: opts.LineNum,
|
||||||
Content: opts.Content,
|
Content: opts.Content,
|
||||||
}
|
}
|
||||||
if _, err = e.Insert(comment); err != nil {
|
if err = tx.Create(comment).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,14 +218,14 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err
|
|||||||
case CommentTypeComment:
|
case CommentTypeComment:
|
||||||
act.OpType = ActionCommentIssue
|
act.OpType = ActionCommentIssue
|
||||||
|
|
||||||
if _, err = e.Exec("UPDATE `issue` SET num_comments=num_comments+1 WHERE id=?", opts.Issue.ID); err != nil {
|
if err = tx.Exec("UPDATE `issue` SET num_comments=num_comments+1 WHERE id=?", opts.Issue.ID).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check attachments
|
// Check attachments
|
||||||
attachments := make([]*Attachment, 0, len(opts.Attachments))
|
attachments := make([]*Attachment, 0, len(opts.Attachments))
|
||||||
for _, uuid := range opts.Attachments {
|
for _, uuid := range opts.Attachments {
|
||||||
attach, err := getAttachmentByUUID(e, uuid)
|
attach, err := getAttachmentByUUID(tx, uuid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if IsErrAttachmentNotExist(err) {
|
if IsErrAttachmentNotExist(err) {
|
||||||
continue
|
continue
|
||||||
@@ -236,8 +238,10 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err
|
|||||||
for i := range attachments {
|
for i := range attachments {
|
||||||
attachments[i].IssueID = opts.Issue.ID
|
attachments[i].IssueID = opts.Issue.ID
|
||||||
attachments[i].CommentID = comment.ID
|
attachments[i].CommentID = comment.ID
|
||||||
// No assign value could be 0, so ignore AllCols().
|
if err = tx.Model(attachments[i]).Where("id = ?", attachments[i].ID).Updates(map[string]any{
|
||||||
if _, err = e.ID(attachments[i].ID).Update(attachments[i]); err != nil {
|
"issue_id": attachments[i].IssueID,
|
||||||
|
"comment_id": attachments[i].CommentID,
|
||||||
|
}).Error; err != nil {
|
||||||
return nil, errors.Newf("update attachment [%d]: %v", attachments[i].ID, err)
|
return nil, errors.Newf("update attachment [%d]: %v", attachments[i].ID, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -249,9 +253,9 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err
|
|||||||
}
|
}
|
||||||
|
|
||||||
if opts.Issue.IsPull {
|
if opts.Issue.IsPull {
|
||||||
_, err = e.Exec("UPDATE `repository` SET num_closed_pulls=num_closed_pulls-1 WHERE id=?", opts.Repo.ID)
|
err = tx.Exec("UPDATE `repository` SET num_closed_pulls=num_closed_pulls-1 WHERE id=?", opts.Repo.ID).Error
|
||||||
} else {
|
} else {
|
||||||
_, err = e.Exec("UPDATE `repository` SET num_closed_issues=num_closed_issues-1 WHERE id=?", opts.Repo.ID)
|
err = tx.Exec("UPDATE `repository` SET num_closed_issues=num_closed_issues-1 WHERE id=?", opts.Repo.ID).Error
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -264,38 +268,38 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err
|
|||||||
}
|
}
|
||||||
|
|
||||||
if opts.Issue.IsPull {
|
if opts.Issue.IsPull {
|
||||||
_, err = e.Exec("UPDATE `repository` SET num_closed_pulls=num_closed_pulls+1 WHERE id=?", opts.Repo.ID)
|
err = tx.Exec("UPDATE `repository` SET num_closed_pulls=num_closed_pulls+1 WHERE id=?", opts.Repo.ID).Error
|
||||||
} else {
|
} else {
|
||||||
_, err = e.Exec("UPDATE `repository` SET num_closed_issues=num_closed_issues+1 WHERE id=?", opts.Repo.ID)
|
err = tx.Exec("UPDATE `repository` SET num_closed_issues=num_closed_issues+1 WHERE id=?", opts.Repo.ID).Error
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = e.Exec("UPDATE `issue` SET updated_unix = ? WHERE id = ?", time.Now().Unix(), opts.Issue.ID); err != nil {
|
if err = tx.Exec("UPDATE `issue` SET updated_unix = ? WHERE id = ?", tx.NowFunc().Unix(), opts.Issue.ID).Error; err != nil {
|
||||||
return nil, errors.Newf("update issue 'updated_unix': %v", err)
|
return nil, errors.Newf("update issue 'updated_unix': %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify watchers for whatever action comes in, ignore if no action type.
|
// Notify watchers for whatever action comes in, ignore if no action type.
|
||||||
if act.OpType > 0 {
|
if act.OpType > 0 {
|
||||||
if err = notifyWatchers(e, act); err != nil {
|
if err = notifyWatchers(tx, act); err != nil {
|
||||||
log.Error("notifyWatchers: %v", err)
|
log.Error("notifyWatchers: %v", err)
|
||||||
}
|
}
|
||||||
if err = comment.mailParticipants(e, act.OpType, opts.Issue); err != nil {
|
if err = comment.mailParticipants(tx, act.OpType, opts.Issue); err != nil {
|
||||||
log.Error("MailParticipants: %v", err)
|
log.Error("MailParticipants: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return comment, comment.loadAttributes(e)
|
return comment, comment.loadAttributes(tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createStatusComment(e *xorm.Session, doer *User, repo *Repository, issue *Issue) (*Comment, error) {
|
func createStatusComment(tx *gorm.DB, doer *User, repo *Repository, issue *Issue) (*Comment, error) {
|
||||||
cmtType := CommentTypeClose
|
cmtType := CommentTypeClose
|
||||||
if !issue.IsClosed {
|
if !issue.IsClosed {
|
||||||
cmtType = CommentTypeReopen
|
cmtType = CommentTypeReopen
|
||||||
}
|
}
|
||||||
return createComment(e, &CreateCommentOptions{
|
return createComment(tx, &CreateCommentOptions{
|
||||||
Type: cmtType,
|
Type: cmtType,
|
||||||
Doer: doer,
|
Doer: doer,
|
||||||
Repo: repo,
|
Repo: repo,
|
||||||
@@ -318,18 +322,12 @@ type CreateCommentOptions struct {
|
|||||||
|
|
||||||
// CreateComment creates comment of issue or commit.
|
// CreateComment creates comment of issue or commit.
|
||||||
func CreateComment(opts *CreateCommentOptions) (comment *Comment, err error) {
|
func CreateComment(opts *CreateCommentOptions) (comment *Comment, err error) {
|
||||||
sess := x.NewSession()
|
err = db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
var err error
|
||||||
if err = sess.Begin(); err != nil {
|
comment, err = createComment(tx, opts)
|
||||||
return nil, err
|
return err
|
||||||
}
|
})
|
||||||
|
return comment, err
|
||||||
comment, err = createComment(sess, opts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return comment, sess.Commit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateIssueComment creates a plain issue comment.
|
// CreateIssueComment creates a plain issue comment.
|
||||||
@@ -367,14 +365,12 @@ func CreateRefComment(doer *User, repo *Repository, issue *Issue, content, commi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if same reference from same commit has already existed.
|
// Check if same reference from same commit has already existed.
|
||||||
has, err := x.Get(&Comment{
|
var count int64
|
||||||
Type: CommentTypeCommitRef,
|
err := db.Model(new(Comment)).Where("type = ? AND issue_id = ? AND commit_sha = ?",
|
||||||
IssueID: issue.ID,
|
CommentTypeCommitRef, issue.ID, commitSHA).Count(&count).Error
|
||||||
CommitSHA: commitSHA,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Newf("check reference comment: %v", err)
|
return errors.Newf("check reference comment: %v", err)
|
||||||
} else if has {
|
} else if count > 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -411,19 +407,20 @@ func (ErrCommentNotExist) NotFound() bool {
|
|||||||
// GetCommentByID returns the comment by given ID.
|
// GetCommentByID returns the comment by given ID.
|
||||||
func GetCommentByID(id int64) (*Comment, error) {
|
func GetCommentByID(id int64) (*Comment, error) {
|
||||||
c := new(Comment)
|
c := new(Comment)
|
||||||
has, err := x.Id(id).Get(c)
|
err := db.Where("id = ?", id).First(c).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, ErrCommentNotExist{args: map[string]any{"commentID": id}}
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
|
||||||
return nil, ErrCommentNotExist{args: map[string]any{"commentID": id}}
|
|
||||||
}
|
}
|
||||||
return c, c.LoadAttributes()
|
return c, c.LoadAttributes()
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: use CommentList to improve performance.
|
// FIXME: use CommentList to improve performance.
|
||||||
func loadCommentsAttributes(e Engine, comments []*Comment) (err error) {
|
func loadCommentsAttributes(tx *gorm.DB, comments []*Comment) (err error) {
|
||||||
for i := range comments {
|
for i := range comments {
|
||||||
if err = comments[i].loadAttributes(e); err != nil {
|
if err = comments[i].loadAttributes(tx); err != nil {
|
||||||
return errors.Newf("loadAttributes [%d]: %v", comments[i].ID, err)
|
return errors.Newf("loadAttributes [%d]: %v", comments[i].ID, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -431,53 +428,55 @@ func loadCommentsAttributes(e Engine, comments []*Comment) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCommentsByIssueIDSince(e Engine, issueID, since int64) ([]*Comment, error) {
|
func getCommentsByIssueIDSince(tx *gorm.DB, issueID, since int64) ([]*Comment, error) {
|
||||||
comments := make([]*Comment, 0, 10)
|
comments := make([]*Comment, 0, 10)
|
||||||
sess := e.Where("issue_id = ?", issueID).Asc("created_unix")
|
query := tx.Where("issue_id = ?", issueID).Order("created_unix ASC")
|
||||||
if since > 0 {
|
if since > 0 {
|
||||||
sess.And("updated_unix >= ?", since)
|
query = query.Where("updated_unix >= ?", since)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := sess.Find(&comments); err != nil {
|
if err := query.Find(&comments).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return comments, loadCommentsAttributes(e, comments)
|
return comments, loadCommentsAttributes(tx, comments)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCommentsByRepoIDSince(e Engine, repoID, since int64) ([]*Comment, error) {
|
func getCommentsByRepoIDSince(tx *gorm.DB, repoID, since int64) ([]*Comment, error) {
|
||||||
comments := make([]*Comment, 0, 10)
|
comments := make([]*Comment, 0, 10)
|
||||||
sess := e.Where("issue.repo_id = ?", repoID).Join("INNER", "issue", "issue.id = comment.issue_id").Asc("comment.created_unix")
|
query := tx.Joins("INNER JOIN issue ON issue.id = comment.issue_id").
|
||||||
|
Where("issue.repo_id = ?", repoID).
|
||||||
|
Order("comment.created_unix ASC")
|
||||||
if since > 0 {
|
if since > 0 {
|
||||||
sess.And("comment.updated_unix >= ?", since)
|
query = query.Where("comment.updated_unix >= ?", since)
|
||||||
}
|
}
|
||||||
if err := sess.Find(&comments); err != nil {
|
if err := query.Find(&comments).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return comments, loadCommentsAttributes(e, comments)
|
return comments, loadCommentsAttributes(tx, comments)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCommentsByIssueID(e Engine, issueID int64) ([]*Comment, error) {
|
func getCommentsByIssueID(tx *gorm.DB, issueID int64) ([]*Comment, error) {
|
||||||
return getCommentsByIssueIDSince(e, issueID, -1)
|
return getCommentsByIssueIDSince(tx, issueID, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCommentsByIssueID returns all comments of an issue.
|
// GetCommentsByIssueID returns all comments of an issue.
|
||||||
func GetCommentsByIssueID(issueID int64) ([]*Comment, error) {
|
func GetCommentsByIssueID(issueID int64) ([]*Comment, error) {
|
||||||
return getCommentsByIssueID(x, issueID)
|
return getCommentsByIssueID(db, issueID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCommentsByIssueIDSince returns a list of comments of an issue since a given time point.
|
// GetCommentsByIssueIDSince returns a list of comments of an issue since a given time point.
|
||||||
func GetCommentsByIssueIDSince(issueID, since int64) ([]*Comment, error) {
|
func GetCommentsByIssueIDSince(issueID, since int64) ([]*Comment, error) {
|
||||||
return getCommentsByIssueIDSince(x, issueID, since)
|
return getCommentsByIssueIDSince(db, issueID, since)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCommentsByRepoIDSince returns a list of comments for all issues in a repo since a given time point.
|
// GetCommentsByRepoIDSince returns a list of comments for all issues in a repo since a given time point.
|
||||||
func GetCommentsByRepoIDSince(repoID, since int64) ([]*Comment, error) {
|
func GetCommentsByRepoIDSince(repoID, since int64) ([]*Comment, error) {
|
||||||
return getCommentsByRepoIDSince(x, repoID, since)
|
return getCommentsByRepoIDSince(db, repoID, since)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateComment updates information of comment.
|
// UpdateComment updates information of comment.
|
||||||
func UpdateComment(doer *User, c *Comment, oldContent string) (err error) {
|
func UpdateComment(doer *User, c *Comment, oldContent string) (err error) {
|
||||||
if _, err = x.Id(c.ID).AllCols().Update(c); err != nil {
|
if err = db.Model(c).Where("id = ?", c.ID).Updates(c).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -511,24 +510,21 @@ func DeleteCommentByID(doer *User, id int64) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
err = db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
if err := tx.Where("id = ?", comment.ID).Delete(new(Comment)).Error; err != nil {
|
||||||
if err = sess.Begin(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = sess.ID(comment.ID).Delete(new(Comment)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if comment.Type == CommentTypeComment {
|
|
||||||
if _, err = sess.Exec("UPDATE `issue` SET num_comments = num_comments - 1 WHERE id = ?", comment.IssueID); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if err = sess.Commit(); err != nil {
|
if comment.Type == CommentTypeComment {
|
||||||
return errors.Newf("commit: %v", err)
|
if err := tx.Exec("UPDATE `issue` SET num_comments = num_comments - 1 WHERE id = ?", comment.IssueID).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return errors.Newf("transaction: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = DeleteAttachmentsByComment(comment.ID, true)
|
_, err = DeleteAttachmentsByComment(comment.ID, true)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -6,14 +6,12 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"xorm.io/xorm"
|
|
||||||
|
|
||||||
"github.com/cockroachdb/errors"
|
"github.com/cockroachdb/errors"
|
||||||
api "github.com/gogs/go-gogs-client"
|
api "github.com/gogs/go-gogs-client"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
"gogs.io/gogs/internal/errutil"
|
"gogs.io/gogs/internal/errutil"
|
||||||
"gogs.io/gogs/internal/lazyregexp"
|
"gogs.io/gogs/internal/lazyregexp"
|
||||||
"gogs.io/gogs/internal/tool"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var labelColorPattern = lazyregexp.New("#([a-fA-F0-9]{6})")
|
var labelColorPattern = lazyregexp.New("#([a-fA-F0-9]{6})")
|
||||||
@@ -53,13 +51,13 @@ func GetLabelTemplateFile(name string) ([][2]string, error) {
|
|||||||
// Label represents a label of repository for issues.
|
// Label represents a label of repository for issues.
|
||||||
type Label struct {
|
type Label struct {
|
||||||
ID int64
|
ID int64
|
||||||
RepoID int64 `xorm:"INDEX"`
|
RepoID int64 `gorm:"index"`
|
||||||
Name string
|
Name string
|
||||||
Color string `xorm:"VARCHAR(7)"`
|
Color string `gorm:"type:varchar(7)"`
|
||||||
NumIssues int
|
NumIssues int
|
||||||
NumClosedIssues int
|
NumClosedIssues int
|
||||||
NumOpenIssues int `xorm:"-" json:"-" gorm:"-"`
|
NumOpenIssues int `gorm:"-" json:"-"`
|
||||||
IsChecked bool `xorm:"-" json:"-" gorm:"-"`
|
IsChecked bool `gorm:"-" json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Label) APIFormat() *api.Label {
|
func (l *Label) APIFormat() *api.Label {
|
||||||
@@ -97,8 +95,7 @@ func (l *Label) ForegroundColor() template.CSS {
|
|||||||
|
|
||||||
// NewLabels creates new label(s) for a repository.
|
// NewLabels creates new label(s) for a repository.
|
||||||
func NewLabels(labels ...*Label) error {
|
func NewLabels(labels ...*Label) error {
|
||||||
_, err := x.Insert(labels)
|
return db.Create(labels).Error
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ errutil.NotFound = (*ErrLabelNotExist)(nil)
|
var _ errutil.NotFound = (*ErrLabelNotExist)(nil)
|
||||||
@@ -123,20 +120,22 @@ func (ErrLabelNotExist) NotFound() bool {
|
|||||||
// getLabelOfRepoByName returns a label by Name in given repository.
|
// getLabelOfRepoByName returns a label by Name in given repository.
|
||||||
// If pass repoID as 0, then ORM will ignore limitation of repository
|
// If pass repoID as 0, then ORM will ignore limitation of repository
|
||||||
// and can return arbitrary label with any valid ID.
|
// and can return arbitrary label with any valid ID.
|
||||||
func getLabelOfRepoByName(e Engine, repoID int64, labelName string) (*Label, error) {
|
func getLabelOfRepoByName(tx *gorm.DB, repoID int64, labelName string) (*Label, error) {
|
||||||
if len(labelName) <= 0 {
|
if len(labelName) <= 0 {
|
||||||
return nil, ErrLabelNotExist{args: map[string]any{"repoID": repoID}}
|
return nil, ErrLabelNotExist{args: map[string]any{"repoID": repoID}}
|
||||||
}
|
}
|
||||||
|
|
||||||
l := &Label{
|
l := &Label{}
|
||||||
Name: labelName,
|
query := tx.Where("name = ?", labelName)
|
||||||
RepoID: repoID,
|
if repoID > 0 {
|
||||||
|
query = query.Where("repo_id = ?", repoID)
|
||||||
}
|
}
|
||||||
has, err := e.Get(l)
|
err := query.First(l).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, ErrLabelNotExist{args: map[string]any{"repoID": repoID}}
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
|
||||||
return nil, ErrLabelNotExist{args: map[string]any{"repoID": repoID}}
|
|
||||||
}
|
}
|
||||||
return l, nil
|
return l, nil
|
||||||
}
|
}
|
||||||
@@ -144,54 +143,56 @@ func getLabelOfRepoByName(e Engine, repoID int64, labelName string) (*Label, err
|
|||||||
// getLabelInRepoByID returns a label by ID in given repository.
|
// getLabelInRepoByID returns a label by ID in given repository.
|
||||||
// If pass repoID as 0, then ORM will ignore limitation of repository
|
// If pass repoID as 0, then ORM will ignore limitation of repository
|
||||||
// and can return arbitrary label with any valid ID.
|
// and can return arbitrary label with any valid ID.
|
||||||
func getLabelOfRepoByID(e Engine, repoID, labelID int64) (*Label, error) {
|
func getLabelOfRepoByID(tx *gorm.DB, repoID, labelID int64) (*Label, error) {
|
||||||
if labelID <= 0 {
|
if labelID <= 0 {
|
||||||
return nil, ErrLabelNotExist{args: map[string]any{"repoID": repoID, "labelID": labelID}}
|
return nil, ErrLabelNotExist{args: map[string]any{"repoID": repoID, "labelID": labelID}}
|
||||||
}
|
}
|
||||||
|
|
||||||
l := &Label{
|
l := &Label{}
|
||||||
ID: labelID,
|
query := tx.Where("id = ?", labelID)
|
||||||
RepoID: repoID,
|
if repoID > 0 {
|
||||||
|
query = query.Where("repo_id = ?", repoID)
|
||||||
}
|
}
|
||||||
has, err := e.Get(l)
|
err := query.First(l).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, ErrLabelNotExist{args: map[string]any{"repoID": repoID, "labelID": labelID}}
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
|
||||||
return nil, ErrLabelNotExist{args: map[string]any{"repoID": repoID, "labelID": labelID}}
|
|
||||||
}
|
}
|
||||||
return l, nil
|
return l, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLabelByID returns a label by given ID.
|
// GetLabelByID returns a label by given ID.
|
||||||
func GetLabelByID(id int64) (*Label, error) {
|
func GetLabelByID(id int64) (*Label, error) {
|
||||||
return getLabelOfRepoByID(x, 0, id)
|
return getLabelOfRepoByID(db, 0, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLabelOfRepoByID returns a label by ID in given repository.
|
// GetLabelOfRepoByID returns a label by ID in given repository.
|
||||||
func GetLabelOfRepoByID(repoID, labelID int64) (*Label, error) {
|
func GetLabelOfRepoByID(repoID, labelID int64) (*Label, error) {
|
||||||
return getLabelOfRepoByID(x, repoID, labelID)
|
return getLabelOfRepoByID(db, repoID, labelID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLabelOfRepoByName returns a label by name in given repository.
|
// GetLabelOfRepoByName returns a label by name in given repository.
|
||||||
func GetLabelOfRepoByName(repoID int64, labelName string) (*Label, error) {
|
func GetLabelOfRepoByName(repoID int64, labelName string) (*Label, error) {
|
||||||
return getLabelOfRepoByName(x, repoID, labelName)
|
return getLabelOfRepoByName(db, repoID, labelName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLabelsInRepoByIDs returns a list of labels by IDs in given repository,
|
// GetLabelsInRepoByIDs returns a list of labels by IDs in given repository,
|
||||||
// it silently ignores label IDs that are not belong to the repository.
|
// it silently ignores label IDs that are not belong to the repository.
|
||||||
func GetLabelsInRepoByIDs(repoID int64, labelIDs []int64) ([]*Label, error) {
|
func GetLabelsInRepoByIDs(repoID int64, labelIDs []int64) ([]*Label, error) {
|
||||||
labels := make([]*Label, 0, len(labelIDs))
|
labels := make([]*Label, 0, len(labelIDs))
|
||||||
return labels, x.Where("repo_id = ?", repoID).In("id", tool.Int64sToStrings(labelIDs)).Asc("name").Find(&labels)
|
return labels, db.Where("repo_id = ? AND id IN ?", repoID, labelIDs).Order("name ASC").Find(&labels).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLabelsByRepoID returns all labels that belong to given repository by ID.
|
// GetLabelsByRepoID returns all labels that belong to given repository by ID.
|
||||||
func GetLabelsByRepoID(repoID int64) ([]*Label, error) {
|
func GetLabelsByRepoID(repoID int64) ([]*Label, error) {
|
||||||
labels := make([]*Label, 0, 10)
|
labels := make([]*Label, 0, 10)
|
||||||
return labels, x.Where("repo_id = ?", repoID).Asc("name").Find(&labels)
|
return labels, db.Where("repo_id = ?", repoID).Order("name ASC").Find(&labels).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLabelsByIssueID(e Engine, issueID int64) ([]*Label, error) {
|
func getLabelsByIssueID(tx *gorm.DB, issueID int64) ([]*Label, error) {
|
||||||
issueLabels, err := getIssueLabels(e, issueID)
|
issueLabels, err := getIssueLabels(tx, issueID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Newf("getIssueLabels: %v", err)
|
return nil, errors.Newf("getIssueLabels: %v", err)
|
||||||
} else if len(issueLabels) == 0 {
|
} else if len(issueLabels) == 0 {
|
||||||
@@ -204,22 +205,21 @@ func getLabelsByIssueID(e Engine, issueID int64) ([]*Label, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
labels := make([]*Label, 0, len(labelIDs))
|
labels := make([]*Label, 0, len(labelIDs))
|
||||||
return labels, e.Where("id > 0").In("id", tool.Int64sToStrings(labelIDs)).Asc("name").Find(&labels)
|
return labels, tx.Where("id > 0 AND id IN ?", labelIDs).Order("name ASC").Find(&labels).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLabelsByIssueID returns all labels that belong to given issue by ID.
|
// GetLabelsByIssueID returns all labels that belong to given issue by ID.
|
||||||
func GetLabelsByIssueID(issueID int64) ([]*Label, error) {
|
func GetLabelsByIssueID(issueID int64) ([]*Label, error) {
|
||||||
return getLabelsByIssueID(x, issueID)
|
return getLabelsByIssueID(db, issueID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateLabel(e Engine, l *Label) error {
|
func updateLabel(tx *gorm.DB, l *Label) error {
|
||||||
_, err := e.ID(l.ID).AllCols().Update(l)
|
return tx.Model(l).Where("id = ?", l.ID).Updates(l).Error
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateLabel updates label information.
|
// UpdateLabel updates label information.
|
||||||
func UpdateLabel(l *Label) error {
|
func UpdateLabel(l *Label) error {
|
||||||
return updateLabel(x, l)
|
return updateLabel(db, l)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteLabel delete a label of given repository.
|
// DeleteLabel delete a label of given repository.
|
||||||
@@ -232,19 +232,15 @@ func DeleteLabel(repoID, labelID int64) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
if err := tx.Where("id = ?", labelID).Delete(new(Label)).Error; err != nil {
|
||||||
if err = sess.Begin(); err != nil {
|
return err
|
||||||
return err
|
}
|
||||||
}
|
if err := tx.Where("label_id = ?", labelID).Delete(new(IssueLabel)).Error; err != nil {
|
||||||
|
return err
|
||||||
if _, err = sess.ID(labelID).Delete(new(Label)); err != nil {
|
}
|
||||||
return err
|
return nil
|
||||||
} else if _, err = sess.Where("label_id = ?", labelID).Delete(new(IssueLabel)); err != nil {
|
})
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return sess.Commit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// .___ .____ ___. .__
|
// .___ .____ ___. .__
|
||||||
@@ -257,25 +253,26 @@ func DeleteLabel(repoID, labelID int64) error {
|
|||||||
// IssueLabel represents an issue-lable relation.
|
// IssueLabel represents an issue-lable relation.
|
||||||
type IssueLabel struct {
|
type IssueLabel struct {
|
||||||
ID int64
|
ID int64
|
||||||
IssueID int64 `xorm:"UNIQUE(s)"`
|
IssueID int64 `gorm:"uniqueIndex:issue_label_unique"`
|
||||||
LabelID int64 `xorm:"UNIQUE(s)"`
|
LabelID int64 `gorm:"uniqueIndex:issue_label_unique"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasIssueLabel(e Engine, issueID, labelID int64) bool {
|
func hasIssueLabel(tx *gorm.DB, issueID, labelID int64) bool {
|
||||||
has, _ := e.Where("issue_id = ? AND label_id = ?", issueID, labelID).Get(new(IssueLabel))
|
var count int64
|
||||||
return has
|
tx.Model(new(IssueLabel)).Where("issue_id = ? AND label_id = ?", issueID, labelID).Count(&count)
|
||||||
|
return count > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasIssueLabel returns true if issue has been labeled.
|
// HasIssueLabel returns true if issue has been labeled.
|
||||||
func HasIssueLabel(issueID, labelID int64) bool {
|
func HasIssueLabel(issueID, labelID int64) bool {
|
||||||
return hasIssueLabel(x, issueID, labelID)
|
return hasIssueLabel(db, issueID, labelID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newIssueLabel(e *xorm.Session, issue *Issue, label *Label) (err error) {
|
func newIssueLabel(tx *gorm.DB, issue *Issue, label *Label) (err error) {
|
||||||
if _, err = e.Insert(&IssueLabel{
|
if err = tx.Create(&IssueLabel{
|
||||||
IssueID: issue.ID,
|
IssueID: issue.ID,
|
||||||
LabelID: label.ID,
|
LabelID: label.ID,
|
||||||
}); err != nil {
|
}).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,7 +281,7 @@ func newIssueLabel(e *xorm.Session, issue *Issue, label *Label) (err error) {
|
|||||||
label.NumClosedIssues++
|
label.NumClosedIssues++
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = updateLabel(e, label); err != nil {
|
if err = updateLabel(tx, label); err != nil {
|
||||||
return errors.Newf("updateLabel: %v", err)
|
return errors.Newf("updateLabel: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,26 +295,18 @@ func NewIssueLabel(issue *Issue, label *Label) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
return newIssueLabel(tx, issue, label)
|
||||||
if err = sess.Begin(); err != nil {
|
})
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = newIssueLabel(sess, issue, label); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return sess.Commit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newIssueLabels(e *xorm.Session, issue *Issue, labels []*Label) (err error) {
|
func newIssueLabels(tx *gorm.DB, issue *Issue, labels []*Label) (err error) {
|
||||||
for i := range labels {
|
for i := range labels {
|
||||||
if hasIssueLabel(e, issue.ID, labels[i].ID) {
|
if hasIssueLabel(tx, issue.ID, labels[i].ID) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = newIssueLabel(e, issue, labels[i]); err != nil {
|
if err = newIssueLabel(tx, issue, labels[i]); err != nil {
|
||||||
return errors.Newf("newIssueLabel: %v", err)
|
return errors.Newf("newIssueLabel: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -327,34 +316,23 @@ func newIssueLabels(e *xorm.Session, issue *Issue, labels []*Label) (err error)
|
|||||||
|
|
||||||
// NewIssueLabels creates a list of issue-label relations.
|
// NewIssueLabels creates a list of issue-label relations.
|
||||||
func NewIssueLabels(issue *Issue, labels []*Label) (err error) {
|
func NewIssueLabels(issue *Issue, labels []*Label) (err error) {
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
return newIssueLabels(tx, issue, labels)
|
||||||
if err = sess.Begin(); err != nil {
|
})
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = newIssueLabels(sess, issue, labels); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return sess.Commit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getIssueLabels(e Engine, issueID int64) ([]*IssueLabel, error) {
|
func getIssueLabels(tx *gorm.DB, issueID int64) ([]*IssueLabel, error) {
|
||||||
issueLabels := make([]*IssueLabel, 0, 10)
|
issueLabels := make([]*IssueLabel, 0, 10)
|
||||||
return issueLabels, e.Where("issue_id=?", issueID).Asc("label_id").Find(&issueLabels)
|
return issueLabels, tx.Where("issue_id = ?", issueID).Order("label_id ASC").Find(&issueLabels).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetIssueLabels returns all issue-label relations of given issue by ID.
|
// GetIssueLabels returns all issue-label relations of given issue by ID.
|
||||||
func GetIssueLabels(issueID int64) ([]*IssueLabel, error) {
|
func GetIssueLabels(issueID int64) ([]*IssueLabel, error) {
|
||||||
return getIssueLabels(x, issueID)
|
return getIssueLabels(db, issueID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteIssueLabel(e *xorm.Session, issue *Issue, label *Label) (err error) {
|
func deleteIssueLabel(tx *gorm.DB, issue *Issue, label *Label) (err error) {
|
||||||
if _, err = e.Delete(&IssueLabel{
|
if err = tx.Where("issue_id = ? AND label_id = ?", issue.ID, label.ID).Delete(&IssueLabel{}).Error; err != nil {
|
||||||
IssueID: issue.ID,
|
|
||||||
LabelID: label.ID,
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,7 +340,7 @@ func deleteIssueLabel(e *xorm.Session, issue *Issue, label *Label) (err error) {
|
|||||||
if issue.IsClosed {
|
if issue.IsClosed {
|
||||||
label.NumClosedIssues--
|
label.NumClosedIssues--
|
||||||
}
|
}
|
||||||
if err = updateLabel(e, label); err != nil {
|
if err = updateLabel(tx, label); err != nil {
|
||||||
return errors.Newf("updateLabel: %v", err)
|
return errors.Newf("updateLabel: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,15 +355,7 @@ func deleteIssueLabel(e *xorm.Session, issue *Issue, label *Label) (err error) {
|
|||||||
|
|
||||||
// DeleteIssueLabel deletes issue-label relation.
|
// DeleteIssueLabel deletes issue-label relation.
|
||||||
func DeleteIssueLabel(issue *Issue, label *Label) (err error) {
|
func DeleteIssueLabel(issue *Issue, label *Label) (err error) {
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
return deleteIssueLabel(tx, issue, label)
|
||||||
if err = sess.Begin(); err != nil {
|
})
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = deleteIssueLabel(sess, issue, label); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return sess.Commit()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ func mailIssueCommentToParticipants(issue *Issue, doer *User, mentions []string)
|
|||||||
// and mentioned people.
|
// and mentioned people.
|
||||||
func (issue *Issue) MailParticipants() (err error) {
|
func (issue *Issue) MailParticipants() (err error) {
|
||||||
mentions := markup.FindAllMentions(issue.Content)
|
mentions := markup.FindAllMentions(issue.Content)
|
||||||
if err = updateIssueMentions(x, issue.ID, mentions); err != nil {
|
if err = updateIssueMentions(db, issue.ID, mentions); err != nil {
|
||||||
return errors.Newf("UpdateIssueMentions [%d]: %v", issue.ID, err)
|
return errors.Newf("UpdateIssueMentions [%d]: %v", issue.ID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
log "unknwon.dev/clog/v2"
|
|
||||||
"xorm.io/xorm"
|
|
||||||
|
|
||||||
"github.com/cockroachdb/errors"
|
"github.com/cockroachdb/errors"
|
||||||
api "github.com/gogs/go-gogs-client"
|
api "github.com/gogs/go-gogs-client"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
log "unknwon.dev/clog/v2"
|
||||||
|
|
||||||
"gogs.io/gogs/internal/conf"
|
"gogs.io/gogs/internal/conf"
|
||||||
"gogs.io/gogs/internal/errutil"
|
"gogs.io/gogs/internal/errutil"
|
||||||
@@ -17,29 +16,30 @@ import (
|
|||||||
// Milestone represents a milestone of repository.
|
// Milestone represents a milestone of repository.
|
||||||
type Milestone struct {
|
type Milestone struct {
|
||||||
ID int64
|
ID int64
|
||||||
RepoID int64 `xorm:"INDEX"`
|
RepoID int64 `gorm:"index"`
|
||||||
Name string
|
Name string
|
||||||
Content string `xorm:"TEXT"`
|
Content string `gorm:"type:text"`
|
||||||
RenderedContent string `xorm:"-" json:"-" gorm:"-"`
|
RenderedContent string `gorm:"-" json:"-"`
|
||||||
IsClosed bool
|
IsClosed bool
|
||||||
NumIssues int
|
NumIssues int
|
||||||
NumClosedIssues int
|
NumClosedIssues int
|
||||||
NumOpenIssues int `xorm:"-" json:"-" gorm:"-"`
|
NumOpenIssues int `gorm:"-" json:"-"`
|
||||||
Completeness int // Percentage(1-100).
|
Completeness int // Percentage(1-100).
|
||||||
IsOverDue bool `xorm:"-" json:"-" gorm:"-"`
|
IsOverDue bool `gorm:"-" json:"-"`
|
||||||
|
|
||||||
DeadlineString string `xorm:"-" json:"-" gorm:"-"`
|
DeadlineString string `gorm:"-" json:"-"`
|
||||||
Deadline time.Time `xorm:"-" json:"-" gorm:"-"`
|
Deadline time.Time `gorm:"-" json:"-"`
|
||||||
DeadlineUnix int64
|
DeadlineUnix int64
|
||||||
ClosedDate time.Time `xorm:"-" json:"-" gorm:"-"`
|
ClosedDate time.Time `gorm:"-" json:"-"`
|
||||||
ClosedDateUnix int64
|
ClosedDateUnix int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Milestone) BeforeInsert() {
|
func (m *Milestone) BeforeCreate(tx *gorm.DB) error {
|
||||||
m.DeadlineUnix = m.Deadline.Unix()
|
m.DeadlineUnix = m.Deadline.Unix()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Milestone) BeforeUpdate() {
|
func (m *Milestone) BeforeUpdate(tx *gorm.DB) error {
|
||||||
if m.NumIssues > 0 {
|
if m.NumIssues > 0 {
|
||||||
m.Completeness = m.NumClosedIssues * 100 / m.NumIssues
|
m.Completeness = m.NumClosedIssues * 100 / m.NumIssues
|
||||||
} else {
|
} else {
|
||||||
@@ -48,27 +48,22 @@ func (m *Milestone) BeforeUpdate() {
|
|||||||
|
|
||||||
m.DeadlineUnix = m.Deadline.Unix()
|
m.DeadlineUnix = m.Deadline.Unix()
|
||||||
m.ClosedDateUnix = m.ClosedDate.Unix()
|
m.ClosedDateUnix = m.ClosedDate.Unix()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Milestone) AfterSet(colName string, _ xorm.Cell) {
|
func (m *Milestone) AfterFind(tx *gorm.DB) error {
|
||||||
switch colName {
|
m.NumOpenIssues = m.NumIssues - m.NumClosedIssues
|
||||||
case "num_closed_issues":
|
|
||||||
m.NumOpenIssues = m.NumIssues - m.NumClosedIssues
|
|
||||||
|
|
||||||
case "deadline_unix":
|
|
||||||
m.Deadline = time.Unix(m.DeadlineUnix, 0).Local()
|
|
||||||
if m.Deadline.Year() == 9999 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
|
m.Deadline = time.Unix(m.DeadlineUnix, 0).Local()
|
||||||
|
if m.Deadline.Year() != 9999 {
|
||||||
m.DeadlineString = m.Deadline.Format("2006-01-02")
|
m.DeadlineString = m.Deadline.Format("2006-01-02")
|
||||||
if time.Now().Local().After(m.Deadline) {
|
if time.Now().Local().After(m.Deadline) {
|
||||||
m.IsOverDue = true
|
m.IsOverDue = true
|
||||||
}
|
}
|
||||||
|
|
||||||
case "closed_date_unix":
|
|
||||||
m.ClosedDate = time.Unix(m.ClosedDateUnix, 0).Local()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.ClosedDate = time.Unix(m.ClosedDateUnix, 0).Local()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// State returns string representation of milestone status.
|
// State returns string representation of milestone status.
|
||||||
@@ -102,30 +97,24 @@ func (m *Milestone) APIFormat() *api.Milestone {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *Milestone) CountIssues(isClosed, includePulls bool) int64 {
|
func (m *Milestone) CountIssues(isClosed, includePulls bool) int64 {
|
||||||
sess := x.Where("milestone_id = ?", m.ID).And("is_closed = ?", isClosed)
|
query := db.Model(new(Issue)).Where("milestone_id = ? AND is_closed = ?", m.ID, isClosed)
|
||||||
if !includePulls {
|
if !includePulls {
|
||||||
sess.And("is_pull = ?", false)
|
query = query.Where("is_pull = ?", false)
|
||||||
}
|
}
|
||||||
count, _ := sess.Count(new(Issue))
|
var count int64
|
||||||
|
query.Count(&count)
|
||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMilestone creates new milestone of repository.
|
// NewMilestone creates new milestone of repository.
|
||||||
func NewMilestone(m *Milestone) (err error) {
|
func NewMilestone(m *Milestone) (err error) {
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
if err := tx.Create(m).Error; err != nil {
|
||||||
if err = sess.Begin(); err != nil {
|
return err
|
||||||
return err
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = sess.Insert(m); err != nil {
|
return tx.Exec("UPDATE `repository` SET num_milestones = num_milestones + 1 WHERE id = ?", m.RepoID).Error
|
||||||
return err
|
})
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = sess.Exec("UPDATE `repository` SET num_milestones = num_milestones + 1 WHERE id = ?", m.RepoID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return sess.Commit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ errutil.NotFound = (*ErrMilestoneNotExist)(nil)
|
var _ errutil.NotFound = (*ErrMilestoneNotExist)(nil)
|
||||||
@@ -147,74 +136,73 @@ func (ErrMilestoneNotExist) NotFound() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMilestoneByRepoID(e Engine, repoID, id int64) (*Milestone, error) {
|
func getMilestoneByRepoID(e *gorm.DB, repoID, id int64) (*Milestone, error) {
|
||||||
m := &Milestone{
|
m := &Milestone{}
|
||||||
ID: id,
|
err := e.Where("id = ? AND repo_id = ?", id, repoID).First(m).Error
|
||||||
RepoID: repoID,
|
|
||||||
}
|
|
||||||
has, err := e.Get(m)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, ErrMilestoneNotExist{args: map[string]any{"repoID": repoID, "milestoneID": id}}
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
|
||||||
return nil, ErrMilestoneNotExist{args: map[string]any{"repoID": repoID, "milestoneID": id}}
|
|
||||||
}
|
}
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetWebhookByRepoID returns the milestone in a repository.
|
// GetWebhookByRepoID returns the milestone in a repository.
|
||||||
func GetMilestoneByRepoID(repoID, id int64) (*Milestone, error) {
|
func GetMilestoneByRepoID(repoID, id int64) (*Milestone, error) {
|
||||||
return getMilestoneByRepoID(x, repoID, id)
|
return getMilestoneByRepoID(db, repoID, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMilestonesByRepoID returns all milestones of a repository.
|
// GetMilestonesByRepoID returns all milestones of a repository.
|
||||||
func GetMilestonesByRepoID(repoID int64) ([]*Milestone, error) {
|
func GetMilestonesByRepoID(repoID int64) ([]*Milestone, error) {
|
||||||
miles := make([]*Milestone, 0, 10)
|
miles := make([]*Milestone, 0, 10)
|
||||||
return miles, x.Where("repo_id = ?", repoID).Find(&miles)
|
return miles, db.Where("repo_id = ?", repoID).Find(&miles).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMilestones returns a list of milestones of given repository and status.
|
// GetMilestones returns a list of milestones of given repository and status.
|
||||||
func GetMilestones(repoID int64, page int, isClosed bool) ([]*Milestone, error) {
|
func GetMilestones(repoID int64, page int, isClosed bool) ([]*Milestone, error) {
|
||||||
miles := make([]*Milestone, 0, conf.UI.IssuePagingNum)
|
miles := make([]*Milestone, 0, conf.UI.IssuePagingNum)
|
||||||
sess := x.Where("repo_id = ? AND is_closed = ?", repoID, isClosed)
|
query := db.Where("repo_id = ? AND is_closed = ?", repoID, isClosed)
|
||||||
if page > 0 {
|
if page > 0 {
|
||||||
sess = sess.Limit(conf.UI.IssuePagingNum, (page-1)*conf.UI.IssuePagingNum)
|
query = query.Limit(conf.UI.IssuePagingNum).Offset((page - 1) * conf.UI.IssuePagingNum)
|
||||||
}
|
}
|
||||||
return miles, sess.Find(&miles)
|
return miles, query.Find(&miles).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateMilestone(e Engine, m *Milestone) error {
|
func updateMilestone(e *gorm.DB, m *Milestone) error {
|
||||||
_, err := e.ID(m.ID).AllCols().Update(m)
|
return e.Model(m).Where("id = ?", m.ID).Updates(m).Error
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateMilestone updates information of given milestone.
|
// UpdateMilestone updates information of given milestone.
|
||||||
func UpdateMilestone(m *Milestone) error {
|
func UpdateMilestone(m *Milestone) error {
|
||||||
return updateMilestone(x, m)
|
return updateMilestone(db, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
func countRepoMilestones(e Engine, repoID int64) int64 {
|
func countRepoMilestones(e *gorm.DB, repoID int64) int64 {
|
||||||
count, _ := e.Where("repo_id=?", repoID).Count(new(Milestone))
|
var count int64
|
||||||
|
e.Model(new(Milestone)).Where("repo_id = ?", repoID).Count(&count)
|
||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
// CountRepoMilestones returns number of milestones in given repository.
|
// CountRepoMilestones returns number of milestones in given repository.
|
||||||
func CountRepoMilestones(repoID int64) int64 {
|
func CountRepoMilestones(repoID int64) int64 {
|
||||||
return countRepoMilestones(x, repoID)
|
return countRepoMilestones(db, repoID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func countRepoClosedMilestones(e Engine, repoID int64) int64 {
|
func countRepoClosedMilestones(e *gorm.DB, repoID int64) int64 {
|
||||||
closed, _ := e.Where("repo_id=? AND is_closed=?", repoID, true).Count(new(Milestone))
|
var count int64
|
||||||
return closed
|
e.Model(new(Milestone)).Where("repo_id = ? AND is_closed = ?", repoID, true).Count(&count)
|
||||||
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
// CountRepoClosedMilestones returns number of closed milestones in given repository.
|
// CountRepoClosedMilestones returns number of closed milestones in given repository.
|
||||||
func CountRepoClosedMilestones(repoID int64) int64 {
|
func CountRepoClosedMilestones(repoID int64) int64 {
|
||||||
return countRepoClosedMilestones(x, repoID)
|
return countRepoClosedMilestones(db, repoID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MilestoneStats returns number of open and closed milestones of given repository.
|
// MilestoneStats returns number of open and closed milestones of given repository.
|
||||||
func MilestoneStats(repoID int64) (open, closed int64) {
|
func MilestoneStats(repoID int64) (open, closed int64) {
|
||||||
open, _ = x.Where("repo_id=? AND is_closed=?", repoID, false).Count(new(Milestone))
|
db.Model(new(Milestone)).Where("repo_id = ? AND is_closed = ?", repoID, false).Count(&open)
|
||||||
return open, CountRepoClosedMilestones(repoID)
|
return open, CountRepoClosedMilestones(repoID)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,26 +215,19 @@ func ChangeMilestoneStatus(m *Milestone, isClosed bool) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
m.IsClosed = isClosed
|
||||||
if err = sess.Begin(); err != nil {
|
if err := updateMilestone(tx, m); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
m.IsClosed = isClosed
|
repo.NumMilestones = int(countRepoMilestones(tx, repo.ID))
|
||||||
if err = updateMilestone(sess, m); err != nil {
|
repo.NumClosedMilestones = int(countRepoClosedMilestones(tx, repo.ID))
|
||||||
return err
|
return tx.Model(repo).Where("id = ?", repo.ID).Updates(repo).Error
|
||||||
}
|
})
|
||||||
|
|
||||||
repo.NumMilestones = int(countRepoMilestones(sess, repo.ID))
|
|
||||||
repo.NumClosedMilestones = int(countRepoClosedMilestones(sess, repo.ID))
|
|
||||||
if _, err = sess.ID(repo.ID).AllCols().Update(repo); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return sess.Commit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func changeMilestoneIssueStats(e *xorm.Session, issue *Issue) error {
|
func changeMilestoneIssueStats(e *gorm.DB, issue *Issue) error {
|
||||||
if issue.MilestoneID == 0 {
|
if issue.MilestoneID == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -270,20 +251,12 @@ func changeMilestoneIssueStats(e *xorm.Session, issue *Issue) error {
|
|||||||
// ChangeMilestoneIssueStats updates the open/closed issues counter and progress
|
// ChangeMilestoneIssueStats updates the open/closed issues counter and progress
|
||||||
// for the milestone associated with the given issue.
|
// for the milestone associated with the given issue.
|
||||||
func ChangeMilestoneIssueStats(issue *Issue) (err error) {
|
func ChangeMilestoneIssueStats(issue *Issue) (err error) {
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
return changeMilestoneIssueStats(tx, issue)
|
||||||
if err = sess.Begin(); err != nil {
|
})
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = changeMilestoneIssueStats(sess, issue); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return sess.Commit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func changeMilestoneAssign(e *xorm.Session, issue *Issue, oldMilestoneID int64) error {
|
func changeMilestoneAssign(e *gorm.DB, issue *Issue, oldMilestoneID int64) error {
|
||||||
if oldMilestoneID > 0 {
|
if oldMilestoneID > 0 {
|
||||||
m, err := getMilestoneByRepoID(e, issue.RepoID, oldMilestoneID)
|
m, err := getMilestoneByRepoID(e, issue.RepoID, oldMilestoneID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -297,7 +270,9 @@ func changeMilestoneAssign(e *xorm.Session, issue *Issue, oldMilestoneID int64)
|
|||||||
|
|
||||||
if err = updateMilestone(e, m); err != nil {
|
if err = updateMilestone(e, m); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if _, err = e.Exec("UPDATE `issue_user` SET milestone_id = 0 WHERE issue_id = ?", issue.ID); err != nil {
|
}
|
||||||
|
|
||||||
|
if err = e.Exec("UPDATE `issue_user` SET milestone_id = 0 WHERE issue_id = ?", issue.ID).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,7 +292,9 @@ func changeMilestoneAssign(e *xorm.Session, issue *Issue, oldMilestoneID int64)
|
|||||||
|
|
||||||
if err = updateMilestone(e, m); err != nil {
|
if err = updateMilestone(e, m); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if _, err = e.Exec("UPDATE `issue_user` SET milestone_id = ? WHERE issue_id = ?", m.ID, issue.ID); err != nil {
|
}
|
||||||
|
|
||||||
|
if err = e.Exec("UPDATE `issue_user` SET milestone_id = ? WHERE issue_id = ?", m.ID, issue.ID).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,18 +306,11 @@ func changeMilestoneAssign(e *xorm.Session, issue *Issue, oldMilestoneID int64)
|
|||||||
|
|
||||||
// ChangeMilestoneAssign changes assignment of milestone for issue.
|
// ChangeMilestoneAssign changes assignment of milestone for issue.
|
||||||
func ChangeMilestoneAssign(doer *User, issue *Issue, oldMilestoneID int64) (err error) {
|
func ChangeMilestoneAssign(doer *User, issue *Issue, oldMilestoneID int64) (err error) {
|
||||||
sess := x.NewSession()
|
err = db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
return changeMilestoneAssign(tx, issue, oldMilestoneID)
|
||||||
if err = sess.Begin(); err != nil {
|
})
|
||||||
return err
|
if err != nil {
|
||||||
}
|
return errors.Newf("transaction: %v", err)
|
||||||
|
|
||||||
if err = changeMilestoneAssign(sess, issue, oldMilestoneID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = sess.Commit(); err != nil {
|
|
||||||
return errors.Newf("commit: %v", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var hookAction api.HookIssueAction
|
var hookAction api.HookIssueAction
|
||||||
@@ -394,26 +364,21 @@ func DeleteMilestoneOfRepoByID(repoID, id int64) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
if err := tx.Where("id = ?", m.ID).Delete(new(Milestone)).Error; err != nil {
|
||||||
if err = sess.Begin(); err != nil {
|
return err
|
||||||
return err
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = sess.ID(m.ID).Delete(new(Milestone)); err != nil {
|
repo.NumMilestones = int(countRepoMilestones(tx, repo.ID))
|
||||||
return err
|
repo.NumClosedMilestones = int(countRepoClosedMilestones(tx, repo.ID))
|
||||||
}
|
if err := tx.Model(repo).Where("id = ?", repo.ID).Updates(repo).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
repo.NumMilestones = int(countRepoMilestones(sess, repo.ID))
|
if err := tx.Exec("UPDATE `issue` SET milestone_id = 0 WHERE milestone_id = ?", m.ID).Error; err != nil {
|
||||||
repo.NumClosedMilestones = int(countRepoClosedMilestones(sess, repo.ID))
|
return err
|
||||||
if _, err = sess.ID(repo.ID).AllCols().Update(repo); err != nil {
|
}
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = sess.Exec("UPDATE `issue` SET milestone_id = 0 WHERE milestone_id = ?", m.ID); err != nil {
|
return tx.Exec("UPDATE `issue_user` SET milestone_id = 0 WHERE milestone_id = ?", m.ID).Error
|
||||||
return err
|
})
|
||||||
} else if _, err = sess.Exec("UPDATE `issue_user` SET milestone_id = 0 WHERE milestone_id = ?", m.ID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return sess.Commit()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,12 +8,11 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cockroachdb/errors"
|
"github.com/cockroachdb/errors"
|
||||||
|
"github.com/gogs/git-module"
|
||||||
"github.com/unknwon/com"
|
"github.com/unknwon/com"
|
||||||
"gopkg.in/ini.v1"
|
"gopkg.in/ini.v1"
|
||||||
|
"gorm.io/gorm"
|
||||||
log "unknwon.dev/clog/v2"
|
log "unknwon.dev/clog/v2"
|
||||||
"xorm.io/xorm"
|
|
||||||
|
|
||||||
"github.com/gogs/git-module"
|
|
||||||
|
|
||||||
"gogs.io/gogs/internal/conf"
|
"gogs.io/gogs/internal/conf"
|
||||||
"gogs.io/gogs/internal/process"
|
"gogs.io/gogs/internal/process"
|
||||||
@@ -41,41 +40,41 @@ func (err MirrorNotExist) Error() string {
|
|||||||
type Mirror struct {
|
type Mirror struct {
|
||||||
ID int64
|
ID int64
|
||||||
RepoID int64
|
RepoID int64
|
||||||
Repo *Repository `xorm:"-" json:"-" gorm:"-"`
|
Repo *Repository `gorm:"-" json:"-"`
|
||||||
Interval int // Hour.
|
Interval int // Hour.
|
||||||
EnablePrune bool `xorm:"NOT NULL DEFAULT true"`
|
EnablePrune bool `gorm:"not null;default:true"`
|
||||||
|
|
||||||
// Last and next sync time of Git data from upstream
|
// Last and next sync time of Git data from upstream
|
||||||
LastSync time.Time `xorm:"-" json:"-" gorm:"-"`
|
LastSync time.Time `gorm:"-" json:"-"`
|
||||||
LastSyncUnix int64 `xorm:"updated_unix"`
|
LastSyncUnix int64 `gorm:"column:updated_unix"`
|
||||||
NextSync time.Time `xorm:"-" json:"-" gorm:"-"`
|
NextSync time.Time `gorm:"-" json:"-"`
|
||||||
NextSyncUnix int64 `xorm:"next_update_unix"`
|
NextSyncUnix int64 `gorm:"column:next_update_unix"`
|
||||||
|
|
||||||
address string `xorm:"-"`
|
address string `gorm:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mirror) BeforeInsert() {
|
func (m *Mirror) BeforeCreate(tx *gorm.DB) error {
|
||||||
m.NextSyncUnix = m.NextSync.Unix()
|
m.NextSyncUnix = m.NextSync.Unix()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mirror) BeforeUpdate() {
|
func (m *Mirror) BeforeUpdate(tx *gorm.DB) error {
|
||||||
m.LastSyncUnix = m.LastSync.Unix()
|
m.LastSyncUnix = m.LastSync.Unix()
|
||||||
m.NextSyncUnix = m.NextSync.Unix()
|
m.NextSyncUnix = m.NextSync.Unix()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mirror) AfterSet(colName string, _ xorm.Cell) {
|
func (m *Mirror) AfterFind(tx *gorm.DB) error {
|
||||||
var err error
|
if m.RepoID > 0 {
|
||||||
switch colName {
|
var err error
|
||||||
case "repo_id":
|
|
||||||
m.Repo, err = GetRepositoryByID(m.RepoID)
|
m.Repo, err = GetRepositoryByID(m.RepoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetRepositoryByID [%d]: %v", m.ID, err)
|
log.Error("GetRepositoryByID [%d]: %v", m.ID, err)
|
||||||
}
|
}
|
||||||
case "updated_unix":
|
|
||||||
m.LastSync = time.Unix(m.LastSyncUnix, 0).Local()
|
|
||||||
case "next_update_unix":
|
|
||||||
m.NextSync = time.Unix(m.NextSyncUnix, 0).Local()
|
|
||||||
}
|
}
|
||||||
|
m.LastSync = time.Unix(m.LastSyncUnix, 0).Local()
|
||||||
|
m.NextSync = time.Unix(m.NextSyncUnix, 0).Local()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScheduleNextSync calculates and sets next sync time based on repository mirror setting.
|
// ScheduleNextSync calculates and sets next sync time based on repository mirror setting.
|
||||||
@@ -277,34 +276,33 @@ func (m *Mirror) runSync() ([]*mirrorSyncResult, bool) {
|
|||||||
return parseRemoteUpdateOutput(output), true
|
return parseRemoteUpdateOutput(output), true
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMirrorByRepoID(e Engine, repoID int64) (*Mirror, error) {
|
func getMirrorByRepoID(e *gorm.DB, repoID int64) (*Mirror, error) {
|
||||||
m := &Mirror{RepoID: repoID}
|
m := &Mirror{}
|
||||||
has, err := e.Get(m)
|
err := e.Where("repo_id = ?", repoID).First(m).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, MirrorNotExist{RepoID: repoID}
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
|
||||||
return nil, MirrorNotExist{RepoID: repoID}
|
|
||||||
}
|
}
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMirrorByRepoID returns mirror information of a repository.
|
// GetMirrorByRepoID returns mirror information of a repository.
|
||||||
func GetMirrorByRepoID(repoID int64) (*Mirror, error) {
|
func GetMirrorByRepoID(repoID int64) (*Mirror, error) {
|
||||||
return getMirrorByRepoID(x, repoID)
|
return getMirrorByRepoID(db, repoID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateMirror(e Engine, m *Mirror) error {
|
func updateMirror(e *gorm.DB, m *Mirror) error {
|
||||||
_, err := e.ID(m.ID).AllCols().Update(m)
|
return e.Model(m).Where("id = ?", m.ID).Updates(m).Error
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateMirror(m *Mirror) error {
|
func UpdateMirror(m *Mirror) error {
|
||||||
return updateMirror(x, m)
|
return updateMirror(db, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteMirrorByRepoID(repoID int64) error {
|
func DeleteMirrorByRepoID(repoID int64) error {
|
||||||
_, err := x.Delete(&Mirror{RepoID: repoID})
|
return db.Where("repo_id = ?", repoID).Delete(&Mirror{}).Error
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MirrorUpdate checks and updates mirror repositories.
|
// MirrorUpdate checks and updates mirror repositories.
|
||||||
@@ -317,17 +315,18 @@ func MirrorUpdate() {
|
|||||||
|
|
||||||
log.Trace("Doing: MirrorUpdate")
|
log.Trace("Doing: MirrorUpdate")
|
||||||
|
|
||||||
if err := x.Where("next_update_unix<=?", time.Now().Unix()).Iterate(new(Mirror), func(idx int, bean any) error {
|
var mirrors []*Mirror
|
||||||
m := bean.(*Mirror)
|
if err := db.Where("next_update_unix <= ?", time.Now().Unix()).Find(&mirrors).Error; err != nil {
|
||||||
|
log.Error("MirrorUpdate: find mirrors: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, m := range mirrors {
|
||||||
if m.Repo == nil {
|
if m.Repo == nil {
|
||||||
log.Error("Disconnected mirror repository found: %d", m.ID)
|
log.Error("Disconnected mirror repository found: %d", m.ID)
|
||||||
return nil
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
MirrorQueue.Add(m.RepoID)
|
MirrorQueue.Add(m.RepoID)
|
||||||
return nil
|
|
||||||
}); err != nil {
|
|
||||||
log.Error("MirrorUpdate: %v", err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,7 +453,7 @@ func SyncMirrors() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = x.Exec("UPDATE mirror SET updated_unix = ? WHERE repo_id = ?", time.Now().Unix(), m.RepoID); err != nil {
|
if err = db.Exec("UPDATE mirror SET updated_unix = ? WHERE repo_id = ?", time.Now().Unix(), m.RepoID).Error; err != nil {
|
||||||
log.Error("Update 'mirror.updated_unix' [%d]: %v", m.RepoID, err)
|
log.Error("Update 'mirror.updated_unix' [%d]: %v", m.RepoID, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -469,7 +468,7 @@ func SyncMirrors() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = x.Exec("UPDATE repository SET updated_unix = ? WHERE id = ?", latestCommitTime.Unix(), m.RepoID); err != nil {
|
if err = db.Exec("UPDATE repository SET updated_unix = ? WHERE id = ?", latestCommitTime.Unix(), m.RepoID).Error; err != nil {
|
||||||
log.Error("Update 'repository.updated_unix' [%d]: %v", m.RepoID, err)
|
log.Error("Update 'repository.updated_unix' [%d]: %v", m.RepoID, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package database
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
@@ -13,33 +12,16 @@ import (
|
|||||||
"github.com/cockroachdb/errors"
|
"github.com/cockroachdb/errors"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"gorm.io/gorm/logger"
|
"gorm.io/gorm/logger"
|
||||||
|
"gorm.io/gorm/schema"
|
||||||
log "unknwon.dev/clog/v2"
|
log "unknwon.dev/clog/v2"
|
||||||
"xorm.io/core"
|
|
||||||
"xorm.io/xorm"
|
|
||||||
|
|
||||||
"gogs.io/gogs/internal/conf"
|
"gogs.io/gogs/internal/conf"
|
||||||
"gogs.io/gogs/internal/database/migrations"
|
"gogs.io/gogs/internal/database/migrations"
|
||||||
"gogs.io/gogs/internal/dbutil"
|
"gogs.io/gogs/internal/dbutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Engine represents a XORM engine or session.
|
|
||||||
type Engine interface {
|
|
||||||
Delete(any) (int64, error)
|
|
||||||
Exec(...any) (sql.Result, error)
|
|
||||||
Find(any, ...any) error
|
|
||||||
Get(any) (bool, error)
|
|
||||||
ID(any) *xorm.Session
|
|
||||||
In(string, ...any) *xorm.Session
|
|
||||||
Insert(...any) (int64, error)
|
|
||||||
InsertOne(any) (int64, error)
|
|
||||||
Iterate(any, xorm.IterFunc) error
|
|
||||||
Sql(string, ...any) *xorm.Session
|
|
||||||
Table(any) *xorm.Session
|
|
||||||
Where(any, ...any) *xorm.Session
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
x *xorm.Engine
|
db *gorm.DB
|
||||||
legacyTables []any
|
legacyTables []any
|
||||||
HasEngine bool
|
HasEngine bool
|
||||||
)
|
)
|
||||||
@@ -55,93 +37,90 @@ func init() {
|
|||||||
new(ProtectBranch), new(ProtectBranchWhitelist),
|
new(ProtectBranch), new(ProtectBranchWhitelist),
|
||||||
new(Team), new(OrgUser), new(TeamUser), new(TeamRepo),
|
new(Team), new(OrgUser), new(TeamUser), new(TeamRepo),
|
||||||
)
|
)
|
||||||
|
|
||||||
gonicNames := []string{"SSL"}
|
|
||||||
for _, name := range gonicNames {
|
|
||||||
core.LintGonicMapper[name] = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getEngine() (*xorm.Engine, error) {
|
func getGormDB(gormLogger logger.Writer) (*gorm.DB, error) {
|
||||||
Param := "?"
|
if conf.Database.Type == "sqlite3" {
|
||||||
if strings.Contains(conf.Database.Name, Param) {
|
|
||||||
Param = "&"
|
|
||||||
}
|
|
||||||
|
|
||||||
driver := conf.Database.Type
|
|
||||||
connStr := ""
|
|
||||||
switch conf.Database.Type {
|
|
||||||
case "mysql":
|
|
||||||
conf.UseMySQL = true
|
|
||||||
if conf.Database.Host[0] == '/' { // looks like a unix socket
|
|
||||||
connStr = fmt.Sprintf("%s:%s@unix(%s)/%s%scharset=utf8mb4&parseTime=true",
|
|
||||||
conf.Database.User, conf.Database.Password, conf.Database.Host, conf.Database.Name, Param)
|
|
||||||
} else {
|
|
||||||
connStr = fmt.Sprintf("%s:%s@tcp(%s)/%s%scharset=utf8mb4&parseTime=true",
|
|
||||||
conf.Database.User, conf.Database.Password, conf.Database.Host, conf.Database.Name, Param)
|
|
||||||
}
|
|
||||||
engineParams := map[string]string{"rowFormat": "DYNAMIC"}
|
|
||||||
return xorm.NewEngineWithParams(conf.Database.Type, connStr, engineParams)
|
|
||||||
|
|
||||||
case "postgres":
|
|
||||||
conf.UsePostgreSQL = true
|
|
||||||
host, port := dbutil.ParsePostgreSQLHostPort(conf.Database.Host)
|
|
||||||
connStr = fmt.Sprintf("user='%s' password='%s' host='%s' port='%s' dbname='%s' sslmode='%s' search_path='%s'",
|
|
||||||
conf.Database.User, conf.Database.Password, host, port, conf.Database.Name, conf.Database.SSLMode, conf.Database.Schema)
|
|
||||||
driver = "pgx"
|
|
||||||
|
|
||||||
case "mssql":
|
|
||||||
conf.UseMSSQL = true
|
|
||||||
host, port := dbutil.ParseMSSQLHostPort(conf.Database.Host)
|
|
||||||
connStr = fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;", host, port, conf.Database.Name, conf.Database.User, conf.Database.Password)
|
|
||||||
|
|
||||||
case "sqlite3":
|
|
||||||
if err := os.MkdirAll(path.Dir(conf.Database.Path), os.ModePerm); err != nil {
|
if err := os.MkdirAll(path.Dir(conf.Database.Path), os.ModePerm); err != nil {
|
||||||
return nil, errors.Newf("create directories: %v", err)
|
return nil, errors.Newf("create directories: %v", err)
|
||||||
}
|
}
|
||||||
conf.UseSQLite3 = true
|
|
||||||
connStr = "file:" + conf.Database.Path + "?cache=shared&mode=rwc"
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, errors.Newf("unknown database type: %s", conf.Database.Type)
|
|
||||||
}
|
}
|
||||||
return xorm.NewEngine(driver, connStr)
|
|
||||||
|
level := logger.Info
|
||||||
|
if conf.IsProdMode() {
|
||||||
|
level = logger.Warn
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Default = logger.New(gormLogger, logger.Config{
|
||||||
|
SlowThreshold: 100 * time.Millisecond,
|
||||||
|
LogLevel: level,
|
||||||
|
})
|
||||||
|
|
||||||
|
gormDB, err := dbutil.OpenDB(
|
||||||
|
conf.Database,
|
||||||
|
&gorm.Config{
|
||||||
|
SkipDefaultTransaction: true,
|
||||||
|
NamingStrategy: schema.NamingStrategy{
|
||||||
|
SingularTable: true,
|
||||||
|
},
|
||||||
|
NowFunc: func() time.Time {
|
||||||
|
return time.Now().UTC().Truncate(time.Microsecond)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "open database")
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlDB, err := gormDB.DB()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "get underlying *sql.DB")
|
||||||
|
}
|
||||||
|
sqlDB.SetMaxOpenConns(conf.Database.MaxOpenConns)
|
||||||
|
sqlDB.SetMaxIdleConns(conf.Database.MaxIdleConns)
|
||||||
|
sqlDB.SetConnMaxLifetime(time.Minute)
|
||||||
|
|
||||||
|
switch conf.Database.Type {
|
||||||
|
case "postgres":
|
||||||
|
conf.UsePostgreSQL = true
|
||||||
|
case "mysql":
|
||||||
|
conf.UseMySQL = true
|
||||||
|
gormDB = gormDB.Set("gorm:table_options", "ENGINE=InnoDB").Session(&gorm.Session{})
|
||||||
|
case "sqlite3":
|
||||||
|
conf.UseSQLite3 = true
|
||||||
|
case "mssql":
|
||||||
|
conf.UseMSSQL = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return gormDB, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTestEngine() error {
|
func NewTestEngine() error {
|
||||||
x, err := getEngine()
|
var err error
|
||||||
|
db, err = getGormDB(&dbutil.Logger{Writer: os.Stdout})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Newf("connect to database: %v", err)
|
return errors.Newf("connect to database: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if conf.UsePostgreSQL {
|
for _, table := range legacyTables {
|
||||||
x.SetSchema(conf.Database.Schema)
|
if db.Migrator().HasTable(table) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err = db.Migrator().AutoMigrate(table); err != nil {
|
||||||
|
return errors.Wrap(err, "auto migrate")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
x.SetMapper(core.GonicMapper{})
|
|
||||||
return x.StoreEngine("InnoDB").Sync2(legacyTables...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetEngine() (*gorm.DB, error) {
|
func SetEngine() (*gorm.DB, error) {
|
||||||
var err error
|
|
||||||
x, err = getEngine()
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Newf("connect to database: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if conf.UsePostgreSQL {
|
|
||||||
x.SetSchema(conf.Database.Schema)
|
|
||||||
}
|
|
||||||
|
|
||||||
x.SetMapper(core.GonicMapper{})
|
|
||||||
|
|
||||||
var logPath string
|
var logPath string
|
||||||
if conf.HookMode {
|
if conf.HookMode {
|
||||||
logPath = filepath.Join(conf.Log.RootPath, "hooks", "xorm.log")
|
logPath = filepath.Join(conf.Log.RootPath, "hooks", "gorm.log")
|
||||||
} else {
|
} else {
|
||||||
logPath = filepath.Join(conf.Log.RootPath, "xorm.log")
|
logPath = filepath.Join(conf.Log.RootPath, "gorm.log")
|
||||||
}
|
}
|
||||||
sec := conf.File.Section("log.xorm")
|
sec := conf.File.Section("log.gorm")
|
||||||
fileWriter, err := log.NewFileWriter(logPath,
|
fileWriter, err := log.NewFileWriter(logPath,
|
||||||
log.FileRotationConfig{
|
log.FileRotationConfig{
|
||||||
Rotate: sec.Key("ROTATE").MustBool(true),
|
Rotate: sec.Key("ROTATE").MustBool(true),
|
||||||
@@ -151,20 +130,9 @@ func SetEngine() (*gorm.DB, error) {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Newf("create 'xorm.log': %v", err)
|
return nil, errors.Newf("create 'gorm.log': %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
x.SetMaxOpenConns(conf.Database.MaxOpenConns)
|
|
||||||
x.SetMaxIdleConns(conf.Database.MaxIdleConns)
|
|
||||||
x.SetConnMaxLifetime(time.Second)
|
|
||||||
|
|
||||||
if conf.IsProdMode() {
|
|
||||||
x.SetLogger(xorm.NewSimpleLogger3(fileWriter, xorm.DEFAULT_LOG_PREFIX, xorm.DEFAULT_LOG_FLAG, core.LOG_ERR))
|
|
||||||
} else {
|
|
||||||
x.SetLogger(xorm.NewSimpleLogger(fileWriter))
|
|
||||||
}
|
|
||||||
x.ShowSQL(true)
|
|
||||||
|
|
||||||
var gormLogger logger.Writer
|
var gormLogger logger.Writer
|
||||||
if conf.HookMode {
|
if conf.HookMode {
|
||||||
gormLogger = &dbutil.Logger{Writer: fileWriter}
|
gormLogger = &dbutil.Logger{Writer: fileWriter}
|
||||||
@@ -174,23 +142,37 @@ func SetEngine() (*gorm.DB, error) {
|
|||||||
return nil, errors.Wrap(err, "new log writer")
|
return nil, errors.Wrap(err, "new log writer")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
db, err = getGormDB(gormLogger)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return NewConnection(gormLogger)
|
return NewConnection(gormLogger)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEngine() error {
|
func NewEngine() error {
|
||||||
db, err := SetEngine()
|
gormDB, err := SetEngine()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = migrations.Migrate(db); err != nil {
|
if err = migrations.Migrate(gormDB); err != nil {
|
||||||
return errors.Newf("migrate: %v", err)
|
return errors.Newf("migrate: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = x.StoreEngine("InnoDB").Sync2(legacyTables...); err != nil {
|
for _, table := range legacyTables {
|
||||||
return errors.Wrap(err, "sync tables")
|
if gormDB.Migrator().HasTable(table) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
name := strings.TrimPrefix(fmt.Sprintf("%T", table), "*database.")
|
||||||
|
if err = gormDB.Migrator().AutoMigrate(table); err != nil {
|
||||||
|
return errors.Wrapf(err, "auto migrate %q", name)
|
||||||
|
}
|
||||||
|
log.Trace("Auto migrated %q", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HasEngine = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,33 +190,54 @@ type Statistic struct {
|
|||||||
func GetStatistic(ctx context.Context) (stats Statistic) {
|
func GetStatistic(ctx context.Context) (stats Statistic) {
|
||||||
stats.Counter.User = Handle.Users().Count(ctx)
|
stats.Counter.User = Handle.Users().Count(ctx)
|
||||||
stats.Counter.Org = CountOrganizations()
|
stats.Counter.Org = CountOrganizations()
|
||||||
stats.Counter.PublicKey, _ = x.Count(new(PublicKey))
|
var count int64
|
||||||
|
db.Model(new(PublicKey)).Count(&count)
|
||||||
|
stats.Counter.PublicKey = count
|
||||||
stats.Counter.Repo = CountRepositories(true)
|
stats.Counter.Repo = CountRepositories(true)
|
||||||
stats.Counter.Watch, _ = x.Count(new(Watch))
|
db.Model(new(Watch)).Count(&count)
|
||||||
stats.Counter.Star, _ = x.Count(new(Star))
|
stats.Counter.Watch = count
|
||||||
stats.Counter.Action, _ = x.Count(new(Action))
|
db.Model(new(Star)).Count(&count)
|
||||||
stats.Counter.Access, _ = x.Count(new(Access))
|
stats.Counter.Star = count
|
||||||
stats.Counter.Issue, _ = x.Count(new(Issue))
|
db.Model(new(Action)).Count(&count)
|
||||||
stats.Counter.Comment, _ = x.Count(new(Comment))
|
stats.Counter.Action = count
|
||||||
|
db.Model(new(Access)).Count(&count)
|
||||||
|
stats.Counter.Access = count
|
||||||
|
db.Model(new(Issue)).Count(&count)
|
||||||
|
stats.Counter.Issue = count
|
||||||
|
db.Model(new(Comment)).Count(&count)
|
||||||
|
stats.Counter.Comment = count
|
||||||
stats.Counter.Oauth = 0
|
stats.Counter.Oauth = 0
|
||||||
stats.Counter.Follow, _ = x.Count(new(Follow))
|
db.Model(new(Follow)).Count(&count)
|
||||||
stats.Counter.Mirror, _ = x.Count(new(Mirror))
|
stats.Counter.Follow = count
|
||||||
stats.Counter.Release, _ = x.Count(new(Release))
|
db.Model(new(Mirror)).Count(&count)
|
||||||
|
stats.Counter.Mirror = count
|
||||||
|
db.Model(new(Release)).Count(&count)
|
||||||
|
stats.Counter.Release = count
|
||||||
stats.Counter.LoginSource = Handle.LoginSources().Count(ctx)
|
stats.Counter.LoginSource = Handle.LoginSources().Count(ctx)
|
||||||
stats.Counter.Webhook, _ = x.Count(new(Webhook))
|
db.Model(new(Webhook)).Count(&count)
|
||||||
stats.Counter.Milestone, _ = x.Count(new(Milestone))
|
stats.Counter.Webhook = count
|
||||||
stats.Counter.Label, _ = x.Count(new(Label))
|
db.Model(new(Milestone)).Count(&count)
|
||||||
stats.Counter.HookTask, _ = x.Count(new(HookTask))
|
stats.Counter.Milestone = count
|
||||||
stats.Counter.Team, _ = x.Count(new(Team))
|
db.Model(new(Label)).Count(&count)
|
||||||
stats.Counter.Attachment, _ = x.Count(new(Attachment))
|
stats.Counter.Label = count
|
||||||
|
db.Model(new(HookTask)).Count(&count)
|
||||||
|
stats.Counter.HookTask = count
|
||||||
|
db.Model(new(Team)).Count(&count)
|
||||||
|
stats.Counter.Team = count
|
||||||
|
db.Model(new(Attachment)).Count(&count)
|
||||||
|
stats.Counter.Attachment = count
|
||||||
return stats
|
return stats
|
||||||
}
|
}
|
||||||
|
|
||||||
func Ping() error {
|
func Ping() error {
|
||||||
if x == nil {
|
if db == nil {
|
||||||
return errors.New("database not available")
|
return errors.New("database not available")
|
||||||
}
|
}
|
||||||
return x.Ping()
|
sqlDB, err := db.DB()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return sqlDB.Ping()
|
||||||
}
|
}
|
||||||
|
|
||||||
// The version table. Should have only one row with id==1
|
// The version table. Should have only one row with id==1
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/cockroachdb/errors"
|
"github.com/cockroachdb/errors"
|
||||||
"xorm.io/builder"
|
"gorm.io/gorm"
|
||||||
"xorm.io/xorm"
|
|
||||||
|
|
||||||
"gogs.io/gogs/internal/errutil"
|
"gogs.io/gogs/internal/errutil"
|
||||||
"gogs.io/gogs/internal/repoutil"
|
"gogs.io/gogs/internal/repoutil"
|
||||||
@@ -26,32 +25,32 @@ func (org *User) IsOrgMember(uid int64) bool {
|
|||||||
return org.IsOrganization() && IsOrganizationMember(org.ID, uid)
|
return org.IsOrganization() && IsOrganizationMember(org.ID, uid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (org *User) getTeam(e Engine, name string) (*Team, error) {
|
func (org *User) getTeam(tx *gorm.DB, name string) (*Team, error) {
|
||||||
return getTeamOfOrgByName(e, org.ID, name)
|
return getTeamOfOrgByName(tx, org.ID, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTeamOfOrgByName returns named team of organization.
|
// GetTeamOfOrgByName returns named team of organization.
|
||||||
func (org *User) GetTeam(name string) (*Team, error) {
|
func (org *User) GetTeam(name string) (*Team, error) {
|
||||||
return org.getTeam(x, name)
|
return org.getTeam(db, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (org *User) getOwnerTeam(e Engine) (*Team, error) {
|
func (org *User) getOwnerTeam(tx *gorm.DB) (*Team, error) {
|
||||||
return org.getTeam(e, ownerTeamName)
|
return org.getTeam(tx, ownerTeamName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOwnerTeam returns owner team of organization.
|
// GetOwnerTeam returns owner team of organization.
|
||||||
func (org *User) GetOwnerTeam() (*Team, error) {
|
func (org *User) GetOwnerTeam() (*Team, error) {
|
||||||
return org.getOwnerTeam(x)
|
return org.getOwnerTeam(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (org *User) getTeams(e Engine) (err error) {
|
func (org *User) getTeams(tx *gorm.DB) (err error) {
|
||||||
org.Teams, err = getTeamsByOrgID(e, org.ID)
|
org.Teams, err = getTeamsByOrgID(tx, org.ID)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTeams returns all teams that belong to organization.
|
// GetTeams returns all teams that belong to organization.
|
||||||
func (org *User) GetTeams() error {
|
func (org *User) GetTeams() error {
|
||||||
return org.getTeams(x)
|
return org.getTeams(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TeamsHaveAccessToRepo returns all teams that have given access level to the repository.
|
// TeamsHaveAccessToRepo returns all teams that have given access level to the repository.
|
||||||
@@ -86,13 +85,13 @@ func (org *User) RemoveMember(uid int64) error {
|
|||||||
return RemoveOrgUser(org.ID, uid)
|
return RemoveOrgUser(org.ID, uid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (org *User) removeOrgRepo(e Engine, repoID int64) error {
|
func (org *User) removeOrgRepo(tx *gorm.DB, repoID int64) error {
|
||||||
return removeOrgRepo(e, org.ID, repoID)
|
return removeOrgRepo(tx, org.ID, repoID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveOrgRepo removes all team-repository relations of organization.
|
// RemoveOrgRepo removes all team-repository relations of organization.
|
||||||
func (org *User) RemoveOrgRepo(repoID int64) error {
|
func (org *User) RemoveOrgRepo(repoID int64) error {
|
||||||
return org.removeOrgRepo(x, repoID)
|
return org.removeOrgRepo(db, repoID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateOrganization creates record of a new organization.
|
// CreateOrganization creates record of a new organization.
|
||||||
@@ -121,52 +120,48 @@ func CreateOrganization(org, owner *User) (err error) {
|
|||||||
org.NumTeams = 1
|
org.NumTeams = 1
|
||||||
org.NumMembers = 1
|
org.NumMembers = 1
|
||||||
|
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
if err := tx.Create(org).Error; err != nil {
|
||||||
if err = sess.Begin(); err != nil {
|
return errors.Newf("insert organization: %v", err)
|
||||||
return err
|
}
|
||||||
}
|
_ = userutil.GenerateRandomAvatar(org.ID, org.Name, org.Email)
|
||||||
|
|
||||||
if _, err = sess.Insert(org); err != nil {
|
// Add initial creator to organization and owner team.
|
||||||
return errors.Newf("insert organization: %v", err)
|
if err := tx.Create(&OrgUser{
|
||||||
}
|
UID: owner.ID,
|
||||||
_ = userutil.GenerateRandomAvatar(org.ID, org.Name, org.Email)
|
OrgID: org.ID,
|
||||||
|
IsOwner: true,
|
||||||
|
NumTeams: 1,
|
||||||
|
}).Error; err != nil {
|
||||||
|
return errors.Newf("insert org-user relation: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Add initial creator to organization and owner team.
|
// Create default owner team.
|
||||||
if _, err = sess.Insert(&OrgUser{
|
t := &Team{
|
||||||
UID: owner.ID,
|
OrgID: org.ID,
|
||||||
OrgID: org.ID,
|
LowerName: strings.ToLower(ownerTeamName),
|
||||||
IsOwner: true,
|
Name: ownerTeamName,
|
||||||
NumTeams: 1,
|
Authorize: AccessModeOwner,
|
||||||
}); err != nil {
|
NumMembers: 1,
|
||||||
return errors.Newf("insert org-user relation: %v", err)
|
}
|
||||||
}
|
if err := tx.Create(t).Error; err != nil {
|
||||||
|
return errors.Newf("insert owner team: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Create default owner team.
|
if err := tx.Create(&TeamUser{
|
||||||
t := &Team{
|
UID: owner.ID,
|
||||||
OrgID: org.ID,
|
OrgID: org.ID,
|
||||||
LowerName: strings.ToLower(ownerTeamName),
|
TeamID: t.ID,
|
||||||
Name: ownerTeamName,
|
}).Error; err != nil {
|
||||||
Authorize: AccessModeOwner,
|
return errors.Newf("insert team-user relation: %v", err)
|
||||||
NumMembers: 1,
|
}
|
||||||
}
|
|
||||||
if _, err = sess.Insert(t); err != nil {
|
|
||||||
return errors.Newf("insert owner team: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = sess.Insert(&TeamUser{
|
if err := os.MkdirAll(repoutil.UserPath(org.Name), os.ModePerm); err != nil {
|
||||||
UID: owner.ID,
|
return errors.Newf("create directory: %v", err)
|
||||||
OrgID: org.ID,
|
}
|
||||||
TeamID: t.ID,
|
|
||||||
}); err != nil {
|
|
||||||
return errors.Newf("insert team-user relation: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = os.MkdirAll(repoutil.UserPath(org.Name), os.ModePerm); err != nil {
|
return nil
|
||||||
return errors.Newf("create directory: %v", err)
|
})
|
||||||
}
|
|
||||||
|
|
||||||
return sess.Commit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOrgByName returns organization by given name.
|
// GetOrgByName returns organization by given name.
|
||||||
@@ -174,35 +169,36 @@ func GetOrgByName(name string) (*User, error) {
|
|||||||
if name == "" {
|
if name == "" {
|
||||||
return nil, ErrOrgNotExist
|
return nil, ErrOrgNotExist
|
||||||
}
|
}
|
||||||
u := &User{
|
u := &User{}
|
||||||
LowerName: strings.ToLower(name),
|
err := db.Where("lower_name = ? AND type = ?", strings.ToLower(name), UserTypeOrganization).First(u).Error
|
||||||
Type: UserTypeOrganization,
|
|
||||||
}
|
|
||||||
has, err := x.Get(u)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, ErrOrgNotExist
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
|
||||||
return nil, ErrOrgNotExist
|
|
||||||
}
|
}
|
||||||
return u, nil
|
return u, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CountOrganizations returns number of organizations.
|
// CountOrganizations returns number of organizations.
|
||||||
func CountOrganizations() int64 {
|
func CountOrganizations() int64 {
|
||||||
count, _ := x.Where("type=1").Count(new(User))
|
var count int64
|
||||||
|
db.Model(new(User)).Where("type = ?", UserTypeOrganization).Count(&count)
|
||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
// Organizations returns number of organizations in given page.
|
// Organizations returns number of organizations in given page.
|
||||||
func Organizations(page, pageSize int) ([]*User, error) {
|
func Organizations(page, pageSize int) ([]*User, error) {
|
||||||
orgs := make([]*User, 0, pageSize)
|
orgs := make([]*User, 0, pageSize)
|
||||||
return orgs, x.Limit(pageSize, (page-1)*pageSize).Where("type=1").Asc("id").Find(&orgs)
|
return orgs, db.Where("type = ?", UserTypeOrganization).
|
||||||
|
Offset((page - 1) * pageSize).Limit(pageSize).
|
||||||
|
Order("id ASC").Find(&orgs).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// deleteBeans deletes all given beans, beans should contain delete conditions.
|
// deleteBeans deletes all given beans, beans should contain delete conditions.
|
||||||
func deleteBeans(e Engine, beans ...any) (err error) {
|
func deleteBeans(tx *gorm.DB, beans ...any) (err error) {
|
||||||
for i := range beans {
|
for i := range beans {
|
||||||
if _, err = e.Delete(beans[i]); err != nil {
|
if err = tx.Delete(beans[i]).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -216,20 +212,13 @@ func DeleteOrganization(org *User) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
return deleteBeans(tx,
|
||||||
if err = sess.Begin(); err != nil {
|
&Team{OrgID: org.ID},
|
||||||
return err
|
&OrgUser{OrgID: org.ID},
|
||||||
}
|
&TeamUser{OrgID: org.ID},
|
||||||
|
)
|
||||||
if err = deleteBeans(sess,
|
})
|
||||||
&Team{OrgID: org.ID},
|
|
||||||
&OrgUser{OrgID: org.ID},
|
|
||||||
&TeamUser{OrgID: org.ID},
|
|
||||||
); err != nil {
|
|
||||||
return errors.Newf("deleteBeans: %v", err)
|
|
||||||
}
|
|
||||||
return sess.Commit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ________ ____ ___
|
// ________ ____ ___
|
||||||
@@ -251,84 +240,94 @@ type OrgUser struct {
|
|||||||
|
|
||||||
// IsOrganizationOwner returns true if given user is in the owner team.
|
// IsOrganizationOwner returns true if given user is in the owner team.
|
||||||
func IsOrganizationOwner(orgID, userID int64) bool {
|
func IsOrganizationOwner(orgID, userID int64) bool {
|
||||||
has, _ := x.Where("is_owner = ?", true).And("uid = ?", userID).And("org_id = ?", orgID).Get(new(OrgUser))
|
var count int64
|
||||||
return has
|
db.Model(new(OrgUser)).Where("is_owner = ? AND uid = ? AND org_id = ?", true, userID, orgID).Count(&count)
|
||||||
|
return count > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsOrganizationMember returns true if given user is member of organization.
|
// IsOrganizationMember returns true if given user is member of organization.
|
||||||
func IsOrganizationMember(orgID, uid int64) bool {
|
func IsOrganizationMember(orgID, uid int64) bool {
|
||||||
has, _ := x.Where("uid=?", uid).And("org_id=?", orgID).Get(new(OrgUser))
|
var count int64
|
||||||
return has
|
db.Model(new(OrgUser)).Where("uid = ? AND org_id = ?", uid, orgID).Count(&count)
|
||||||
|
return count > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsPublicMembership returns true if given user public his/her membership.
|
// IsPublicMembership returns true if given user public his/her membership.
|
||||||
func IsPublicMembership(orgID, uid int64) bool {
|
func IsPublicMembership(orgID, uid int64) bool {
|
||||||
has, _ := x.Where("uid=?", uid).And("org_id=?", orgID).And("is_public=?", true).Get(new(OrgUser))
|
var count int64
|
||||||
return has
|
db.Model(new(OrgUser)).Where("uid = ? AND org_id = ? AND is_public = ?", uid, orgID, true).Count(&count)
|
||||||
|
return count > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func getOrgsByUserID(sess *xorm.Session, userID int64, showAll bool) ([]*User, error) {
|
func getOrgsByUserID(tx *gorm.DB, userID int64, showAll bool) ([]*User, error) {
|
||||||
orgs := make([]*User, 0, 10)
|
orgs := make([]*User, 0, 10)
|
||||||
|
query := tx.Table("`user`").
|
||||||
|
Joins("INNER JOIN `org_user` ON `org_user`.org_id = `user`.id").
|
||||||
|
Where("`org_user`.uid = ?", userID)
|
||||||
if !showAll {
|
if !showAll {
|
||||||
sess.And("`org_user`.is_public=?", true)
|
query = query.Where("`org_user`.is_public = ?", true)
|
||||||
}
|
}
|
||||||
return orgs, sess.And("`org_user`.uid=?", userID).
|
return orgs, query.Find(&orgs).Error
|
||||||
Join("INNER", "`org_user`", "`org_user`.org_id=`user`.id").Find(&orgs)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOrgsByUserID returns a list of organizations that the given user ID
|
// GetOrgsByUserID returns a list of organizations that the given user ID
|
||||||
// has joined.
|
// has joined.
|
||||||
func GetOrgsByUserID(userID int64, showAll bool) ([]*User, error) {
|
func GetOrgsByUserID(userID int64, showAll bool) ([]*User, error) {
|
||||||
return getOrgsByUserID(x.NewSession(), userID, showAll)
|
return getOrgsByUserID(db, userID, showAll)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getOwnedOrgsByUserID(sess *xorm.Session, userID int64) ([]*User, error) {
|
func getOwnedOrgsByUserID(tx *gorm.DB, userID int64) ([]*User, error) {
|
||||||
orgs := make([]*User, 0, 10)
|
orgs := make([]*User, 0, 10)
|
||||||
return orgs, sess.Where("`org_user`.uid=?", userID).And("`org_user`.is_owner=?", true).
|
return orgs, tx.Table("`user`").
|
||||||
Join("INNER", "`org_user`", "`org_user`.org_id=`user`.id").Find(&orgs)
|
Joins("INNER JOIN `org_user` ON `org_user`.org_id = `user`.id").
|
||||||
|
Where("`org_user`.uid = ? AND `org_user`.is_owner = ?", userID, true).
|
||||||
|
Find(&orgs).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOwnedOrgsByUserID returns a list of organizations are owned by given user ID.
|
// GetOwnedOrgsByUserID returns a list of organizations are owned by given user ID.
|
||||||
func GetOwnedOrgsByUserID(userID int64) ([]*User, error) {
|
func GetOwnedOrgsByUserID(userID int64) ([]*User, error) {
|
||||||
sess := x.NewSession()
|
return getOwnedOrgsByUserID(db, userID)
|
||||||
return getOwnedOrgsByUserID(sess, userID)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOwnedOrganizationsByUserIDDesc returns a list of organizations are owned by
|
// GetOwnedOrganizationsByUserIDDesc returns a list of organizations are owned by
|
||||||
// given user ID, ordered descending by the given condition.
|
// given user ID, ordered descending by the given condition.
|
||||||
func GetOwnedOrgsByUserIDDesc(userID int64, desc string) ([]*User, error) {
|
func GetOwnedOrgsByUserIDDesc(userID int64, desc string) ([]*User, error) {
|
||||||
sess := x.NewSession()
|
orgs := make([]*User, 0, 10)
|
||||||
return getOwnedOrgsByUserID(sess.Desc(desc), userID)
|
return orgs, db.Table("`user`").
|
||||||
|
Joins("INNER JOIN `org_user` ON `org_user`.org_id = `user`.id").
|
||||||
|
Where("`org_user`.uid = ? AND `org_user`.is_owner = ?", userID, true).
|
||||||
|
Order(desc + " DESC").
|
||||||
|
Find(&orgs).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func getOrgUsersByOrgID(e Engine, orgID int64, limit int) ([]*OrgUser, error) {
|
func getOrgUsersByOrgID(tx *gorm.DB, orgID int64, limit int) ([]*OrgUser, error) {
|
||||||
orgUsers := make([]*OrgUser, 0, 10)
|
orgUsers := make([]*OrgUser, 0, 10)
|
||||||
|
|
||||||
sess := e.Where("org_id=?", orgID)
|
query := tx.Where("org_id = ?", orgID)
|
||||||
if limit > 0 {
|
if limit > 0 {
|
||||||
sess = sess.Limit(limit)
|
query = query.Limit(limit)
|
||||||
}
|
}
|
||||||
return orgUsers, sess.Find(&orgUsers)
|
return orgUsers, query.Find(&orgUsers).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOrgUsersByOrgID returns all organization-user relations by organization ID.
|
// GetOrgUsersByOrgID returns all organization-user relations by organization ID.
|
||||||
func GetOrgUsersByOrgID(orgID int64, limit int) ([]*OrgUser, error) {
|
func GetOrgUsersByOrgID(orgID int64, limit int) ([]*OrgUser, error) {
|
||||||
return getOrgUsersByOrgID(x, orgID, limit)
|
return getOrgUsersByOrgID(db, orgID, limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChangeOrgUserStatus changes public or private membership status.
|
// ChangeOrgUserStatus changes public or private membership status.
|
||||||
func ChangeOrgUserStatus(orgID, uid int64, public bool) error {
|
func ChangeOrgUserStatus(orgID, uid int64, public bool) error {
|
||||||
ou := new(OrgUser)
|
ou := new(OrgUser)
|
||||||
has, err := x.Where("uid=?", uid).And("org_id=?", orgID).Get(ou)
|
err := db.Where("uid = ? AND org_id = ?", uid, orgID).First(ou).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
} else if !has {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ou.IsPublic = public
|
ou.IsPublic = public
|
||||||
_, err = x.Id(ou.ID).AllCols().Update(ou)
|
return db.Model(ou).Where("id = ?", ou.ID).Updates(ou).Error
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddOrgUser adds new user to given organization.
|
// AddOrgUser adds new user to given organization.
|
||||||
@@ -337,35 +336,33 @@ func AddOrgUser(orgID, uid int64) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
ou := &OrgUser{
|
||||||
if err := sess.Begin(); err != nil {
|
UID: uid,
|
||||||
return err
|
OrgID: orgID,
|
||||||
}
|
}
|
||||||
|
|
||||||
ou := &OrgUser{
|
if err := tx.Create(ou).Error; err != nil {
|
||||||
UID: uid,
|
return err
|
||||||
OrgID: orgID,
|
}
|
||||||
}
|
if err := tx.Exec("UPDATE `user` SET num_members = num_members + 1 WHERE id = ?", orgID).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if _, err := sess.Insert(ou); err != nil {
|
return nil
|
||||||
return err
|
})
|
||||||
} else if _, err = sess.Exec("UPDATE `user` SET num_members = num_members + 1 WHERE id = ?", orgID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return sess.Commit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveOrgUser removes user from given organization.
|
// RemoveOrgUser removes user from given organization.
|
||||||
func RemoveOrgUser(orgID, userID int64) error {
|
func RemoveOrgUser(orgID, userID int64) error {
|
||||||
ou := new(OrgUser)
|
ou := new(OrgUser)
|
||||||
|
|
||||||
has, err := x.Where("uid=?", userID).And("org_id=?", orgID).Get(ou)
|
err := db.Where("uid = ? AND org_id = ?", userID, orgID).First(ou).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return errors.Newf("get org-user: %v", err)
|
return errors.Newf("get org-user: %v", err)
|
||||||
} else if !has {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := Handle.Users().GetByID(context.TODO(), userID)
|
user, err := Handle.Users().GetByID(context.TODO(), userID)
|
||||||
@@ -394,71 +391,69 @@ func RemoveOrgUser(orgID, userID int64) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
if err := tx.Where("id = ?", ou.ID).Delete(ou).Error; err != nil {
|
||||||
if err := sess.Begin(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := sess.ID(ou.ID).Delete(ou); err != nil {
|
|
||||||
return err
|
|
||||||
} else if _, err = sess.Exec("UPDATE `user` SET num_members=num_members-1 WHERE id=?", orgID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete all repository accesses and unwatch them.
|
|
||||||
repoIDs := make([]int64, 0, len(repos))
|
|
||||||
for i := range repos {
|
|
||||||
repoIDs = append(repoIDs, repos[i].ID)
|
|
||||||
if err = watchRepo(sess, user.ID, repos[i].ID, false); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
if err := tx.Exec("UPDATE `user` SET num_members = num_members - 1 WHERE id = ?", orgID).Error; err != nil {
|
||||||
|
|
||||||
if len(repoIDs) > 0 {
|
|
||||||
if _, err = sess.Where("user_id = ?", user.ID).In("repo_id", repoIDs).Delete(new(Access)); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Delete member in his/her teams.
|
// Delete all repository accesses and unwatch them.
|
||||||
teams, err := getUserTeams(sess, org.ID, user.ID)
|
repoIDs := make([]int64, 0, len(repos))
|
||||||
if err != nil {
|
for i := range repos {
|
||||||
return err
|
repoIDs = append(repoIDs, repos[i].ID)
|
||||||
}
|
if err = watchRepo(tx, user.ID, repos[i].ID, false); err != nil {
|
||||||
for _, t := range teams {
|
return err
|
||||||
if err = removeTeamMember(sess, org.ID, t.ID, user.ID); err != nil {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(repoIDs) > 0 {
|
||||||
|
if err := tx.Where("user_id = ? AND repo_id IN ?", user.ID, repoIDs).Delete(new(Access)).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete member in his/her teams.
|
||||||
|
teams, err := getUserTeams(tx, org.ID, user.ID)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
for _, t := range teams {
|
||||||
|
if err = removeTeamMember(tx, org.ID, t.ID, user.ID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return sess.Commit()
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeOrgRepo(e Engine, orgID, repoID int64) error {
|
func removeOrgRepo(tx *gorm.DB, orgID, repoID int64) error {
|
||||||
_, err := e.Delete(&TeamRepo{
|
return tx.Where("org_id = ? AND repo_id = ?", orgID, repoID).Delete(&TeamRepo{}).Error
|
||||||
OrgID: orgID,
|
|
||||||
RepoID: repoID,
|
|
||||||
})
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveOrgRepo removes all team-repository relations of given organization.
|
// RemoveOrgRepo removes all team-repository relations of given organization.
|
||||||
func RemoveOrgRepo(orgID, repoID int64) error {
|
func RemoveOrgRepo(orgID, repoID int64) error {
|
||||||
return removeOrgRepo(x, orgID, repoID)
|
return removeOrgRepo(db, orgID, repoID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (org *User) getUserTeams(e Engine, userID int64, cols ...string) ([]*Team, error) {
|
func (org *User) getUserTeams(tx *gorm.DB, userID int64, cols ...string) ([]*Team, error) {
|
||||||
teams := make([]*Team, 0, org.NumTeams)
|
teams := make([]*Team, 0, org.NumTeams)
|
||||||
return teams, e.Where("team_user.org_id = ?", org.ID).
|
query := tx.Table("team").
|
||||||
And("team_user.uid = ?", userID).
|
Joins("INNER JOIN team_user ON team_user.team_id = team.id").
|
||||||
Join("INNER", "team_user", "team_user.team_id = team.id").
|
Where("team_user.org_id = ? AND team_user.uid = ?", org.ID, userID)
|
||||||
Cols(cols...).Find(&teams)
|
|
||||||
|
if len(cols) > 0 {
|
||||||
|
query = query.Select(cols)
|
||||||
|
}
|
||||||
|
|
||||||
|
return teams, query.Find(&teams).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserTeamIDs returns of all team IDs of the organization that user is member of.
|
// GetUserTeamIDs returns of all team IDs of the organization that user is member of.
|
||||||
func (org *User) GetUserTeamIDs(userID int64) ([]int64, error) {
|
func (org *User) GetUserTeamIDs(userID int64) ([]int64, error) {
|
||||||
teams, err := org.getUserTeams(x, userID, "team.id")
|
teams, err := org.getUserTeams(db, userID, "team.id")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Newf("getUserTeams [%d]: %v", userID, err)
|
return nil, errors.Newf("getUserTeams [%d]: %v", userID, err)
|
||||||
}
|
}
|
||||||
@@ -473,7 +468,7 @@ func (org *User) GetUserTeamIDs(userID int64) ([]int64, error) {
|
|||||||
// GetTeams returns all teams that belong to organization,
|
// GetTeams returns all teams that belong to organization,
|
||||||
// and that the user has joined.
|
// and that the user has joined.
|
||||||
func (org *User) GetUserTeams(userID int64) ([]*Team, error) {
|
func (org *User) GetUserTeams(userID int64) ([]*Team, error) {
|
||||||
return org.getUserTeams(x, userID)
|
return org.getUserTeams(db, userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserRepositories returns a range of repositories in organization which the user has access to,
|
// GetUserRepositories returns a range of repositories in organization which the user has access to,
|
||||||
@@ -489,7 +484,7 @@ func (org *User) GetUserRepositories(userID int64, page, pageSize int) ([]*Repos
|
|||||||
}
|
}
|
||||||
|
|
||||||
var teamRepoIDs []int64
|
var teamRepoIDs []int64
|
||||||
if err = x.Table("team_repo").In("team_id", teamIDs).Distinct("repo_id").Find(&teamRepoIDs); err != nil {
|
if err = db.Table("team_repo").Where("team_id IN ?", teamIDs).Distinct("repo_id").Find(&teamRepoIDs).Error; err != nil {
|
||||||
return nil, 0, errors.Newf("get team repository IDs: %v", err)
|
return nil, 0, errors.Newf("get team repository IDs: %v", err)
|
||||||
}
|
}
|
||||||
if len(teamRepoIDs) == 0 {
|
if len(teamRepoIDs) == 0 {
|
||||||
@@ -501,22 +496,18 @@ func (org *User) GetUserRepositories(userID int64, page, pageSize int) ([]*Repos
|
|||||||
page = 1
|
page = 1
|
||||||
}
|
}
|
||||||
repos := make([]*Repository, 0, pageSize)
|
repos := make([]*Repository, 0, pageSize)
|
||||||
if err = x.Where("owner_id = ?", org.ID).
|
if err = db.Where("owner_id = ?", org.ID).
|
||||||
And(builder.Or(
|
Where(db.Where("is_private = ? AND is_unlisted = ?", false, false).Or("id IN ?", teamRepoIDs)).
|
||||||
builder.And(builder.Expr("is_private = ?", false), builder.Expr("is_unlisted = ?", false)),
|
Order("updated_unix DESC").
|
||||||
builder.In("id", teamRepoIDs))).
|
Limit(pageSize).Offset((page - 1) * pageSize).
|
||||||
Desc("updated_unix").
|
Find(&repos).Error; err != nil {
|
||||||
Limit(pageSize, (page-1)*pageSize).
|
|
||||||
Find(&repos); err != nil {
|
|
||||||
return nil, 0, errors.Newf("get user repositories: %v", err)
|
return nil, 0, errors.Newf("get user repositories: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
repoCount, err := x.Where("owner_id = ?", org.ID).
|
var repoCount int64
|
||||||
And(builder.Or(
|
if err = db.Model(&Repository{}).Where("owner_id = ?", org.ID).
|
||||||
builder.Expr("is_private = ?", false),
|
Where(db.Where("is_private = ?", false).Or("id IN ?", teamRepoIDs)).
|
||||||
builder.In("id", teamRepoIDs))).
|
Count(&repoCount).Error; err != nil {
|
||||||
Count(new(Repository))
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, errors.Newf("count user repositories: %v", err)
|
return nil, 0, errors.Newf("count user repositories: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -534,7 +525,7 @@ func (org *User) GetUserMirrorRepositories(userID int64) ([]*Repository, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
var teamRepoIDs []int64
|
var teamRepoIDs []int64
|
||||||
err = x.Table("team_repo").In("team_id", teamIDs).Distinct("repo_id").Find(&teamRepoIDs)
|
err = db.Table("team_repo").Where("team_id IN ?", teamIDs).Distinct("repo_id").Find(&teamRepoIDs).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Newf("get team repository ids: %v", err)
|
return nil, errors.Newf("get team repository ids: %v", err)
|
||||||
}
|
}
|
||||||
@@ -544,12 +535,12 @@ func (org *User) GetUserMirrorRepositories(userID int64) ([]*Repository, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
repos := make([]*Repository, 0, 10)
|
repos := make([]*Repository, 0, 10)
|
||||||
if err = x.Where("owner_id = ?", org.ID).
|
if err = db.Where("owner_id = ?", org.ID).
|
||||||
And("is_private = ?", false).
|
Where("is_private = ?", false).
|
||||||
Or(builder.In("id", teamRepoIDs)).
|
Or("id IN ?", teamRepoIDs).
|
||||||
And("is_mirror = ?", true). // Don't move up because it's an independent condition
|
Where("is_mirror = ?", true). // Don't move up because it's an independent condition
|
||||||
Desc("updated_unix").
|
Order("updated_unix DESC").
|
||||||
Find(&repos); err != nil {
|
Find(&repos).Error; err != nil {
|
||||||
return nil, errors.Newf("get user repositories: %v", err)
|
return nil, errors.Newf("get user repositories: %v", err)
|
||||||
}
|
}
|
||||||
return repos, nil
|
return repos, nil
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/cockroachdb/errors"
|
"github.com/cockroachdb/errors"
|
||||||
"xorm.io/xorm"
|
"gorm.io/gorm"
|
||||||
|
|
||||||
"gogs.io/gogs/internal/errutil"
|
"gogs.io/gogs/internal/errutil"
|
||||||
)
|
)
|
||||||
@@ -16,7 +16,7 @@ const ownerTeamName = "Owners"
|
|||||||
// Team represents a organization team.
|
// Team represents a organization team.
|
||||||
type Team struct {
|
type Team struct {
|
||||||
ID int64
|
ID int64
|
||||||
OrgID int64 `xorm:"INDEX"`
|
OrgID int64 `gorm:"index"`
|
||||||
LowerName string
|
LowerName string
|
||||||
Name string
|
Name string
|
||||||
Description string
|
Description string
|
||||||
@@ -27,14 +27,12 @@ type Team struct {
|
|||||||
NumMembers int
|
NumMembers int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Team) AfterSet(colName string, _ xorm.Cell) {
|
func (t *Team) AfterFind(tx *gorm.DB) error {
|
||||||
switch colName {
|
// LEGACY [1.0]: this is backward compatibility bug fix for https://gogs.io/gogs/issues/3671
|
||||||
case "num_repos":
|
if t.NumRepos < 0 {
|
||||||
// LEGACY [1.0]: this is backward compatibility bug fix for https://gogs.io/gogs/issues/3671
|
t.NumRepos = 0
|
||||||
if t.NumRepos < 0 {
|
|
||||||
t.NumRepos = 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsOwnerTeam returns true if team is owner team.
|
// IsOwnerTeam returns true if team is owner team.
|
||||||
@@ -52,15 +50,15 @@ func (t *Team) IsMember(userID int64) bool {
|
|||||||
return IsTeamMember(t.OrgID, t.ID, userID)
|
return IsTeamMember(t.OrgID, t.ID, userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Team) getRepositories(e Engine) (err error) {
|
func (t *Team) getRepositories(tx *gorm.DB) (err error) {
|
||||||
teamRepos := make([]*TeamRepo, 0, t.NumRepos)
|
teamRepos := make([]*TeamRepo, 0, t.NumRepos)
|
||||||
if err = x.Where("team_id=?", t.ID).Find(&teamRepos); err != nil {
|
if err = tx.Where("team_id = ?", t.ID).Find(&teamRepos).Error; err != nil {
|
||||||
return errors.Newf("get team-repos: %v", err)
|
return errors.Newf("get team-repos: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Repos = make([]*Repository, 0, len(teamRepos))
|
t.Repos = make([]*Repository, 0, len(teamRepos))
|
||||||
for i := range teamRepos {
|
for i := range teamRepos {
|
||||||
repo, err := getRepositoryByID(e, teamRepos[i].RepoID)
|
repo, err := getRepositoryByID(tx, teamRepos[i].RepoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Newf("getRepositoryById(%d): %v", teamRepos[i].RepoID, err)
|
return errors.Newf("getRepositoryById(%d): %v", teamRepos[i].RepoID, err)
|
||||||
}
|
}
|
||||||
@@ -71,17 +69,17 @@ func (t *Team) getRepositories(e Engine) (err error) {
|
|||||||
|
|
||||||
// GetRepositories returns all repositories in team of organization.
|
// GetRepositories returns all repositories in team of organization.
|
||||||
func (t *Team) GetRepositories() error {
|
func (t *Team) GetRepositories() error {
|
||||||
return t.getRepositories(x)
|
return t.getRepositories(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Team) getMembers(e Engine) (err error) {
|
func (t *Team) getMembers(tx *gorm.DB) (err error) {
|
||||||
t.Members, err = getTeamMembers(e, t.ID)
|
t.Members, err = getTeamMembers(tx, t.ID)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMembers returns all members in team of organization.
|
// GetMembers returns all members in team of organization.
|
||||||
func (t *Team) GetMembers() (err error) {
|
func (t *Team) GetMembers() (err error) {
|
||||||
return t.getMembers(x)
|
return t.getMembers(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddMember adds new membership of the team to the organization,
|
// AddMember adds new membership of the team to the organization,
|
||||||
@@ -95,34 +93,34 @@ func (t *Team) RemoveMember(uid int64) error {
|
|||||||
return RemoveTeamMember(t.OrgID, t.ID, uid)
|
return RemoveTeamMember(t.OrgID, t.ID, uid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Team) hasRepository(e Engine, repoID int64) bool {
|
func (t *Team) hasRepository(tx *gorm.DB, repoID int64) bool {
|
||||||
return hasTeamRepo(e, t.OrgID, t.ID, repoID)
|
return hasTeamRepo(tx, t.OrgID, t.ID, repoID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasRepository returns true if given repository belong to team.
|
// HasRepository returns true if given repository belong to team.
|
||||||
func (t *Team) HasRepository(repoID int64) bool {
|
func (t *Team) HasRepository(repoID int64) bool {
|
||||||
return t.hasRepository(x, repoID)
|
return t.hasRepository(db, repoID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Team) addRepository(e Engine, repo *Repository) (err error) {
|
func (t *Team) addRepository(tx *gorm.DB, repo *Repository) (err error) {
|
||||||
if err = addTeamRepo(e, t.OrgID, t.ID, repo.ID); err != nil {
|
if err = addTeamRepo(tx, t.OrgID, t.ID, repo.ID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
t.NumRepos++
|
t.NumRepos++
|
||||||
if _, err = e.ID(t.ID).AllCols().Update(t); err != nil {
|
if err = tx.Model(&Team{}).Where("id = ?", t.ID).Updates(t).Error; err != nil {
|
||||||
return errors.Newf("update team: %v", err)
|
return errors.Newf("update team: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = repo.recalculateTeamAccesses(e, 0); err != nil {
|
if err = repo.recalculateTeamAccesses(tx, 0); err != nil {
|
||||||
return errors.Newf("recalculateAccesses: %v", err)
|
return errors.Newf("recalculateAccesses: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = t.getMembers(e); err != nil {
|
if err = t.getMembers(tx); err != nil {
|
||||||
return errors.Newf("getMembers: %v", err)
|
return errors.Newf("getMembers: %v", err)
|
||||||
}
|
}
|
||||||
for _, u := range t.Members {
|
for _, u := range t.Members {
|
||||||
if err = watchRepo(e, u.ID, repo.ID, true); err != nil {
|
if err = watchRepo(tx, u.ID, repo.ID, true); err != nil {
|
||||||
return errors.Newf("watchRepo: %v", err)
|
return errors.Newf("watchRepo: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -137,42 +135,34 @@ func (t *Team) AddRepository(repo *Repository) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
return t.addRepository(tx, repo)
|
||||||
if err = sess.Begin(); err != nil {
|
})
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = t.addRepository(sess, repo); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return sess.Commit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Team) removeRepository(e Engine, repo *Repository, recalculate bool) (err error) {
|
func (t *Team) removeRepository(tx *gorm.DB, repo *Repository, recalculate bool) (err error) {
|
||||||
if err = removeTeamRepo(e, t.ID, repo.ID); err != nil {
|
if err = removeTeamRepo(tx, t.ID, repo.ID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
t.NumRepos--
|
t.NumRepos--
|
||||||
if _, err = e.ID(t.ID).AllCols().Update(t); err != nil {
|
if err = tx.Model(&Team{}).Where("id = ?", t.ID).Updates(t).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't need to recalculate when delete a repository from organization.
|
// Don't need to recalculate when delete a repository from organization.
|
||||||
if recalculate {
|
if recalculate {
|
||||||
if err = repo.recalculateTeamAccesses(e, t.ID); err != nil {
|
if err = repo.recalculateTeamAccesses(tx, t.ID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = t.getMembers(e); err != nil {
|
if err = t.getMembers(tx); err != nil {
|
||||||
return errors.Newf("get team members: %v", err)
|
return errors.Newf("get team members: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Delete me when this method is migrated to use GORM.
|
// TODO: Delete me when this method is migrated to use GORM.
|
||||||
userAccessMode := func(e Engine, userID int64, repo *Repository) (AccessMode, error) {
|
userAccessMode := func(tx *gorm.DB, userID int64, repo *Repository) (AccessMode, error) {
|
||||||
mode := AccessModeNone
|
mode := AccessModeNone
|
||||||
// Everyone has read access to public repository
|
// Everyone has read access to public repository
|
||||||
if !repo.IsPrivate {
|
if !repo.IsPrivate {
|
||||||
@@ -191,26 +181,29 @@ func (t *Team) removeRepository(e Engine, repo *Repository, recalculate bool) (e
|
|||||||
UserID: userID,
|
UserID: userID,
|
||||||
RepoID: repo.ID,
|
RepoID: repo.ID,
|
||||||
}
|
}
|
||||||
if has, err := e.Get(access); !has || err != nil {
|
err := tx.Where("user_id = ? AND repo_id = ?", userID, repo.ID).First(access).Error
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return mode, nil
|
||||||
|
} else if err != nil {
|
||||||
return mode, err
|
return mode, err
|
||||||
}
|
}
|
||||||
return access.Mode, nil
|
return access.Mode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
hasAccess := func(e Engine, userID int64, repo *Repository, testMode AccessMode) (bool, error) {
|
hasAccess := func(tx *gorm.DB, userID int64, repo *Repository, testMode AccessMode) (bool, error) {
|
||||||
mode, err := userAccessMode(e, userID, repo)
|
mode, err := userAccessMode(tx, userID, repo)
|
||||||
return mode >= testMode, err
|
return mode >= testMode, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, member := range t.Members {
|
for _, member := range t.Members {
|
||||||
has, err := hasAccess(e, member.ID, repo, AccessModeRead)
|
has, err := hasAccess(tx, member.ID, repo, AccessModeRead)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
} else if has {
|
} else if has {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = watchRepo(e, member.ID, repo.ID, false); err != nil {
|
if err = watchRepo(tx, member.ID, repo.ID, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -229,17 +222,9 @@ func (t *Team) RemoveRepository(repoID int64) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
return t.removeRepository(tx, repo, true)
|
||||||
if err = sess.Begin(); err != nil {
|
})
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = t.removeRepository(sess, repo, true); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return sess.Commit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var reservedTeamNames = map[string]struct{}{
|
var reservedTeamNames = map[string]struct{}{
|
||||||
@@ -264,37 +249,30 @@ func NewTeam(t *Team) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
has, err := x.Id(t.OrgID).Get(new(User))
|
err := db.Where("id = ?", t.OrgID).First(new(User)).Error
|
||||||
if err != nil {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return err
|
|
||||||
} else if !has {
|
|
||||||
return ErrOrgNotExist
|
return ErrOrgNotExist
|
||||||
|
} else if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
t.LowerName = strings.ToLower(t.Name)
|
t.LowerName = strings.ToLower(t.Name)
|
||||||
existingTeam := Team{}
|
existingTeam := Team{}
|
||||||
has, err = x.Where("org_id=?", t.OrgID).And("lower_name=?", t.LowerName).Get(&existingTeam)
|
err = db.Where("org_id = ? AND lower_name = ?", t.OrgID, t.LowerName).First(&existingTeam).Error
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return err
|
|
||||||
} else if has {
|
|
||||||
return ErrTeamAlreadyExist{existingTeam.ID, t.OrgID, t.LowerName}
|
return ErrTeamAlreadyExist{existingTeam.ID, t.OrgID, t.LowerName}
|
||||||
}
|
} else if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
|
||||||
sess := x.NewSession()
|
|
||||||
defer sess.Close()
|
|
||||||
if err = sess.Begin(); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = sess.Insert(t); err != nil {
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
return err
|
if err := tx.Create(t).Error; err != nil {
|
||||||
}
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Update organization number of teams.
|
// Update organization number of teams.
|
||||||
if _, err = sess.Exec("UPDATE `user` SET num_teams=num_teams+1 WHERE id = ?", t.OrgID); err != nil {
|
return tx.Exec("UPDATE `user` SET num_teams=num_teams+1 WHERE id = ?", t.OrgID).Error
|
||||||
return err
|
})
|
||||||
}
|
|
||||||
return sess.Commit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ errutil.NotFound = (*ErrTeamNotExist)(nil)
|
var _ errutil.NotFound = (*ErrTeamNotExist)(nil)
|
||||||
@@ -316,49 +294,46 @@ func (ErrTeamNotExist) NotFound() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTeamOfOrgByName(e Engine, orgID int64, name string) (*Team, error) {
|
func getTeamOfOrgByName(tx *gorm.DB, orgID int64, name string) (*Team, error) {
|
||||||
t := &Team{
|
t := new(Team)
|
||||||
OrgID: orgID,
|
err := tx.Where("org_id = ? AND lower_name = ?", orgID, strings.ToLower(name)).First(t).Error
|
||||||
LowerName: strings.ToLower(name),
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
}
|
|
||||||
has, err := e.Get(t)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else if !has {
|
|
||||||
return nil, ErrTeamNotExist{args: map[string]any{"orgID": orgID, "name": name}}
|
return nil, ErrTeamNotExist{args: map[string]any{"orgID": orgID, "name": name}}
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTeamOfOrgByName returns team by given team name and organization.
|
// GetTeamOfOrgByName returns team by given team name and organization.
|
||||||
func GetTeamOfOrgByName(orgID int64, name string) (*Team, error) {
|
func GetTeamOfOrgByName(orgID int64, name string) (*Team, error) {
|
||||||
return getTeamOfOrgByName(x, orgID, name)
|
return getTeamOfOrgByName(db, orgID, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTeamByID(e Engine, teamID int64) (*Team, error) {
|
func getTeamByID(tx *gorm.DB, teamID int64) (*Team, error) {
|
||||||
t := new(Team)
|
t := new(Team)
|
||||||
has, err := e.ID(teamID).Get(t)
|
err := tx.Where("id = ?", teamID).First(t).Error
|
||||||
if err != nil {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return nil, err
|
|
||||||
} else if !has {
|
|
||||||
return nil, ErrTeamNotExist{args: map[string]any{"teamID": teamID}}
|
return nil, ErrTeamNotExist{args: map[string]any{"teamID": teamID}}
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTeamByID returns team by given ID.
|
// GetTeamByID returns team by given ID.
|
||||||
func GetTeamByID(teamID int64) (*Team, error) {
|
func GetTeamByID(teamID int64) (*Team, error) {
|
||||||
return getTeamByID(x, teamID)
|
return getTeamByID(db, teamID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTeamsByOrgID(e Engine, orgID int64) ([]*Team, error) {
|
func getTeamsByOrgID(tx *gorm.DB, orgID int64) ([]*Team, error) {
|
||||||
teams := make([]*Team, 0, 3)
|
teams := make([]*Team, 0, 3)
|
||||||
return teams, e.Where("org_id = ?", orgID).Find(&teams)
|
return teams, tx.Where("org_id = ?", orgID).Find(&teams).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTeamsByOrgID returns all teams belong to given organization.
|
// GetTeamsByOrgID returns all teams belong to given organization.
|
||||||
func GetTeamsByOrgID(orgID int64) ([]*Team, error) {
|
func GetTeamsByOrgID(orgID int64) ([]*Team, error) {
|
||||||
return getTeamsByOrgID(x, orgID)
|
return getTeamsByOrgID(db, orgID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateTeam updates information of team.
|
// UpdateTeam updates information of team.
|
||||||
@@ -371,39 +346,35 @@ func UpdateTeam(t *Team, authChanged bool) (err error) {
|
|||||||
t.Description = t.Description[:255]
|
t.Description = t.Description[:255]
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
|
||||||
defer sess.Close()
|
|
||||||
if err = sess.Begin(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
t.LowerName = strings.ToLower(t.Name)
|
t.LowerName = strings.ToLower(t.Name)
|
||||||
existingTeam := new(Team)
|
existingTeam := new(Team)
|
||||||
has, err := x.Where("org_id=?", t.OrgID).And("lower_name=?", t.LowerName).And("id!=?", t.ID).Get(existingTeam)
|
err = db.Where("org_id = ? AND lower_name = ? AND id != ?", t.OrgID, t.LowerName, t.ID).First(existingTeam).Error
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return err
|
|
||||||
} else if has {
|
|
||||||
return ErrTeamAlreadyExist{existingTeam.ID, t.OrgID, t.LowerName}
|
return ErrTeamAlreadyExist{existingTeam.ID, t.OrgID, t.LowerName}
|
||||||
|
} else if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = sess.ID(t.ID).AllCols().Update(t); err != nil {
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
return errors.Newf("update: %v", err)
|
if err := tx.Model(&Team{}).Where("id = ?", t.ID).Updates(t).Error; err != nil {
|
||||||
}
|
return errors.Newf("update: %v", err)
|
||||||
|
|
||||||
// Update access for team members if needed.
|
|
||||||
if authChanged {
|
|
||||||
if err = t.getRepositories(sess); err != nil {
|
|
||||||
return errors.Newf("getRepositories:%v", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, repo := range t.Repos {
|
// Update access for team members if needed.
|
||||||
if err = repo.recalculateTeamAccesses(sess, 0); err != nil {
|
if authChanged {
|
||||||
return errors.Newf("recalculateTeamAccesses: %v", err)
|
if err := t.getRepositories(tx); err != nil {
|
||||||
|
return errors.Newf("getRepositories:%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, repo := range t.Repos {
|
||||||
|
if err := repo.recalculateTeamAccesses(tx, 0); err != nil {
|
||||||
|
return errors.Newf("recalculateTeamAccesses: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return sess.Commit()
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteTeam deletes given team.
|
// DeleteTeam deletes given team.
|
||||||
@@ -419,34 +390,26 @@ func DeleteTeam(t *Team) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
// Delete all accesses.
|
||||||
if err = sess.Begin(); err != nil {
|
for _, repo := range t.Repos {
|
||||||
return err
|
if err := repo.recalculateTeamAccesses(tx, t.ID); err != nil {
|
||||||
}
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Delete all accesses.
|
// Delete team-user.
|
||||||
for _, repo := range t.Repos {
|
if err := tx.Where("org_id = ? AND team_id = ?", org.ID, t.ID).Delete(new(TeamUser)).Error; err != nil {
|
||||||
if err = repo.recalculateTeamAccesses(sess, t.ID); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Delete team-user.
|
// Delete team.
|
||||||
if _, err = sess.Where("org_id=?", org.ID).Where("team_id=?", t.ID).Delete(new(TeamUser)); err != nil {
|
if err := tx.Where("id = ?", t.ID).Delete(new(Team)).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// Update organization number of teams.
|
||||||
// Delete team.
|
return tx.Exec("UPDATE `user` SET num_teams=num_teams-1 WHERE id = ?", t.OrgID).Error
|
||||||
if _, err = sess.ID(t.ID).Delete(new(Team)); err != nil {
|
})
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Update organization number of teams.
|
|
||||||
if _, err = sess.Exec("UPDATE `user` SET num_teams=num_teams-1 WHERE id=?", t.OrgID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return sess.Commit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ___________ ____ ___
|
// ___________ ____ ___
|
||||||
@@ -459,31 +422,30 @@ func DeleteTeam(t *Team) error {
|
|||||||
// TeamUser represents an team-user relation.
|
// TeamUser represents an team-user relation.
|
||||||
type TeamUser struct {
|
type TeamUser struct {
|
||||||
ID int64
|
ID int64
|
||||||
OrgID int64 `xorm:"INDEX"`
|
OrgID int64 `gorm:"index"`
|
||||||
TeamID int64 `xorm:"UNIQUE(s)"`
|
TeamID int64 `gorm:"uniqueIndex:team_user_team_id_uid"`
|
||||||
UID int64 `xorm:"UNIQUE(s)"`
|
UID int64 `gorm:"uniqueIndex:team_user_team_id_uid"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func isTeamMember(e Engine, orgID, teamID, uid int64) bool {
|
func isTeamMember(tx *gorm.DB, orgID, teamID, uid int64) bool {
|
||||||
has, _ := e.Where("org_id=?", orgID).And("team_id=?", teamID).And("uid=?", uid).Get(new(TeamUser))
|
err := tx.Where("org_id = ? AND team_id = ? AND uid = ?", orgID, teamID, uid).First(new(TeamUser)).Error
|
||||||
return has
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsTeamMember returns true if given user is a member of team.
|
// IsTeamMember returns true if given user is a member of team.
|
||||||
func IsTeamMember(orgID, teamID, uid int64) bool {
|
func IsTeamMember(orgID, teamID, uid int64) bool {
|
||||||
return isTeamMember(x, orgID, teamID, uid)
|
return isTeamMember(db, orgID, teamID, uid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTeamMembers(e Engine, teamID int64) (_ []*User, err error) {
|
func getTeamMembers(tx *gorm.DB, teamID int64) (_ []*User, err error) {
|
||||||
teamUsers := make([]*TeamUser, 0, 10)
|
teamUsers := make([]*TeamUser, 0, 10)
|
||||||
if err = e.Sql("SELECT `id`, `org_id`, `team_id`, `uid` FROM `team_user` WHERE team_id = ?", teamID).
|
if err = tx.Select("id, org_id, team_id, uid").Where("team_id = ?", teamID).Find(&teamUsers).Error; err != nil {
|
||||||
Find(&teamUsers); err != nil {
|
|
||||||
return nil, errors.Newf("get team-users: %v", err)
|
return nil, errors.Newf("get team-users: %v", err)
|
||||||
}
|
}
|
||||||
members := make([]*User, 0, len(teamUsers))
|
members := make([]*User, 0, len(teamUsers))
|
||||||
for i := range teamUsers {
|
for i := range teamUsers {
|
||||||
member := new(User)
|
member := new(User)
|
||||||
if _, err = e.ID(teamUsers[i].UID).Get(member); err != nil {
|
if err = tx.Where("id = ?", teamUsers[i].UID).First(member).Error; err != nil {
|
||||||
return nil, errors.Newf("get user '%d': %v", teamUsers[i].UID, err)
|
return nil, errors.Newf("get user '%d': %v", teamUsers[i].UID, err)
|
||||||
}
|
}
|
||||||
members = append(members, member)
|
members = append(members, member)
|
||||||
@@ -493,12 +455,12 @@ func getTeamMembers(e Engine, teamID int64) (_ []*User, err error) {
|
|||||||
|
|
||||||
// GetTeamMembers returns all members in given team of organization.
|
// GetTeamMembers returns all members in given team of organization.
|
||||||
func GetTeamMembers(teamID int64) ([]*User, error) {
|
func GetTeamMembers(teamID int64) ([]*User, error) {
|
||||||
return getTeamMembers(x, teamID)
|
return getTeamMembers(db, teamID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUserTeams(e Engine, orgID, userID int64) ([]*Team, error) {
|
func getUserTeams(tx *gorm.DB, orgID, userID int64) ([]*Team, error) {
|
||||||
teamUsers := make([]*TeamUser, 0, 5)
|
teamUsers := make([]*TeamUser, 0, 5)
|
||||||
if err := e.Where("uid = ?", userID).And("org_id = ?", orgID).Find(&teamUsers); err != nil {
|
if err := tx.Where("uid = ? AND org_id = ?", userID, orgID).Find(&teamUsers).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -509,12 +471,12 @@ func getUserTeams(e Engine, orgID, userID int64) ([]*Team, error) {
|
|||||||
teamIDs[len(teamUsers)] = -1
|
teamIDs[len(teamUsers)] = -1
|
||||||
|
|
||||||
teams := make([]*Team, 0, len(teamIDs))
|
teams := make([]*Team, 0, len(teamIDs))
|
||||||
return teams, e.Where("org_id = ?", orgID).In("id", teamIDs).Find(&teams)
|
return teams, tx.Where("org_id = ? AND id IN ?", orgID, teamIDs).Find(&teams).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserTeams returns all teams that user belongs to in given organization.
|
// GetUserTeams returns all teams that user belongs to in given organization.
|
||||||
func GetUserTeams(orgID, userID int64) ([]*Team, error) {
|
func GetUserTeams(orgID, userID int64) ([]*Team, error) {
|
||||||
return getUserTeams(x, orgID, userID)
|
return getUserTeams(db, orgID, userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddTeamMember adds new membership of given team to given organization,
|
// AddTeamMember adds new membership of given team to given organization,
|
||||||
@@ -539,53 +501,46 @@ func AddTeamMember(orgID, teamID, userID int64) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
tu := &TeamUser{
|
||||||
if err = sess.Begin(); err != nil {
|
UID: userID,
|
||||||
return err
|
OrgID: orgID,
|
||||||
}
|
TeamID: teamID,
|
||||||
|
}
|
||||||
tu := &TeamUser{
|
if err := tx.Create(tu).Error; err != nil {
|
||||||
UID: userID,
|
return err
|
||||||
OrgID: orgID,
|
}
|
||||||
TeamID: teamID,
|
if err := tx.Model(&Team{}).Where("id = ?", t.ID).Updates(t).Error; err != nil {
|
||||||
}
|
|
||||||
if _, err = sess.Insert(tu); err != nil {
|
|
||||||
return err
|
|
||||||
} else if _, err = sess.ID(t.ID).Update(t); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Give access to team repositories.
|
|
||||||
for _, repo := range t.Repos {
|
|
||||||
if err = repo.recalculateTeamAccesses(sess, 0); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// We make sure it exists before.
|
// Give access to team repositories.
|
||||||
ou := new(OrgUser)
|
for _, repo := range t.Repos {
|
||||||
if _, err = sess.Where("uid = ?", userID).And("org_id = ?", orgID).Get(ou); err != nil {
|
if err := repo.recalculateTeamAccesses(tx, 0); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ou.NumTeams++
|
}
|
||||||
if t.IsOwnerTeam() {
|
|
||||||
ou.IsOwner = true
|
|
||||||
}
|
|
||||||
if _, err = sess.ID(ou.ID).AllCols().Update(ou); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return sess.Commit()
|
// We make sure it exists before.
|
||||||
|
ou := new(OrgUser)
|
||||||
|
if err := tx.Where("uid = ? AND org_id = ?", userID, orgID).First(ou).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ou.NumTeams++
|
||||||
|
if t.IsOwnerTeam() {
|
||||||
|
ou.IsOwner = true
|
||||||
|
}
|
||||||
|
return tx.Model(&OrgUser{}).Where("id = ?", ou.ID).Updates(ou).Error
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeTeamMember(e Engine, orgID, teamID, uid int64) error {
|
func removeTeamMember(tx *gorm.DB, orgID, teamID, uid int64) error {
|
||||||
if !isTeamMember(e, orgID, teamID, uid) {
|
if !isTeamMember(tx, orgID, teamID, uid) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get team and its repositories.
|
// Get team and its repositories.
|
||||||
t, err := getTeamByID(e, teamID)
|
t, err := getTeamByID(tx, teamID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -597,12 +552,12 @@ func removeTeamMember(e Engine, orgID, teamID, uid int64) error {
|
|||||||
|
|
||||||
t.NumMembers--
|
t.NumMembers--
|
||||||
|
|
||||||
if err = t.getRepositories(e); err != nil {
|
if err = t.getRepositories(tx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get organization.
|
// Get organization.
|
||||||
org, err := getUserByID(e, orgID)
|
org, err := getUserByID(tx, orgID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -612,46 +567,37 @@ func removeTeamMember(e Engine, orgID, teamID, uid int64) error {
|
|||||||
OrgID: orgID,
|
OrgID: orgID,
|
||||||
TeamID: teamID,
|
TeamID: teamID,
|
||||||
}
|
}
|
||||||
if _, err := e.Delete(tu); err != nil {
|
if err := tx.Where("uid = ? AND org_id = ? AND team_id = ?", uid, orgID, teamID).Delete(tu).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
} else if _, err = e.ID(t.ID).AllCols().Update(t); err != nil {
|
}
|
||||||
|
if err = tx.Model(&Team{}).Where("id = ?", t.ID).Updates(t).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete access to team repositories.
|
// Delete access to team repositories.
|
||||||
for _, repo := range t.Repos {
|
for _, repo := range t.Repos {
|
||||||
if err = repo.recalculateTeamAccesses(e, 0); err != nil {
|
if err = repo.recalculateTeamAccesses(tx, 0); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This must exist.
|
// This must exist.
|
||||||
ou := new(OrgUser)
|
ou := new(OrgUser)
|
||||||
_, err = e.Where("uid = ?", uid).And("org_id = ?", org.ID).Get(ou)
|
if err = tx.Where("uid = ? AND org_id = ?", uid, org.ID).First(ou).Error; err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ou.NumTeams--
|
ou.NumTeams--
|
||||||
if t.IsOwnerTeam() {
|
if t.IsOwnerTeam() {
|
||||||
ou.IsOwner = false
|
ou.IsOwner = false
|
||||||
}
|
}
|
||||||
if _, err = e.ID(ou.ID).AllCols().Update(ou); err != nil {
|
return tx.Model(&OrgUser{}).Where("id = ?", ou.ID).Updates(ou).Error
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveTeamMember removes member from given team of given organization.
|
// RemoveTeamMember removes member from given team of given organization.
|
||||||
func RemoveTeamMember(orgID, teamID, uid int64) error {
|
func RemoveTeamMember(orgID, teamID, uid int64) error {
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
return removeTeamMember(tx, orgID, teamID, uid)
|
||||||
if err := sess.Begin(); err != nil {
|
})
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := removeTeamMember(sess, orgID, teamID, uid); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return sess.Commit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ___________ __________
|
// ___________ __________
|
||||||
@@ -664,54 +610,49 @@ func RemoveTeamMember(orgID, teamID, uid int64) error {
|
|||||||
// TeamRepo represents an team-repository relation.
|
// TeamRepo represents an team-repository relation.
|
||||||
type TeamRepo struct {
|
type TeamRepo struct {
|
||||||
ID int64
|
ID int64
|
||||||
OrgID int64 `xorm:"INDEX"`
|
OrgID int64 `gorm:"index"`
|
||||||
TeamID int64 `xorm:"UNIQUE(s)"`
|
TeamID int64 `gorm:"uniqueIndex:team_repo_team_id_repo_id"`
|
||||||
RepoID int64 `xorm:"UNIQUE(s)"`
|
RepoID int64 `gorm:"uniqueIndex:team_repo_team_id_repo_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasTeamRepo(e Engine, orgID, teamID, repoID int64) bool {
|
func hasTeamRepo(tx *gorm.DB, orgID, teamID, repoID int64) bool {
|
||||||
has, _ := e.Where("org_id = ?", orgID).And("team_id = ?", teamID).And("repo_id = ?", repoID).Get(new(TeamRepo))
|
err := tx.Where("org_id = ? AND team_id = ? AND repo_id = ?", orgID, teamID, repoID).First(new(TeamRepo)).Error
|
||||||
return has
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasTeamRepo returns true if given team has access to the repository of the organization.
|
// HasTeamRepo returns true if given team has access to the repository of the organization.
|
||||||
func HasTeamRepo(orgID, teamID, repoID int64) bool {
|
func HasTeamRepo(orgID, teamID, repoID int64) bool {
|
||||||
return hasTeamRepo(x, orgID, teamID, repoID)
|
return hasTeamRepo(db, orgID, teamID, repoID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func addTeamRepo(e Engine, orgID, teamID, repoID int64) error {
|
func addTeamRepo(tx *gorm.DB, orgID, teamID, repoID int64) error {
|
||||||
_, err := e.InsertOne(&TeamRepo{
|
return tx.Create(&TeamRepo{
|
||||||
OrgID: orgID,
|
OrgID: orgID,
|
||||||
TeamID: teamID,
|
TeamID: teamID,
|
||||||
RepoID: repoID,
|
RepoID: repoID,
|
||||||
})
|
}).Error
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddTeamRepo adds new repository relation to team.
|
// AddTeamRepo adds new repository relation to team.
|
||||||
func AddTeamRepo(orgID, teamID, repoID int64) error {
|
func AddTeamRepo(orgID, teamID, repoID int64) error {
|
||||||
return addTeamRepo(x, orgID, teamID, repoID)
|
return addTeamRepo(db, orgID, teamID, repoID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeTeamRepo(e Engine, teamID, repoID int64) error {
|
func removeTeamRepo(tx *gorm.DB, teamID, repoID int64) error {
|
||||||
_, err := e.Delete(&TeamRepo{
|
return tx.Where("team_id = ? AND repo_id = ?", teamID, repoID).Delete(new(TeamRepo)).Error
|
||||||
TeamID: teamID,
|
|
||||||
RepoID: repoID,
|
|
||||||
})
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveTeamRepo deletes repository relation to team.
|
// RemoveTeamRepo deletes repository relation to team.
|
||||||
func RemoveTeamRepo(teamID, repoID int64) error {
|
func RemoveTeamRepo(teamID, repoID int64) error {
|
||||||
return removeTeamRepo(x, teamID, repoID)
|
return removeTeamRepo(db, teamID, repoID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTeamsHaveAccessToRepo returns all teams in an organization that have given access level to the repository.
|
// GetTeamsHaveAccessToRepo returns all teams in an organization that have given access level to the repository.
|
||||||
func GetTeamsHaveAccessToRepo(orgID, repoID int64, mode AccessMode) ([]*Team, error) {
|
func GetTeamsHaveAccessToRepo(orgID, repoID int64, mode AccessMode) ([]*Team, error) {
|
||||||
teams := make([]*Team, 0, 5)
|
teams := make([]*Team, 0, 5)
|
||||||
return teams, x.Where("team.authorize >= ?", mode).
|
return teams, db.Table("team").
|
||||||
Join("INNER", "team_repo", "team_repo.team_id = team.id").
|
Where("team.authorize >= ?", mode).
|
||||||
And("team_repo.org_id = ?", orgID).
|
Joins("INNER JOIN team_repo ON team_repo.team_id = team.id").
|
||||||
And("team_repo.repo_id = ?", repoID).
|
Where("team_repo.org_id = ? AND team_repo.repo_id = ?", orgID, repoID).
|
||||||
Find(&teams)
|
Find(&teams).Error
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import (
|
|||||||
|
|
||||||
"github.com/cockroachdb/errors"
|
"github.com/cockroachdb/errors"
|
||||||
"github.com/unknwon/com"
|
"github.com/unknwon/com"
|
||||||
|
"gorm.io/gorm"
|
||||||
log "unknwon.dev/clog/v2"
|
log "unknwon.dev/clog/v2"
|
||||||
"xorm.io/xorm"
|
|
||||||
|
|
||||||
"github.com/gogs/git-module"
|
"github.com/gogs/git-module"
|
||||||
api "github.com/gogs/go-gogs-client"
|
api "github.com/gogs/go-gogs-client"
|
||||||
@@ -71,35 +71,31 @@ func (pr *PullRequest) BeforeUpdate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Note: don't try to get Issue because will end up recursive querying.
|
// Note: don't try to get Issue because will end up recursive querying.
|
||||||
func (pr *PullRequest) AfterSet(colName string, _ xorm.Cell) {
|
func (pr *PullRequest) AfterFind(tx *gorm.DB) error {
|
||||||
switch colName {
|
if pr.HasMerged {
|
||||||
case "merged_unix":
|
|
||||||
if !pr.HasMerged {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
pr.Merged = time.Unix(pr.MergedUnix, 0).Local()
|
pr.Merged = time.Unix(pr.MergedUnix, 0).Local()
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: don't try to get Issue because will end up recursive querying.
|
// Note: don't try to get Issue because will end up recursive querying.
|
||||||
func (pr *PullRequest) loadAttributes(e Engine) (err error) {
|
func (pr *PullRequest) loadAttributes(db *gorm.DB) (err error) {
|
||||||
if pr.HeadRepo == nil {
|
if pr.HeadRepo == nil {
|
||||||
pr.HeadRepo, err = getRepositoryByID(e, pr.HeadRepoID)
|
pr.HeadRepo, err = getRepositoryByID(db, pr.HeadRepoID)
|
||||||
if err != nil && !IsErrRepoNotExist(err) {
|
if err != nil && !IsErrRepoNotExist(err) {
|
||||||
return errors.Newf("get head repository by ID: %v", err)
|
return errors.Newf("get head repository by ID: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if pr.BaseRepo == nil {
|
if pr.BaseRepo == nil {
|
||||||
pr.BaseRepo, err = getRepositoryByID(e, pr.BaseRepoID)
|
pr.BaseRepo, err = getRepositoryByID(db, pr.BaseRepoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Newf("get base repository by ID: %v", err)
|
return errors.Newf("get base repository by ID: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if pr.HasMerged && pr.Merger == nil {
|
if pr.HasMerged && pr.Merger == nil {
|
||||||
pr.Merger, err = getUserByID(e, pr.MergerID)
|
pr.Merger, err = getUserByID(db, pr.MergerID)
|
||||||
if IsErrUserNotExist(err) {
|
if IsErrUserNotExist(err) {
|
||||||
pr.MergerID = -1
|
pr.MergerID = -1
|
||||||
pr.Merger = NewGhostUser()
|
pr.Merger = NewGhostUser()
|
||||||
@@ -112,7 +108,7 @@ func (pr *PullRequest) loadAttributes(e Engine) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pr *PullRequest) LoadAttributes() error {
|
func (pr *PullRequest) LoadAttributes() error {
|
||||||
return pr.loadAttributes(x)
|
return pr.loadAttributes(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pr *PullRequest) LoadIssue() (err error) {
|
func (pr *PullRequest) LoadIssue() (err error) {
|
||||||
@@ -199,198 +195,190 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
|
|||||||
go AddTestPullRequestTask(doer, pr.BaseRepo.ID, pr.BaseBranch, false)
|
go AddTestPullRequestTask(doer, pr.BaseRepo.ID, pr.BaseBranch, false)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
if err := pr.Issue.changeStatus(tx, doer, pr.Issue.Repo, true); err != nil {
|
||||||
if err = sess.Begin(); err != nil {
|
return errors.Newf("Issue.changeStatus: %v", err)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = pr.Issue.changeStatus(sess, doer, pr.Issue.Repo, true); err != nil {
|
|
||||||
return errors.Newf("Issue.changeStatus: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
headRepoPath := RepoPath(pr.HeadUserName, pr.HeadRepo.Name)
|
|
||||||
headGitRepo, err := git.Open(headRepoPath)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Newf("open repository: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create temporary directory to store temporary copy of the base repository,
|
|
||||||
// and clean it up when operation finished regardless of succeed or not.
|
|
||||||
tmpBasePath := filepath.Join(conf.Server.AppDataPath, "tmp", "repos", com.ToStr(time.Now().Nanosecond())+".git")
|
|
||||||
if err = os.MkdirAll(filepath.Dir(tmpBasePath), os.ModePerm); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
_ = os.RemoveAll(filepath.Dir(tmpBasePath))
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Clone the base repository to the defined temporary directory,
|
|
||||||
// and checks out to base branch directly.
|
|
||||||
var stderr string
|
|
||||||
if _, stderr, err = process.ExecTimeout(5*time.Minute,
|
|
||||||
fmt.Sprintf("PullRequest.Merge (git clone): %s", tmpBasePath),
|
|
||||||
"git", "clone", "-b", pr.BaseBranch, baseGitRepo.Path(), tmpBasePath); err != nil {
|
|
||||||
return errors.Newf("git clone: %s", stderr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add remote which points to the head repository.
|
|
||||||
if _, stderr, err = process.ExecDir(-1, tmpBasePath,
|
|
||||||
fmt.Sprintf("PullRequest.Merge (git remote add): %s", tmpBasePath),
|
|
||||||
"git", "remote", "add", "head_repo", headRepoPath); err != nil {
|
|
||||||
return errors.Newf("git remote add [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch information from head repository to the temporary copy.
|
|
||||||
if _, stderr, err = process.ExecDir(-1, tmpBasePath,
|
|
||||||
fmt.Sprintf("PullRequest.Merge (git fetch): %s", tmpBasePath),
|
|
||||||
"git", "fetch", "head_repo"); err != nil {
|
|
||||||
return errors.Newf("git fetch [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
|
|
||||||
}
|
|
||||||
|
|
||||||
remoteHeadBranch := "head_repo/" + pr.HeadBranch
|
|
||||||
|
|
||||||
// Check if merge style is allowed, reset to default style if not
|
|
||||||
if mergeStyle == MergeStyleRebase && !pr.BaseRepo.PullsAllowRebase {
|
|
||||||
mergeStyle = MergeStyleRegular
|
|
||||||
}
|
|
||||||
|
|
||||||
switch mergeStyle {
|
|
||||||
case MergeStyleRegular: // Create merge commit
|
|
||||||
|
|
||||||
// Merge changes from head branch.
|
|
||||||
if _, stderr, err = process.ExecDir(-1, tmpBasePath,
|
|
||||||
fmt.Sprintf("PullRequest.Merge (git merge --no-ff --no-commit): %s", tmpBasePath),
|
|
||||||
"git", "merge", "--no-ff", "--no-commit", remoteHeadBranch); err != nil {
|
|
||||||
return errors.Newf("git merge --no-ff --no-commit [%s]: %v - %s", tmpBasePath, err, stderr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a merge commit for the base branch.
|
headRepoPath := RepoPath(pr.HeadUserName, pr.HeadRepo.Name)
|
||||||
if _, stderr, err = process.ExecDir(-1, tmpBasePath,
|
headGitRepo, err := git.Open(headRepoPath)
|
||||||
fmt.Sprintf("PullRequest.Merge (git merge): %s", tmpBasePath),
|
if err != nil {
|
||||||
"git", "commit", fmt.Sprintf("--author='%s <%s>'", doer.DisplayName(), doer.Email),
|
return errors.Newf("open repository: %v", err)
|
||||||
"-m", fmt.Sprintf("Merge branch '%s' of %s/%s into %s", pr.HeadBranch, pr.HeadUserName, pr.HeadRepo.Name, pr.BaseBranch),
|
|
||||||
"-m", commitDescription); err != nil {
|
|
||||||
return errors.Newf("git commit [%s]: %v - %s", tmpBasePath, err, stderr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case MergeStyleRebase: // Rebase before merging
|
// Create temporary directory to store temporary copy of the base repository,
|
||||||
|
// and clean it up when operation finished regardless of succeed or not.
|
||||||
|
tmpBasePath := filepath.Join(conf.Server.AppDataPath, "tmp", "repos", com.ToStr(time.Now().Nanosecond())+".git")
|
||||||
|
if err = os.MkdirAll(filepath.Dir(tmpBasePath), os.ModePerm); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
_ = os.RemoveAll(filepath.Dir(tmpBasePath))
|
||||||
|
}()
|
||||||
|
|
||||||
// Rebase head branch based on base branch, this creates a non-branch commit state.
|
// Clone the base repository to the defined temporary directory,
|
||||||
if _, stderr, err = process.ExecDir(-1, tmpBasePath,
|
// and checks out to base branch directly.
|
||||||
fmt.Sprintf("PullRequest.Merge (git rebase): %s", tmpBasePath),
|
var stderr string
|
||||||
"git", "rebase", "--quiet", pr.BaseBranch, remoteHeadBranch); err != nil {
|
if _, stderr, err = process.ExecTimeout(5*time.Minute,
|
||||||
return errors.Newf("git rebase [%s on %s]: %s", remoteHeadBranch, pr.BaseBranch, stderr)
|
fmt.Sprintf("PullRequest.Merge (git clone): %s", tmpBasePath),
|
||||||
|
"git", "clone", "-b", pr.BaseBranch, baseGitRepo.Path(), tmpBasePath); err != nil {
|
||||||
|
return errors.Newf("git clone: %s", stderr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name non-branch commit state to a new temporary branch in order to save changes.
|
// Add remote which points to the head repository.
|
||||||
tmpBranch := com.ToStr(time.Now().UnixNano(), 10)
|
|
||||||
if _, stderr, err = process.ExecDir(-1, tmpBasePath,
|
if _, stderr, err = process.ExecDir(-1, tmpBasePath,
|
||||||
fmt.Sprintf("PullRequest.Merge (git checkout): %s", tmpBasePath),
|
fmt.Sprintf("PullRequest.Merge (git remote add): %s", tmpBasePath),
|
||||||
"git", "checkout", "-b", tmpBranch); err != nil {
|
"git", "remote", "add", "head_repo", headRepoPath); err != nil {
|
||||||
return errors.Newf("git checkout '%s': %s", tmpBranch, stderr)
|
return errors.Newf("git remote add [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check out the base branch to be operated on.
|
// Fetch information from head repository to the temporary copy.
|
||||||
if _, stderr, err = process.ExecDir(-1, tmpBasePath,
|
if _, stderr, err = process.ExecDir(-1, tmpBasePath,
|
||||||
fmt.Sprintf("PullRequest.Merge (git checkout): %s", tmpBasePath),
|
fmt.Sprintf("PullRequest.Merge (git fetch): %s", tmpBasePath),
|
||||||
"git", "checkout", pr.BaseBranch); err != nil {
|
"git", "fetch", "head_repo"); err != nil {
|
||||||
return errors.Newf("git checkout '%s': %s", pr.BaseBranch, stderr)
|
return errors.Newf("git fetch [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge changes from temporary branch to the base branch.
|
remoteHeadBranch := "head_repo/" + pr.HeadBranch
|
||||||
if _, stderr, err = process.ExecDir(-1, tmpBasePath,
|
|
||||||
fmt.Sprintf("PullRequest.Merge (git merge): %s", tmpBasePath),
|
// Check if merge style is allowed, reset to default style if not
|
||||||
"git", "merge", tmpBranch); err != nil {
|
if mergeStyle == MergeStyleRebase && !pr.BaseRepo.PullsAllowRebase {
|
||||||
return errors.Newf("git merge [%s]: %v - %s", tmpBasePath, err, stderr)
|
mergeStyle = MergeStyleRegular
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
switch mergeStyle {
|
||||||
return errors.Newf("unknown merge style: %s", mergeStyle)
|
case MergeStyleRegular: // Create merge commit
|
||||||
}
|
|
||||||
|
|
||||||
// Push changes on base branch to upstream.
|
// Merge changes from head branch.
|
||||||
if _, stderr, err = process.ExecDir(-1, tmpBasePath,
|
if _, stderr, err = process.ExecDir(-1, tmpBasePath,
|
||||||
fmt.Sprintf("PullRequest.Merge (git push): %s", tmpBasePath),
|
fmt.Sprintf("PullRequest.Merge (git merge --no-ff --no-commit): %s", tmpBasePath),
|
||||||
"git", "push", baseGitRepo.Path(), pr.BaseBranch); err != nil {
|
"git", "merge", "--no-ff", "--no-commit", remoteHeadBranch); err != nil {
|
||||||
return errors.Newf("git push: %s", stderr)
|
return errors.Newf("git merge --no-ff --no-commit [%s]: %v - %s", tmpBasePath, err, stderr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pr.MergedCommitID, err = headGitRepo.BranchCommitID(pr.HeadBranch)
|
// Create a merge commit for the base branch.
|
||||||
if err != nil {
|
if _, stderr, err = process.ExecDir(-1, tmpBasePath,
|
||||||
return errors.Newf("get head branch %q commit ID: %v", pr.HeadBranch, err)
|
fmt.Sprintf("PullRequest.Merge (git merge): %s", tmpBasePath),
|
||||||
}
|
"git", "commit", fmt.Sprintf("--author='%s <%s>'", doer.DisplayName(), doer.Email),
|
||||||
|
"-m", fmt.Sprintf("Merge branch '%s' of %s/%s into %s", pr.HeadBranch, pr.HeadUserName, pr.HeadRepo.Name, pr.BaseBranch),
|
||||||
|
"-m", commitDescription); err != nil {
|
||||||
|
return errors.Newf("git commit [%s]: %v - %s", tmpBasePath, err, stderr)
|
||||||
|
}
|
||||||
|
|
||||||
pr.HasMerged = true
|
case MergeStyleRebase: // Rebase before merging
|
||||||
pr.Merged = time.Now()
|
|
||||||
pr.MergerID = doer.ID
|
|
||||||
if _, err = sess.ID(pr.ID).AllCols().Update(pr); err != nil {
|
|
||||||
return errors.Newf("update pull request: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = sess.Commit(); err != nil {
|
// Rebase head branch based on base branch, this creates a non-branch commit state.
|
||||||
return errors.Newf("commit: %v", err)
|
if _, stderr, err = process.ExecDir(-1, tmpBasePath,
|
||||||
}
|
fmt.Sprintf("PullRequest.Merge (git rebase): %s", tmpBasePath),
|
||||||
|
"git", "rebase", "--quiet", pr.BaseBranch, remoteHeadBranch); err != nil {
|
||||||
|
return errors.Newf("git rebase [%s on %s]: %s", remoteHeadBranch, pr.BaseBranch, stderr)
|
||||||
|
}
|
||||||
|
|
||||||
if err = Handle.Actions().MergePullRequest(ctx, doer, pr.Issue.Repo.Owner, pr.Issue.Repo, pr.Issue); err != nil {
|
// Name non-branch commit state to a new temporary branch in order to save changes.
|
||||||
log.Error("Failed to create action for merge pull request, pull_request_id: %d, error: %v", pr.ID, err)
|
tmpBranch := com.ToStr(time.Now().UnixNano(), 10)
|
||||||
}
|
if _, stderr, err = process.ExecDir(-1, tmpBasePath,
|
||||||
|
fmt.Sprintf("PullRequest.Merge (git checkout): %s", tmpBasePath),
|
||||||
|
"git", "checkout", "-b", tmpBranch); err != nil {
|
||||||
|
return errors.Newf("git checkout '%s': %s", tmpBranch, stderr)
|
||||||
|
}
|
||||||
|
|
||||||
// Reload pull request information.
|
// Check out the base branch to be operated on.
|
||||||
if err = pr.LoadAttributes(); err != nil {
|
if _, stderr, err = process.ExecDir(-1, tmpBasePath,
|
||||||
log.Error("LoadAttributes: %v", err)
|
fmt.Sprintf("PullRequest.Merge (git checkout): %s", tmpBasePath),
|
||||||
|
"git", "checkout", pr.BaseBranch); err != nil {
|
||||||
|
return errors.Newf("git checkout '%s': %s", pr.BaseBranch, stderr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge changes from temporary branch to the base branch.
|
||||||
|
if _, stderr, err = process.ExecDir(-1, tmpBasePath,
|
||||||
|
fmt.Sprintf("PullRequest.Merge (git merge): %s", tmpBasePath),
|
||||||
|
"git", "merge", tmpBranch); err != nil {
|
||||||
|
return errors.Newf("git merge [%s]: %v - %s", tmpBasePath, err, stderr)
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return errors.Newf("unknown merge style: %s", mergeStyle)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push changes on base branch to upstream.
|
||||||
|
if _, stderr, err = process.ExecDir(-1, tmpBasePath,
|
||||||
|
fmt.Sprintf("PullRequest.Merge (git push): %s", tmpBasePath),
|
||||||
|
"git", "push", baseGitRepo.Path(), pr.BaseBranch); err != nil {
|
||||||
|
return errors.Newf("git push: %s", stderr)
|
||||||
|
}
|
||||||
|
|
||||||
|
pr.MergedCommitID, err = headGitRepo.BranchCommitID(pr.HeadBranch)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Newf("get head branch %q commit ID: %v", pr.HeadBranch, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pr.HasMerged = true
|
||||||
|
pr.Merged = time.Now()
|
||||||
|
pr.MergerID = doer.ID
|
||||||
|
if err := tx.Model(&PullRequest{}).Where("id = ?", pr.ID).Updates(pr).Error; err != nil {
|
||||||
|
return errors.Newf("update pull request: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = Handle.Actions().MergePullRequest(ctx, doer, pr.Issue.Repo.Owner, pr.Issue.Repo, pr.Issue); err != nil {
|
||||||
|
log.Error("Failed to create action for merge pull request, pull_request_id: %d, error: %v", pr.ID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reload pull request information.
|
||||||
|
if err = pr.LoadAttributes(); err != nil {
|
||||||
|
log.Error("LoadAttributes: %v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err = PrepareWebhooks(pr.Issue.Repo, HookEventTypePullRequest, &api.PullRequestPayload{
|
||||||
|
Action: api.HOOK_ISSUE_CLOSED,
|
||||||
|
Index: pr.Index,
|
||||||
|
PullRequest: pr.APIFormat(),
|
||||||
|
Repository: pr.Issue.Repo.APIFormatLegacy(nil),
|
||||||
|
Sender: doer.APIFormat(),
|
||||||
|
}); err != nil {
|
||||||
|
log.Error("PrepareWebhooks: %v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
commits, err := headGitRepo.RevList([]string{pr.MergeBase + "..." + pr.MergedCommitID})
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to list commits [merge_base: %s, merged_commit_id: %s]: %v", pr.MergeBase, pr.MergedCommitID, err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: It is possible that head branch is not fully sync with base branch
|
||||||
|
// for merge commits, so we need to get latest head commit and append merge
|
||||||
|
// commit manually to avoid strange diff commits produced.
|
||||||
|
mergeCommit, err := baseGitRepo.BranchCommit(pr.BaseBranch)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to get base branch %q commit: %v", pr.BaseBranch, err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if mergeStyle == MergeStyleRegular {
|
||||||
|
commits = append([]*git.Commit{mergeCommit}, commits...)
|
||||||
|
}
|
||||||
|
|
||||||
|
pcs, err := CommitsToPushCommits(commits).APIFormat(ctx, Handle.Users(), pr.BaseRepo.RepoPath(), pr.BaseRepo.HTMLURL())
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to convert to API payload commits: %v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
p := &api.PushPayload{
|
||||||
|
Ref: git.RefsHeads + pr.BaseBranch,
|
||||||
|
Before: pr.MergeBase,
|
||||||
|
After: mergeCommit.ID.String(),
|
||||||
|
CompareURL: conf.Server.ExternalURL + pr.BaseRepo.ComposeCompareURL(pr.MergeBase, pr.MergedCommitID),
|
||||||
|
Commits: pcs,
|
||||||
|
Repo: pr.BaseRepo.APIFormatLegacy(nil),
|
||||||
|
Pusher: pr.HeadRepo.MustOwner().APIFormat(),
|
||||||
|
Sender: doer.APIFormat(),
|
||||||
|
}
|
||||||
|
if err = PrepareWebhooks(pr.BaseRepo, HookEventTypePush, p); err != nil {
|
||||||
|
log.Error("Failed to prepare webhooks: %v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
})
|
||||||
if err = PrepareWebhooks(pr.Issue.Repo, HookEventTypePullRequest, &api.PullRequestPayload{
|
|
||||||
Action: api.HOOK_ISSUE_CLOSED,
|
|
||||||
Index: pr.Index,
|
|
||||||
PullRequest: pr.APIFormat(),
|
|
||||||
Repository: pr.Issue.Repo.APIFormatLegacy(nil),
|
|
||||||
Sender: doer.APIFormat(),
|
|
||||||
}); err != nil {
|
|
||||||
log.Error("PrepareWebhooks: %v", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
commits, err := headGitRepo.RevList([]string{pr.MergeBase + "..." + pr.MergedCommitID})
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Failed to list commits [merge_base: %s, merged_commit_id: %s]: %v", pr.MergeBase, pr.MergedCommitID, err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: It is possible that head branch is not fully sync with base branch
|
|
||||||
// for merge commits, so we need to get latest head commit and append merge
|
|
||||||
// commit manually to avoid strange diff commits produced.
|
|
||||||
mergeCommit, err := baseGitRepo.BranchCommit(pr.BaseBranch)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Failed to get base branch %q commit: %v", pr.BaseBranch, err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if mergeStyle == MergeStyleRegular {
|
|
||||||
commits = append([]*git.Commit{mergeCommit}, commits...)
|
|
||||||
}
|
|
||||||
|
|
||||||
pcs, err := CommitsToPushCommits(commits).APIFormat(ctx, Handle.Users(), pr.BaseRepo.RepoPath(), pr.BaseRepo.HTMLURL())
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Failed to convert to API payload commits: %v", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
p := &api.PushPayload{
|
|
||||||
Ref: git.RefsHeads + pr.BaseBranch,
|
|
||||||
Before: pr.MergeBase,
|
|
||||||
After: mergeCommit.ID.String(),
|
|
||||||
CompareURL: conf.Server.ExternalURL + pr.BaseRepo.ComposeCompareURL(pr.MergeBase, pr.MergedCommitID),
|
|
||||||
Commits: pcs,
|
|
||||||
Repo: pr.BaseRepo.APIFormatLegacy(nil),
|
|
||||||
Pusher: pr.HeadRepo.MustOwner().APIFormat(),
|
|
||||||
Sender: doer.APIFormat(),
|
|
||||||
}
|
|
||||||
if err = PrepareWebhooks(pr.BaseRepo, HookEventTypePush, p); err != nil {
|
|
||||||
log.Error("Failed to prepare webhooks: %v", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// testPatch checks if patch can be merged to base repository without conflict.
|
// testPatch checks if patch can be merged to base repository without conflict.
|
||||||
@@ -443,45 +431,42 @@ func (pr *PullRequest) testPatch() (err error) {
|
|||||||
|
|
||||||
// NewPullRequest creates new pull request with labels for repository.
|
// NewPullRequest creates new pull request with labels for repository.
|
||||||
func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []string, pr *PullRequest, patch []byte) (err error) {
|
func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []string, pr *PullRequest, patch []byte) (err error) {
|
||||||
sess := x.NewSession()
|
err = db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
if err := newIssue(tx, NewIssueOptions{
|
||||||
if err = sess.Begin(); err != nil {
|
Repo: repo,
|
||||||
|
Issue: pull,
|
||||||
|
LableIDs: labelIDs,
|
||||||
|
Attachments: uuids,
|
||||||
|
IsPull: true,
|
||||||
|
}); err != nil {
|
||||||
|
return errors.Newf("newIssue: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pr.Index = pull.Index
|
||||||
|
if err := repo.SavePatch(pr.Index, patch); err != nil {
|
||||||
|
return errors.Newf("SavePatch: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pr.BaseRepo = repo
|
||||||
|
if err := pr.testPatch(); err != nil {
|
||||||
|
return errors.Newf("testPatch: %v", err)
|
||||||
|
}
|
||||||
|
// No conflict appears after test means mergeable.
|
||||||
|
if pr.Status == PullRequestStatusChecking {
|
||||||
|
pr.Status = PullRequestStatusMergeable
|
||||||
|
}
|
||||||
|
|
||||||
|
pr.IssueID = pull.ID
|
||||||
|
if err := tx.Create(pr).Error; err != nil {
|
||||||
|
return errors.Newf("insert pull repo: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = newIssue(sess, NewIssueOptions{
|
|
||||||
Repo: repo,
|
|
||||||
Issue: pull,
|
|
||||||
LableIDs: labelIDs,
|
|
||||||
Attachments: uuids,
|
|
||||||
IsPull: true,
|
|
||||||
}); err != nil {
|
|
||||||
return errors.Newf("newIssue: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
pr.Index = pull.Index
|
|
||||||
if err = repo.SavePatch(pr.Index, patch); err != nil {
|
|
||||||
return errors.Newf("SavePatch: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
pr.BaseRepo = repo
|
|
||||||
if err = pr.testPatch(); err != nil {
|
|
||||||
return errors.Newf("testPatch: %v", err)
|
|
||||||
}
|
|
||||||
// No conflict appears after test means mergeable.
|
|
||||||
if pr.Status == PullRequestStatusChecking {
|
|
||||||
pr.Status = PullRequestStatusMergeable
|
|
||||||
}
|
|
||||||
|
|
||||||
pr.IssueID = pull.ID
|
|
||||||
if _, err = sess.Insert(pr); err != nil {
|
|
||||||
return errors.Newf("insert pull repo: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = sess.Commit(); err != nil {
|
|
||||||
return errors.Newf("commit: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = NotifyWatchers(&Action{
|
if err = NotifyWatchers(&Action{
|
||||||
ActUserID: pull.Poster.ID,
|
ActUserID: pull.Poster.ID,
|
||||||
ActUserName: pull.Poster.Name,
|
ActUserName: pull.Poster.Name,
|
||||||
@@ -517,18 +502,20 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
|
|||||||
// by given head/base and repo/branch.
|
// by given head/base and repo/branch.
|
||||||
func GetUnmergedPullRequest(headRepoID, baseRepoID int64, headBranch, baseBranch string) (*PullRequest, error) {
|
func GetUnmergedPullRequest(headRepoID, baseRepoID int64, headBranch, baseBranch string) (*PullRequest, error) {
|
||||||
pr := new(PullRequest)
|
pr := new(PullRequest)
|
||||||
has, err := x.Where("head_repo_id=? AND head_branch=? AND base_repo_id=? AND base_branch=? AND has_merged=? AND issue.is_closed=?",
|
err := db.Joins("INNER JOIN issue ON issue.id = pull_request.issue_id").
|
||||||
headRepoID, headBranch, baseRepoID, baseBranch, false, false).
|
Where("pull_request.head_repo_id = ? AND pull_request.head_branch = ? AND pull_request.base_repo_id = ? AND pull_request.base_branch = ? AND pull_request.has_merged = ? AND issue.is_closed = ?",
|
||||||
Join("INNER", "issue", "issue.id=pull_request.issue_id").Get(pr)
|
headRepoID, headBranch, baseRepoID, baseBranch, false, false).
|
||||||
|
First(pr).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, ErrPullRequestNotExist{args: map[string]any{
|
||||||
|
"headRepoID": headRepoID,
|
||||||
|
"baseRepoID": baseRepoID,
|
||||||
|
"headBranch": headBranch,
|
||||||
|
"baseBranch": baseBranch,
|
||||||
|
}}
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
|
||||||
return nil, ErrPullRequestNotExist{args: map[string]any{
|
|
||||||
"headRepoID": headRepoID,
|
|
||||||
"baseRepoID": baseRepoID,
|
|
||||||
"headBranch": headBranch,
|
|
||||||
"baseBranch": baseBranch,
|
|
||||||
}}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return pr, nil
|
return pr, nil
|
||||||
@@ -538,18 +525,22 @@ func GetUnmergedPullRequest(headRepoID, baseRepoID int64, headBranch, baseBranch
|
|||||||
// by given head information (repo and branch).
|
// by given head information (repo and branch).
|
||||||
func GetUnmergedPullRequestsByHeadInfo(repoID int64, branch string) ([]*PullRequest, error) {
|
func GetUnmergedPullRequestsByHeadInfo(repoID int64, branch string) ([]*PullRequest, error) {
|
||||||
prs := make([]*PullRequest, 0, 2)
|
prs := make([]*PullRequest, 0, 2)
|
||||||
return prs, x.Where("head_repo_id = ? AND head_branch = ? AND has_merged = ? AND issue.is_closed = ?",
|
err := db.Joins("INNER JOIN issue ON issue.id = pull_request.issue_id").
|
||||||
repoID, branch, false, false).
|
Where("pull_request.head_repo_id = ? AND pull_request.head_branch = ? AND pull_request.has_merged = ? AND issue.is_closed = ?",
|
||||||
Join("INNER", "issue", "issue.id = pull_request.issue_id").Find(&prs)
|
repoID, branch, false, false).
|
||||||
|
Find(&prs).Error
|
||||||
|
return prs, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUnmergedPullRequestsByBaseInfo returns all pull requests that are open and has not been merged
|
// GetUnmergedPullRequestsByBaseInfo returns all pull requests that are open and has not been merged
|
||||||
// by given base information (repo and branch).
|
// by given base information (repo and branch).
|
||||||
func GetUnmergedPullRequestsByBaseInfo(repoID int64, branch string) ([]*PullRequest, error) {
|
func GetUnmergedPullRequestsByBaseInfo(repoID int64, branch string) ([]*PullRequest, error) {
|
||||||
prs := make([]*PullRequest, 0, 2)
|
prs := make([]*PullRequest, 0, 2)
|
||||||
return prs, x.Where("base_repo_id=? AND base_branch=? AND has_merged=? AND issue.is_closed=?",
|
err := db.Joins("INNER JOIN issue ON issue.id = pull_request.issue_id").
|
||||||
repoID, branch, false, false).
|
Where("pull_request.base_repo_id = ? AND pull_request.base_branch = ? AND pull_request.has_merged = ? AND issue.is_closed = ?",
|
||||||
Join("INNER", "issue", "issue.id=pull_request.issue_id").Find(&prs)
|
repoID, branch, false, false).
|
||||||
|
Find(&prs).Error
|
||||||
|
return prs, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ errutil.NotFound = (*ErrPullRequestNotExist)(nil)
|
var _ errutil.NotFound = (*ErrPullRequestNotExist)(nil)
|
||||||
@@ -571,50 +562,65 @@ func (ErrPullRequestNotExist) NotFound() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPullRequestByID(e Engine, id int64) (*PullRequest, error) {
|
func getPullRequestByID(db *gorm.DB, id int64) (*PullRequest, error) {
|
||||||
pr := new(PullRequest)
|
pr := new(PullRequest)
|
||||||
has, err := e.ID(id).Get(pr)
|
err := db.First(pr, id).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, ErrPullRequestNotExist{args: map[string]any{"pullRequestID": id}}
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
|
||||||
return nil, ErrPullRequestNotExist{args: map[string]any{"pullRequestID": id}}
|
|
||||||
}
|
}
|
||||||
return pr, pr.loadAttributes(e)
|
return pr, pr.loadAttributes(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPullRequestByID returns a pull request by given ID.
|
// GetPullRequestByID returns a pull request by given ID.
|
||||||
func GetPullRequestByID(id int64) (*PullRequest, error) {
|
func GetPullRequestByID(id int64) (*PullRequest, error) {
|
||||||
return getPullRequestByID(x, id)
|
return getPullRequestByID(db, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPullRequestByIssueID(e Engine, issueID int64) (*PullRequest, error) {
|
func getPullRequestByIssueID(db *gorm.DB, issueID int64) (*PullRequest, error) {
|
||||||
pr := &PullRequest{
|
pr := &PullRequest{}
|
||||||
IssueID: issueID,
|
err := db.Where("issue_id = ?", issueID).First(pr).Error
|
||||||
}
|
|
||||||
has, err := e.Get(pr)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, ErrPullRequestNotExist{args: map[string]any{"issueID": issueID}}
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
|
||||||
return nil, ErrPullRequestNotExist{args: map[string]any{"issueID": issueID}}
|
|
||||||
}
|
}
|
||||||
return pr, pr.loadAttributes(e)
|
return pr, pr.loadAttributes(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPullRequestByIssueID returns pull request by given issue ID.
|
// GetPullRequestByIssueID returns pull request by given issue ID.
|
||||||
func GetPullRequestByIssueID(issueID int64) (*PullRequest, error) {
|
func GetPullRequestByIssueID(issueID int64) (*PullRequest, error) {
|
||||||
return getPullRequestByIssueID(x, issueID)
|
return getPullRequestByIssueID(db, issueID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update updates all fields of pull request.
|
// Update updates all fields of pull request.
|
||||||
func (pr *PullRequest) Update() error {
|
func (pr *PullRequest) Update() error {
|
||||||
_, err := x.Id(pr.ID).AllCols().Update(pr)
|
return db.Model(&PullRequest{}).Where("id = ?", pr.ID).Updates(pr).Error
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update updates specific fields of pull request.
|
// Update updates specific fields of pull request.
|
||||||
func (pr *PullRequest) UpdateCols(cols ...string) error {
|
func (pr *PullRequest) UpdateCols(cols ...string) error {
|
||||||
_, err := x.Id(pr.ID).Cols(cols...).Update(pr)
|
updates := make(map[string]any)
|
||||||
return err
|
for _, col := range cols {
|
||||||
|
switch col {
|
||||||
|
case "status":
|
||||||
|
updates["status"] = pr.Status
|
||||||
|
case "merge_base":
|
||||||
|
updates["merge_base"] = pr.MergeBase
|
||||||
|
case "has_merged":
|
||||||
|
updates["has_merged"] = pr.HasMerged
|
||||||
|
case "merged_commit_id":
|
||||||
|
updates["merged_commit_id"] = pr.MergedCommitID
|
||||||
|
case "merger_id":
|
||||||
|
updates["merger_id"] = pr.MergerID
|
||||||
|
case "merged_unix":
|
||||||
|
updates["merged_unix"] = pr.MergedUnix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return db.Model(&PullRequest{}).Where("id = ?", pr.ID).Updates(updates).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatePatch generates and saves a new patch.
|
// UpdatePatch generates and saves a new patch.
|
||||||
@@ -711,7 +717,7 @@ func (pr *PullRequest) AddToTaskQueue() {
|
|||||||
|
|
||||||
type PullRequestList []*PullRequest
|
type PullRequestList []*PullRequest
|
||||||
|
|
||||||
func (prs PullRequestList) loadAttributes(e Engine) (err error) {
|
func (prs PullRequestList) loadAttributes(db *gorm.DB) (err error) {
|
||||||
if len(prs) == 0 {
|
if len(prs) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -726,7 +732,7 @@ func (prs PullRequestList) loadAttributes(e Engine) (err error) {
|
|||||||
issueIDs = append(issueIDs, issueID)
|
issueIDs = append(issueIDs, issueID)
|
||||||
}
|
}
|
||||||
issues := make([]*Issue, 0, len(issueIDs))
|
issues := make([]*Issue, 0, len(issueIDs))
|
||||||
if err = e.Where("id > 0").In("id", issueIDs).Find(&issues); err != nil {
|
if err = db.Where("id IN ?", issueIDs).Find(&issues).Error; err != nil {
|
||||||
return errors.Newf("find issues: %v", err)
|
return errors.Newf("find issues: %v", err)
|
||||||
}
|
}
|
||||||
for i := range issues {
|
for i := range issues {
|
||||||
@@ -738,7 +744,7 @@ func (prs PullRequestList) loadAttributes(e Engine) (err error) {
|
|||||||
|
|
||||||
// Load attributes
|
// Load attributes
|
||||||
for i := range prs {
|
for i := range prs {
|
||||||
if err = prs[i].loadAttributes(e); err != nil {
|
if err = prs[i].loadAttributes(db); err != nil {
|
||||||
return errors.Newf("loadAttributes [%d]: %v", prs[i].ID, err)
|
return errors.Newf("loadAttributes [%d]: %v", prs[i].ID, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -747,7 +753,7 @@ func (prs PullRequestList) loadAttributes(e Engine) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (prs PullRequestList) LoadAttributes() error {
|
func (prs PullRequestList) LoadAttributes() error {
|
||||||
return prs.loadAttributes(x)
|
return prs.loadAttributes(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
func addHeadRepoTasks(prs []*PullRequest) {
|
func addHeadRepoTasks(prs []*PullRequest) {
|
||||||
@@ -838,25 +844,23 @@ func (pr *PullRequest) checkAndUpdateStatus() {
|
|||||||
// TestPullRequests checks and tests untested patches of pull requests.
|
// TestPullRequests checks and tests untested patches of pull requests.
|
||||||
// TODO: test more pull requests at same time.
|
// TODO: test more pull requests at same time.
|
||||||
func TestPullRequests() {
|
func TestPullRequests() {
|
||||||
prs := make([]*PullRequest, 0, 10)
|
var prs []*PullRequest
|
||||||
_ = x.Iterate(PullRequest{
|
_ = db.Where("status = ?", PullRequestStatusChecking).FindInBatches(&prs, 100, func(tx *gorm.DB, batch int) error {
|
||||||
Status: PullRequestStatusChecking,
|
for i := range prs {
|
||||||
},
|
pr := prs[i]
|
||||||
func(idx int, bean any) error {
|
|
||||||
pr := bean.(*PullRequest)
|
|
||||||
|
|
||||||
if err := pr.LoadAttributes(); err != nil {
|
if err := pr.LoadAttributes(); err != nil {
|
||||||
log.Error("LoadAttributes: %v", err)
|
log.Error("LoadAttributes: %v", err)
|
||||||
return nil
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := pr.testPatch(); err != nil {
|
if err := pr.testPatch(); err != nil {
|
||||||
log.Error("testPatch: %v", err)
|
log.Error("testPatch: %v", err)
|
||||||
return nil
|
continue
|
||||||
}
|
}
|
||||||
prs = append(prs, pr)
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
// Update pull request status.
|
// Update pull request status.
|
||||||
for _, pr := range prs {
|
for _, pr := range prs {
|
||||||
|
|||||||
@@ -6,12 +6,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
log "unknwon.dev/clog/v2"
|
|
||||||
"xorm.io/xorm"
|
|
||||||
|
|
||||||
"github.com/cockroachdb/errors"
|
"github.com/cockroachdb/errors"
|
||||||
"github.com/gogs/git-module"
|
"github.com/gogs/git-module"
|
||||||
api "github.com/gogs/go-gogs-client"
|
api "github.com/gogs/go-gogs-client"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
log "unknwon.dev/clog/v2"
|
||||||
|
|
||||||
"gogs.io/gogs/internal/errutil"
|
"gogs.io/gogs/internal/errutil"
|
||||||
"gogs.io/gogs/internal/process"
|
"gogs.io/gogs/internal/process"
|
||||||
@@ -21,40 +20,39 @@ import (
|
|||||||
type Release struct {
|
type Release struct {
|
||||||
ID int64
|
ID int64
|
||||||
RepoID int64
|
RepoID int64
|
||||||
Repo *Repository `xorm:"-" json:"-" gorm:"-"`
|
Repo *Repository `gorm:"-" json:"-"`
|
||||||
PublisherID int64
|
PublisherID int64
|
||||||
Publisher *User `xorm:"-" json:"-" gorm:"-"`
|
Publisher *User `gorm:"-" json:"-"`
|
||||||
TagName string
|
TagName string
|
||||||
LowerTagName string
|
LowerTagName string
|
||||||
Target string
|
Target string
|
||||||
Title string
|
Title string
|
||||||
Sha1 string `xorm:"VARCHAR(40)"`
|
Sha1 string `gorm:"type:varchar(40)"`
|
||||||
NumCommits int64
|
NumCommits int64
|
||||||
NumCommitsBehind int64 `xorm:"-" json:"-" gorm:"-"`
|
NumCommitsBehind int64 `gorm:"-" json:"-"`
|
||||||
Note string `xorm:"TEXT"`
|
Note string `gorm:"type:text"`
|
||||||
IsDraft bool `xorm:"NOT NULL DEFAULT false"`
|
IsDraft bool `gorm:"not null;default:false"`
|
||||||
IsPrerelease bool
|
IsPrerelease bool
|
||||||
|
|
||||||
Created time.Time `xorm:"-" json:"-" gorm:"-"`
|
Created time.Time `gorm:"-" json:"-"`
|
||||||
CreatedUnix int64
|
CreatedUnix int64
|
||||||
|
|
||||||
Attachments []*Attachment `xorm:"-" json:"-" gorm:"-"`
|
Attachments []*Attachment `gorm:"-" json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Release) BeforeInsert() {
|
func (r *Release) BeforeCreate(tx *gorm.DB) error {
|
||||||
if r.CreatedUnix == 0 {
|
if r.CreatedUnix == 0 {
|
||||||
r.CreatedUnix = time.Now().Unix()
|
r.CreatedUnix = tx.NowFunc().Unix()
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Release) AfterSet(colName string, _ xorm.Cell) {
|
func (r *Release) AfterFind(tx *gorm.DB) error {
|
||||||
switch colName {
|
r.Created = time.Unix(r.CreatedUnix, 0).Local()
|
||||||
case "created_unix":
|
return nil
|
||||||
r.Created = time.Unix(r.CreatedUnix, 0).Local()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Release) loadAttributes(e Engine) (err error) {
|
func (r *Release) loadAttributes(e *gorm.DB) (err error) {
|
||||||
if r.Repo == nil {
|
if r.Repo == nil {
|
||||||
r.Repo, err = getRepositoryByID(e, r.RepoID)
|
r.Repo, err = getRepositoryByID(e, r.RepoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -85,7 +83,7 @@ func (r *Release) loadAttributes(e Engine) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Release) LoadAttributes() error {
|
func (r *Release) LoadAttributes() error {
|
||||||
return r.loadAttributes(x)
|
return r.loadAttributes(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method assumes some fields assigned with values:
|
// This method assumes some fields assigned with values:
|
||||||
@@ -110,7 +108,9 @@ func IsReleaseExist(repoID int64, tagName string) (bool, error) {
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return x.Get(&Release{RepoID: repoID, LowerTagName: strings.ToLower(tagName)})
|
var count int64
|
||||||
|
err := db.Model(&Release{}).Where("repo_id = ? AND lower_tag_name = ?", repoID, strings.ToLower(tagName)).Count(&count).Error
|
||||||
|
return count > 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTag(gitRepo *git.Repository, r *Release) error {
|
func createTag(gitRepo *git.Repository, r *Release) error {
|
||||||
@@ -171,24 +171,21 @@ func NewRelease(gitRepo *git.Repository, r *Release, uuids []string) error {
|
|||||||
}
|
}
|
||||||
r.LowerTagName = strings.ToLower(r.TagName)
|
r.LowerTagName = strings.ToLower(r.TagName)
|
||||||
|
|
||||||
sess := x.NewSession()
|
err = db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
if err := tx.Create(r).Error; err != nil {
|
||||||
if err = sess.Begin(); err != nil {
|
return errors.Newf("insert: %v", err)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = sess.Insert(r); err != nil {
|
|
||||||
return errors.Newf("insert: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(uuids) > 0 {
|
|
||||||
if _, err = sess.In("uuid", uuids).Cols("release_id").Update(&Attachment{ReleaseID: r.ID}); err != nil {
|
|
||||||
return errors.Newf("link attachments: %v", err)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if err = sess.Commit(); err != nil {
|
if len(uuids) > 0 {
|
||||||
return errors.Newf("commit: %v", err)
|
if err := tx.Model(&Attachment{}).Where("uuid IN ?", uuids).Update("release_id", r.ID).Error; err != nil {
|
||||||
|
return errors.Newf("link attachments: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only send webhook when actually published, skip drafts
|
// Only send webhook when actually published, skip drafts
|
||||||
@@ -231,8 +228,8 @@ func GetRelease(repoID int64, tagName string) (*Release, error) {
|
|||||||
return nil, ErrReleaseNotExist{args: map[string]any{"tag": tagName}}
|
return nil, ErrReleaseNotExist{args: map[string]any{"tag": tagName}}
|
||||||
}
|
}
|
||||||
|
|
||||||
r := &Release{RepoID: repoID, LowerTagName: strings.ToLower(tagName)}
|
r := &Release{}
|
||||||
if _, err = x.Get(r); err != nil {
|
if err = db.Where("repo_id = ? AND lower_tag_name = ?", repoID, strings.ToLower(tagName)).First(r).Error; err != nil {
|
||||||
return nil, errors.Newf("get: %v", err)
|
return nil, errors.Newf("get: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,11 +239,12 @@ func GetRelease(repoID int64, tagName string) (*Release, error) {
|
|||||||
// GetReleaseByID returns release with given ID.
|
// GetReleaseByID returns release with given ID.
|
||||||
func GetReleaseByID(id int64) (*Release, error) {
|
func GetReleaseByID(id int64) (*Release, error) {
|
||||||
r := new(Release)
|
r := new(Release)
|
||||||
has, err := x.Id(id).Get(r)
|
err := db.Where("id = ?", id).First(r).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, ErrReleaseNotExist{args: map[string]any{"releaseID": id}}
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
|
||||||
return nil, ErrReleaseNotExist{args: map[string]any{"releaseID": id}}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return r, r.LoadAttributes()
|
return r, r.LoadAttributes()
|
||||||
@@ -256,24 +254,24 @@ func GetReleaseByID(id int64) (*Release, error) {
|
|||||||
// If matches is not empty, only published releases in matches will be returned.
|
// If matches is not empty, only published releases in matches will be returned.
|
||||||
// In any case, drafts won't be returned by this function.
|
// In any case, drafts won't be returned by this function.
|
||||||
func GetPublishedReleasesByRepoID(repoID int64, matches ...string) ([]*Release, error) {
|
func GetPublishedReleasesByRepoID(repoID int64, matches ...string) ([]*Release, error) {
|
||||||
sess := x.Where("repo_id = ?", repoID).And("is_draft = ?", false).Desc("created_unix")
|
query := db.Where("repo_id = ? AND is_draft = ?", repoID, false).Order("created_unix DESC")
|
||||||
if len(matches) > 0 {
|
if len(matches) > 0 {
|
||||||
sess.In("tag_name", matches)
|
query = query.Where("tag_name IN ?", matches)
|
||||||
}
|
}
|
||||||
releases := make([]*Release, 0, 5)
|
releases := make([]*Release, 0, 5)
|
||||||
return releases, sess.Find(&releases, new(Release))
|
return releases, query.Find(&releases).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetReleasesByRepoID returns a list of all releases (including drafts) of given repository.
|
// GetReleasesByRepoID returns a list of all releases (including drafts) of given repository.
|
||||||
func GetReleasesByRepoID(repoID int64) ([]*Release, error) {
|
func GetReleasesByRepoID(repoID int64) ([]*Release, error) {
|
||||||
releases := make([]*Release, 0)
|
releases := make([]*Release, 0)
|
||||||
return releases, x.Where("repo_id = ?", repoID).Find(&releases)
|
return releases, db.Where("repo_id = ?", repoID).Find(&releases).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDraftReleasesByRepoID returns all draft releases of repository.
|
// GetDraftReleasesByRepoID returns all draft releases of repository.
|
||||||
func GetDraftReleasesByRepoID(repoID int64) ([]*Release, error) {
|
func GetDraftReleasesByRepoID(repoID int64) ([]*Release, error) {
|
||||||
releases := make([]*Release, 0)
|
releases := make([]*Release, 0)
|
||||||
return releases, x.Where("repo_id = ?", repoID).And("is_draft = ?", true).Find(&releases)
|
return releases, db.Where("repo_id = ? AND is_draft = ?", repoID, true).Find(&releases).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
type ReleaseSorter struct {
|
type ReleaseSorter struct {
|
||||||
@@ -310,28 +308,26 @@ func UpdateRelease(doer *User, gitRepo *git.Repository, r *Release, isPublish bo
|
|||||||
|
|
||||||
r.PublisherID = doer.ID
|
r.PublisherID = doer.ID
|
||||||
|
|
||||||
sess := x.NewSession()
|
err = db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
if err := tx.Model(r).Where("id = ?", r.ID).Updates(r).Error; err != nil {
|
||||||
if err = sess.Begin(); err != nil {
|
return errors.Newf("Update: %v", err)
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err = sess.ID(r.ID).AllCols().Update(r); err != nil {
|
|
||||||
return errors.Newf("Update: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unlink all current attachments and link back later if still valid
|
|
||||||
if _, err = sess.Exec("UPDATE attachment SET release_id = 0 WHERE release_id = ?", r.ID); err != nil {
|
|
||||||
return errors.Newf("unlink current attachments: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(uuids) > 0 {
|
|
||||||
if _, err = sess.In("uuid", uuids).Cols("release_id").Update(&Attachment{ReleaseID: r.ID}); err != nil {
|
|
||||||
return errors.Newf("link attachments: %v", err)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if err = sess.Commit(); err != nil {
|
// Unlink all current attachments and link back later if still valid
|
||||||
return errors.Newf("commit: %v", err)
|
if err := tx.Exec("UPDATE attachment SET release_id = 0 WHERE release_id = ?", r.ID).Error; err != nil {
|
||||||
|
return errors.Newf("unlink current attachments: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(uuids) > 0 {
|
||||||
|
if err := tx.Model(&Attachment{}).Where("uuid IN ?", uuids).Update("release_id", r.ID).Error; err != nil {
|
||||||
|
return errors.Newf("link attachments: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isPublish {
|
if !isPublish {
|
||||||
@@ -366,7 +362,7 @@ func DeleteReleaseOfRepoByID(repoID, id int64) error {
|
|||||||
return errors.Newf("git tag -d: %v - %s", err, stderr)
|
return errors.Newf("git tag -d: %v - %s", err, stderr)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = x.Id(rel.ID).Delete(new(Release)); err != nil {
|
if err = db.Where("id = ?", rel.ID).Delete(new(Release)).Error; err != nil {
|
||||||
return errors.Newf("delete: %v", err)
|
return errors.Newf("delete: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/cockroachdb/errors"
|
"github.com/cockroachdb/errors"
|
||||||
"github.com/gogs/git-module"
|
"github.com/gogs/git-module"
|
||||||
"github.com/unknwon/com"
|
"github.com/unknwon/com"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
"gogs.io/gogs/internal/errutil"
|
"gogs.io/gogs/internal/errutil"
|
||||||
"gogs.io/gogs/internal/tool"
|
"gogs.io/gogs/internal/tool"
|
||||||
@@ -93,8 +94,9 @@ type ProtectBranchWhitelist struct {
|
|||||||
|
|
||||||
// IsUserInProtectBranchWhitelist returns true if given user is in the whitelist of a branch in a repository.
|
// IsUserInProtectBranchWhitelist returns true if given user is in the whitelist of a branch in a repository.
|
||||||
func IsUserInProtectBranchWhitelist(repoID, userID int64, branch string) bool {
|
func IsUserInProtectBranchWhitelist(repoID, userID int64, branch string) bool {
|
||||||
has, err := x.Where("repo_id = ?", repoID).And("user_id = ?", userID).And("name = ?", branch).Get(new(ProtectBranchWhitelist))
|
var whitelist ProtectBranchWhitelist
|
||||||
return has && err == nil
|
err := db.Where("repo_id = ?", repoID).Where("user_id = ?", userID).Where("name = ?", branch).First(&whitelist).Error
|
||||||
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProtectBranch contains options of a protected branch.
|
// ProtectBranch contains options of a protected branch.
|
||||||
@@ -115,11 +117,11 @@ func GetProtectBranchOfRepoByName(repoID int64, name string) (*ProtectBranch, er
|
|||||||
RepoID: repoID,
|
RepoID: repoID,
|
||||||
Name: name,
|
Name: name,
|
||||||
}
|
}
|
||||||
has, err := x.Get(protectBranch)
|
err := db.Where("repo_id = ? AND name = ?", repoID, name).First(protectBranch).Error
|
||||||
if err != nil {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return nil, err
|
|
||||||
} else if !has {
|
|
||||||
return nil, ErrBranchNotExist{args: map[string]any{"name": name}}
|
return nil, ErrBranchNotExist{args: map[string]any{"name": name}}
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
return protectBranch, nil
|
return protectBranch, nil
|
||||||
}
|
}
|
||||||
@@ -136,23 +138,19 @@ func IsBranchOfRepoRequirePullRequest(repoID int64, name string) bool {
|
|||||||
// UpdateProtectBranch saves branch protection options.
|
// UpdateProtectBranch saves branch protection options.
|
||||||
// If ID is 0, it creates a new record. Otherwise, updates existing record.
|
// If ID is 0, it creates a new record. Otherwise, updates existing record.
|
||||||
func UpdateProtectBranch(protectBranch *ProtectBranch) (err error) {
|
func UpdateProtectBranch(protectBranch *ProtectBranch) (err error) {
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
if protectBranch.ID == 0 {
|
||||||
if err = sess.Begin(); err != nil {
|
if err := tx.Create(protectBranch).Error; err != nil {
|
||||||
return err
|
return errors.Newf("insert: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if protectBranch.ID == 0 {
|
|
||||||
if _, err = sess.Insert(protectBranch); err != nil {
|
|
||||||
return errors.Newf("insert: %v", err)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = sess.ID(protectBranch.ID).AllCols().Update(protectBranch); err != nil {
|
if err := tx.Model(&ProtectBranch{}).Where("id = ?", protectBranch.ID).Updates(protectBranch).Error; err != nil {
|
||||||
return errors.Newf("update: %v", err)
|
return errors.Newf("update: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return sess.Commit()
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateOrgProtectBranch saves branch protection options of organizational repository.
|
// UpdateOrgProtectBranch saves branch protection options of organizational repository.
|
||||||
@@ -209,7 +207,7 @@ func UpdateOrgProtectBranch(repo *Repository, protectBranch *ProtectBranch, whit
|
|||||||
|
|
||||||
// Make sure protectBranch.ID is not 0 for whitelists
|
// Make sure protectBranch.ID is not 0 for whitelists
|
||||||
if protectBranch.ID == 0 {
|
if protectBranch.ID == 0 {
|
||||||
if _, err = x.Insert(protectBranch); err != nil {
|
if err = db.Create(protectBranch).Error; err != nil {
|
||||||
return errors.Newf("insert: %v", err)
|
return errors.Newf("insert: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -247,30 +245,29 @@ func UpdateOrgProtectBranch(repo *Repository, protectBranch *ProtectBranch, whit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
if err := tx.Model(&ProtectBranch{}).Where("id = ?", protectBranch.ID).Updates(protectBranch).Error; err != nil {
|
||||||
if err = sess.Begin(); err != nil {
|
return errors.Newf("Update: %v", err)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = sess.ID(protectBranch.ID).AllCols().Update(protectBranch); err != nil {
|
|
||||||
return errors.Newf("Update: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh whitelists
|
|
||||||
if hasUsersChanged || hasTeamsChanged {
|
|
||||||
if _, err = sess.Delete(&ProtectBranchWhitelist{ProtectBranchID: protectBranch.ID}); err != nil {
|
|
||||||
return errors.Newf("delete old protect branch whitelists: %v", err)
|
|
||||||
} else if _, err = sess.Insert(whitelists); err != nil {
|
|
||||||
return errors.Newf("insert new protect branch whitelists: %v", err)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return sess.Commit()
|
// Refresh whitelists
|
||||||
|
if hasUsersChanged || hasTeamsChanged {
|
||||||
|
if err := tx.Delete(&ProtectBranchWhitelist{}, "protect_branch_id = ?", protectBranch.ID).Error; err != nil {
|
||||||
|
return errors.Newf("delete old protect branch whitelists: %v", err)
|
||||||
|
}
|
||||||
|
if len(whitelists) > 0 {
|
||||||
|
if err := tx.Create(&whitelists).Error; err != nil {
|
||||||
|
return errors.Newf("insert new protect branch whitelists: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetProtectBranchesByRepoID returns a list of *ProtectBranch in given repository.
|
// GetProtectBranchesByRepoID returns a list of *ProtectBranch in given repository.
|
||||||
func GetProtectBranchesByRepoID(repoID int64) ([]*ProtectBranch, error) {
|
func GetProtectBranchesByRepoID(repoID int64) ([]*ProtectBranch, error) {
|
||||||
protectBranches := make([]*ProtectBranch, 0, 2)
|
protectBranches := make([]*ProtectBranch, 0, 2)
|
||||||
return protectBranches, x.Where("repo_id = ? and protected = ?", repoID, true).Asc("name").Find(&protectBranches)
|
return protectBranches, db.Where("repo_id = ? AND protected = ?", repoID, true).Order("name ASC").Find(&protectBranches).Error
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/cockroachdb/errors"
|
"github.com/cockroachdb/errors"
|
||||||
api "github.com/gogs/go-gogs-client"
|
api "github.com/gogs/go-gogs-client"
|
||||||
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Collaboration represent the relation between an individual and a repository.
|
// Collaboration represent the relation between an individual and a repository.
|
||||||
@@ -34,12 +35,12 @@ func IsCollaborator(repoID, userID int64) bool {
|
|||||||
RepoID: repoID,
|
RepoID: repoID,
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
}
|
}
|
||||||
has, err := x.Get(collaboration)
|
err := db.Where("repo_id = ? AND user_id = ?", repoID, userID).First(collaboration).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("get collaboration [repo_id: %d, user_id: %d]: %v", repoID, userID, err)
|
log.Error("get collaboration [repo_id: %d, user_id: %d]: %v", repoID, userID, err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return has
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) IsCollaborator(userID int64) bool {
|
func (r *Repository) IsCollaborator(userID int64) bool {
|
||||||
@@ -53,32 +54,29 @@ func (r *Repository) AddCollaborator(u *User) error {
|
|||||||
UserID: u.ID,
|
UserID: u.ID,
|
||||||
}
|
}
|
||||||
|
|
||||||
has, err := x.Get(collaboration)
|
var existing Collaboration
|
||||||
if err != nil {
|
err := db.Where("repo_id = ? AND user_id = ?", r.ID, u.ID).First(&existing).Error
|
||||||
return err
|
if err == nil {
|
||||||
} else if has {
|
|
||||||
return nil
|
return nil
|
||||||
|
} else if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
collaboration.Mode = AccessModeWrite
|
collaboration.Mode = AccessModeWrite
|
||||||
|
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
if err := tx.Create(collaboration).Error; err != nil {
|
||||||
if err = sess.Begin(); err != nil {
|
return err
|
||||||
return err
|
}
|
||||||
}
|
if err := r.recalculateAccesses(tx); err != nil {
|
||||||
|
return errors.Newf("recalculateAccesses [repo_id: %v]: %v", r.ID, err)
|
||||||
if _, err = sess.Insert(collaboration); err != nil {
|
}
|
||||||
return err
|
return nil
|
||||||
} else if err = r.recalculateAccesses(sess); err != nil {
|
})
|
||||||
return errors.Newf("recalculateAccesses [repo_id: %v]: %v", r.ID, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return sess.Commit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) getCollaborations(e Engine) ([]*Collaboration, error) {
|
func (r *Repository) getCollaborations(e *gorm.DB) ([]*Collaboration, error) {
|
||||||
collaborations := make([]*Collaboration, 0)
|
collaborations := make([]*Collaboration, 0)
|
||||||
return collaborations, e.Find(&collaborations, &Collaboration{RepoID: r.ID})
|
return collaborations, e.Where("repo_id = ?", r.ID).Find(&collaborations).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collaborator represents a user with collaboration details.
|
// Collaborator represents a user with collaboration details.
|
||||||
@@ -98,7 +96,7 @@ func (c *Collaborator) APIFormat() *api.Collaborator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) getCollaborators(e Engine) ([]*Collaborator, error) {
|
func (r *Repository) getCollaborators(e *gorm.DB) ([]*Collaborator, error) {
|
||||||
collaborations, err := r.getCollaborations(e)
|
collaborations, err := r.getCollaborations(e)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Newf("getCollaborations: %v", err)
|
return nil, errors.Newf("getCollaborations: %v", err)
|
||||||
@@ -120,7 +118,7 @@ func (r *Repository) getCollaborators(e Engine) ([]*Collaborator, error) {
|
|||||||
|
|
||||||
// GetCollaborators returns the collaborators for a repository
|
// GetCollaborators returns the collaborators for a repository
|
||||||
func (r *Repository) GetCollaborators() ([]*Collaborator, error) {
|
func (r *Repository) GetCollaborators() ([]*Collaborator, error) {
|
||||||
return r.getCollaborators(x)
|
return r.getCollaborators(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChangeCollaborationAccessMode sets new access mode for the collaboration.
|
// ChangeCollaborationAccessMode sets new access mode for the collaboration.
|
||||||
@@ -134,11 +132,11 @@ func (r *Repository) ChangeCollaborationAccessMode(userID int64, mode AccessMode
|
|||||||
RepoID: r.ID,
|
RepoID: r.ID,
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
}
|
}
|
||||||
has, err := x.Get(collaboration)
|
err := db.Where("repo_id = ? AND user_id = ?", r.ID, userID).First(collaboration).Error
|
||||||
if err != nil {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return errors.Newf("get collaboration: %v", err)
|
|
||||||
} else if !has {
|
|
||||||
return nil
|
return nil
|
||||||
|
} else if err != nil {
|
||||||
|
return errors.Newf("get collaboration: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if collaboration.Mode == mode {
|
if collaboration.Mode == mode {
|
||||||
@@ -159,35 +157,31 @@ func (r *Repository) ChangeCollaborationAccessMode(userID int64, mode AccessMode
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
if err := tx.Model(&Collaboration{}).Where("id = ?", collaboration.ID).Updates(collaboration).Error; err != nil {
|
||||||
if err = sess.Begin(); err != nil {
|
return errors.Newf("update collaboration: %v", err)
|
||||||
return err
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = sess.ID(collaboration.ID).AllCols().Update(collaboration); err != nil {
|
access := &Access{
|
||||||
return errors.Newf("update collaboration: %v", err)
|
UserID: userID,
|
||||||
}
|
RepoID: r.ID,
|
||||||
|
}
|
||||||
|
err := tx.Where("user_id = ? AND repo_id = ?", userID, r.ID).First(access).Error
|
||||||
|
if err == nil {
|
||||||
|
if err := tx.Exec("UPDATE access SET mode = ? WHERE user_id = ? AND repo_id = ?", mode, userID, r.ID).Error; err != nil {
|
||||||
|
return errors.Newf("update access table: %v", err)
|
||||||
|
}
|
||||||
|
} else if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
access.Mode = mode
|
||||||
|
if err := tx.Create(access).Error; err != nil {
|
||||||
|
return errors.Newf("insert access table: %v", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return errors.Newf("get access record: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
access := &Access{
|
return nil
|
||||||
UserID: userID,
|
})
|
||||||
RepoID: r.ID,
|
|
||||||
}
|
|
||||||
has, err = sess.Get(access)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Newf("get access record: %v", err)
|
|
||||||
}
|
|
||||||
if has {
|
|
||||||
_, err = sess.Exec("UPDATE access SET mode = ? WHERE user_id = ? AND repo_id = ?", mode, userID, r.ID)
|
|
||||||
} else {
|
|
||||||
access.Mode = mode
|
|
||||||
_, err = sess.Insert(access)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return errors.Newf("update/insert access table: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return sess.Commit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteCollaboration removes collaboration relation between the user and repository.
|
// DeleteCollaboration removes collaboration relation between the user and repository.
|
||||||
@@ -201,19 +195,20 @@ func DeleteCollaboration(repo *Repository, userID int64) (err error) {
|
|||||||
UserID: userID,
|
UserID: userID,
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
result := tx.Delete(collaboration, "repo_id = ? AND user_id = ?", repo.ID, userID)
|
||||||
if err = sess.Begin(); err != nil {
|
if result.Error != nil {
|
||||||
return err
|
return result.Error
|
||||||
}
|
} else if result.RowsAffected == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if has, err := sess.Delete(collaboration); err != nil || has == 0 {
|
if err := repo.recalculateAccesses(tx); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if err = repo.recalculateAccesses(sess); err != nil {
|
}
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return sess.Commit()
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) DeleteCollaboration(userID int64) error {
|
func (r *Repository) DeleteCollaboration(userID int64) error {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/cockroachdb/errors"
|
"github.com/cockroachdb/errors"
|
||||||
gouuid "github.com/satori/go.uuid"
|
gouuid "github.com/satori/go.uuid"
|
||||||
"github.com/unknwon/com"
|
"github.com/unknwon/com"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
"github.com/gogs/git-module"
|
"github.com/gogs/git-module"
|
||||||
|
|
||||||
@@ -441,7 +442,7 @@ func NewUpload(name string, buf []byte, file multipart.File) (_ *Upload, err err
|
|||||||
return nil, errors.Newf("copy: %v", err)
|
return nil, errors.Newf("copy: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := x.Insert(upload); err != nil {
|
if err := db.Create(upload).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,11 +451,12 @@ func NewUpload(name string, buf []byte, file multipart.File) (_ *Upload, err err
|
|||||||
|
|
||||||
func GetUploadByUUID(uuid string) (*Upload, error) {
|
func GetUploadByUUID(uuid string) (*Upload, error) {
|
||||||
upload := &Upload{UUID: uuid}
|
upload := &Upload{UUID: uuid}
|
||||||
has, err := x.Get(upload)
|
err := db.Where("uuid = ?", uuid).First(upload).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, ErrUploadNotExist{0, uuid}
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
|
||||||
return nil, ErrUploadNotExist{0, uuid}
|
|
||||||
}
|
}
|
||||||
return upload, nil
|
return upload, nil
|
||||||
}
|
}
|
||||||
@@ -466,7 +468,7 @@ func GetUploadsByUUIDs(uuids []string) ([]*Upload, error) {
|
|||||||
|
|
||||||
// Silently drop invalid uuids.
|
// Silently drop invalid uuids.
|
||||||
uploads := make([]*Upload, 0, len(uuids))
|
uploads := make([]*Upload, 0, len(uuids))
|
||||||
return uploads, x.In("uuid", uuids).Find(&uploads)
|
return uploads, db.Where("uuid IN ?", uuids).Find(&uploads).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteUploads(uploads ...*Upload) (err error) {
|
func DeleteUploads(uploads ...*Upload) (err error) {
|
||||||
@@ -474,32 +476,28 @@ func DeleteUploads(uploads ...*Upload) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
ids := make([]int64, len(uploads))
|
||||||
if err = sess.Begin(); err != nil {
|
for i := 0; i < len(uploads); i++ {
|
||||||
return err
|
ids[i] = uploads[i].ID
|
||||||
}
|
}
|
||||||
|
if err := tx.Where("id IN ?", ids).Delete(new(Upload)).Error; err != nil {
|
||||||
ids := make([]int64, len(uploads))
|
return errors.Newf("delete uploads: %v", err)
|
||||||
for i := 0; i < len(uploads); i++ {
|
|
||||||
ids[i] = uploads[i].ID
|
|
||||||
}
|
|
||||||
if _, err = sess.In("id", ids).Delete(new(Upload)); err != nil {
|
|
||||||
return errors.Newf("delete uploads: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, upload := range uploads {
|
|
||||||
localPath := upload.LocalPath()
|
|
||||||
if !osutil.IsFile(localPath) {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.Remove(localPath); err != nil {
|
for _, upload := range uploads {
|
||||||
return errors.Newf("remove upload: %v", err)
|
localPath := upload.LocalPath()
|
||||||
}
|
if !osutil.IsFile(localPath) {
|
||||||
}
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
return sess.Commit()
|
if err := os.Remove(localPath); err != nil {
|
||||||
|
return errors.Newf("remove upload: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteUpload(u *Upload) error {
|
func DeleteUpload(u *Upload) error {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/cockroachdb/errors"
|
"github.com/cockroachdb/errors"
|
||||||
api "github.com/gogs/go-gogs-client"
|
api "github.com/gogs/go-gogs-client"
|
||||||
@@ -28,13 +27,6 @@ func (r *Repository) BeforeUpdate(tx *gorm.DB) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AfterFind implements the GORM query hook.
|
|
||||||
func (r *Repository) AfterFind(_ *gorm.DB) error {
|
|
||||||
r.Created = time.Unix(r.CreatedUnix, 0).Local()
|
|
||||||
r.Updated = time.Unix(r.UpdatedUnix, 0).Local()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type RepositoryAPIFormatOptions struct {
|
type RepositoryAPIFormatOptions struct {
|
||||||
Permission *api.Permission
|
Permission *api.Permission
|
||||||
Parent *api.Repository
|
Parent *api.Repository
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ import (
|
|||||||
"github.com/cockroachdb/errors"
|
"github.com/cockroachdb/errors"
|
||||||
"github.com/unknwon/com"
|
"github.com/unknwon/com"
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
|
"gorm.io/gorm"
|
||||||
log "unknwon.dev/clog/v2"
|
log "unknwon.dev/clog/v2"
|
||||||
"xorm.io/xorm"
|
|
||||||
|
|
||||||
"gogs.io/gogs/internal/conf"
|
"gogs.io/gogs/internal/conf"
|
||||||
"gogs.io/gogs/internal/errutil"
|
"gogs.io/gogs/internal/errutil"
|
||||||
@@ -40,38 +40,41 @@ const (
|
|||||||
// PublicKey represents a user or deploy SSH public key.
|
// PublicKey represents a user or deploy SSH public key.
|
||||||
type PublicKey struct {
|
type PublicKey struct {
|
||||||
ID int64 `gorm:"primaryKey"`
|
ID int64 `gorm:"primaryKey"`
|
||||||
OwnerID int64 `xorm:"INDEX NOT NULL" gorm:"index;not null"`
|
OwnerID int64 `gorm:"index;not null"`
|
||||||
Name string `xorm:"NOT NULL" gorm:"not null"`
|
Name string `gorm:"not null"`
|
||||||
Fingerprint string `xorm:"NOT NULL" gorm:"not null"`
|
Fingerprint string `gorm:"not null"`
|
||||||
Content string `xorm:"TEXT NOT NULL" gorm:"type:TEXT;not null"`
|
Content string `gorm:"type:text;not null"`
|
||||||
Mode AccessMode `xorm:"NOT NULL DEFAULT 2" gorm:"not null;default:2"`
|
Mode AccessMode `gorm:"not null;default:2"`
|
||||||
Type KeyType `xorm:"NOT NULL DEFAULT 1" gorm:"not null;default:1"`
|
Type KeyType `gorm:"not null;default:1"`
|
||||||
|
|
||||||
Created time.Time `xorm:"-" json:"-" gorm:"-"`
|
Created time.Time `gorm:"-" json:"-"`
|
||||||
CreatedUnix int64
|
CreatedUnix int64
|
||||||
Updated time.Time `xorm:"-" json:"-" gorm:"-"` // Note: Updated must below Created for AfterSet.
|
Updated time.Time `gorm:"-" json:"-"` // Note: Updated must below Created for AfterFind.
|
||||||
UpdatedUnix int64
|
UpdatedUnix int64
|
||||||
HasRecentActivity bool `xorm:"-" json:"-" gorm:"-"`
|
HasRecentActivity bool `gorm:"-" json:"-"`
|
||||||
HasUsed bool `xorm:"-" json:"-" gorm:"-"`
|
HasUsed bool `gorm:"-" json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *PublicKey) BeforeInsert() {
|
func (k *PublicKey) BeforeCreate(tx *gorm.DB) error {
|
||||||
k.CreatedUnix = time.Now().Unix()
|
if k.CreatedUnix == 0 {
|
||||||
|
k.CreatedUnix = tx.NowFunc().Unix()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *PublicKey) BeforeUpdate() {
|
func (k *PublicKey) BeforeUpdate(tx *gorm.DB) error {
|
||||||
k.UpdatedUnix = time.Now().Unix()
|
k.UpdatedUnix = tx.NowFunc().Unix()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *PublicKey) AfterSet(colName string, _ xorm.Cell) {
|
func (k *PublicKey) AfterFind(tx *gorm.DB) error {
|
||||||
switch colName {
|
k.Created = time.Unix(k.CreatedUnix, 0).Local()
|
||||||
case "created_unix":
|
if k.UpdatedUnix > 0 {
|
||||||
k.Created = time.Unix(k.CreatedUnix, 0).Local()
|
|
||||||
case "updated_unix":
|
|
||||||
k.Updated = time.Unix(k.UpdatedUnix, 0).Local()
|
k.Updated = time.Unix(k.UpdatedUnix, 0).Local()
|
||||||
k.HasUsed = k.Updated.After(k.Created)
|
k.HasUsed = k.Updated.After(k.Created)
|
||||||
k.HasRecentActivity = k.Updated.Add(7 * 24 * time.Hour).After(time.Now())
|
k.HasRecentActivity = k.Updated.Add(7 * 24 * time.Hour).After(tx.NowFunc())
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// OmitEmail returns content of public key without email address.
|
// OmitEmail returns content of public key without email address.
|
||||||
@@ -356,19 +359,16 @@ func appendAuthorizedKeysToFile(keys ...*PublicKey) error {
|
|||||||
// checkKeyContent onlys checks if key content has been used as public key,
|
// checkKeyContent onlys checks if key content has been used as public key,
|
||||||
// it is OK to use same key as deploy key for multiple repositories/users.
|
// it is OK to use same key as deploy key for multiple repositories/users.
|
||||||
func checkKeyContent(content string) error {
|
func checkKeyContent(content string) error {
|
||||||
has, err := x.Get(&PublicKey{
|
err := db.Where("content = ? AND type = ?", content, KeyTypeUser).First(&PublicKey{}).Error
|
||||||
Content: content,
|
if err == nil {
|
||||||
Type: KeyTypeUser,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
} else if has {
|
|
||||||
return ErrKeyAlreadyExist{0, content}
|
return ErrKeyAlreadyExist{0, content}
|
||||||
|
} else if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addKey(e Engine, key *PublicKey) (err error) {
|
func addKey(tx *gorm.DB, key *PublicKey) (err error) {
|
||||||
// Calculate fingerprint.
|
// Calculate fingerprint.
|
||||||
tmpPath := strings.ReplaceAll(path.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().Nanosecond()), "id_rsa.pub"), "\\", "/")
|
tmpPath := strings.ReplaceAll(path.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().Nanosecond()), "id_rsa.pub"), "\\", "/")
|
||||||
_ = os.MkdirAll(path.Dir(tmpPath), os.ModePerm)
|
_ = os.MkdirAll(path.Dir(tmpPath), os.ModePerm)
|
||||||
@@ -385,7 +385,7 @@ func addKey(e Engine, key *PublicKey) (err error) {
|
|||||||
key.Fingerprint = strings.Split(stdout, " ")[1]
|
key.Fingerprint = strings.Split(stdout, " ")[1]
|
||||||
|
|
||||||
// Save SSH key.
|
// Save SSH key.
|
||||||
if _, err = e.Insert(key); err != nil {
|
if err = tx.Create(key).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,16 +404,10 @@ func AddPublicKey(ownerID int64, name, content string) (*PublicKey, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Key name of same user cannot be duplicated.
|
// Key name of same user cannot be duplicated.
|
||||||
has, err := x.Where("owner_id = ? AND name = ?", ownerID, name).Get(new(PublicKey))
|
err := db.Where("owner_id = ? AND name = ?", ownerID, name).First(new(PublicKey)).Error
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return nil, err
|
|
||||||
} else if has {
|
|
||||||
return nil, ErrKeyNameAlreadyUsed{ownerID, name}
|
return nil, ErrKeyNameAlreadyUsed{ownerID, name}
|
||||||
}
|
} else if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
|
||||||
sess := x.NewSession()
|
|
||||||
defer sess.Close()
|
|
||||||
if err = sess.Begin(); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -424,21 +418,25 @@ func AddPublicKey(ownerID int64, name, content string) (*PublicKey, error) {
|
|||||||
Mode: AccessModeWrite,
|
Mode: AccessModeWrite,
|
||||||
Type: KeyTypeUser,
|
Type: KeyTypeUser,
|
||||||
}
|
}
|
||||||
if err = addKey(sess, key); err != nil {
|
err = db.Transaction(func(tx *gorm.DB) error {
|
||||||
|
return addKey(tx, key)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
return nil, errors.Newf("addKey: %v", err)
|
return nil, errors.Newf("addKey: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return key, sess.Commit()
|
return key, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPublicKeyByID returns public key by given ID.
|
// GetPublicKeyByID returns public key by given ID.
|
||||||
func GetPublicKeyByID(keyID int64) (*PublicKey, error) {
|
func GetPublicKeyByID(keyID int64) (*PublicKey, error) {
|
||||||
key := new(PublicKey)
|
key := new(PublicKey)
|
||||||
has, err := x.Id(keyID).Get(key)
|
err := db.Where("id = ?", keyID).First(key).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, ErrKeyNotExist{keyID}
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
|
||||||
return nil, ErrKeyNotExist{keyID}
|
|
||||||
}
|
}
|
||||||
return key, nil
|
return key, nil
|
||||||
}
|
}
|
||||||
@@ -448,11 +446,12 @@ func GetPublicKeyByID(keyID int64) (*PublicKey, error) {
|
|||||||
// exists.
|
// exists.
|
||||||
func SearchPublicKeyByContent(content string) (*PublicKey, error) {
|
func SearchPublicKeyByContent(content string) (*PublicKey, error) {
|
||||||
key := new(PublicKey)
|
key := new(PublicKey)
|
||||||
has, err := x.Where("content like ?", content+"%").Get(key)
|
err := db.Where("content LIKE ?", content+"%").First(key).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, ErrKeyNotExist{}
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
|
||||||
return nil, ErrKeyNotExist{}
|
|
||||||
}
|
}
|
||||||
return key, nil
|
return key, nil
|
||||||
}
|
}
|
||||||
@@ -460,23 +459,21 @@ func SearchPublicKeyByContent(content string) (*PublicKey, error) {
|
|||||||
// ListPublicKeys returns a list of public keys belongs to given user.
|
// ListPublicKeys returns a list of public keys belongs to given user.
|
||||||
func ListPublicKeys(uid int64) ([]*PublicKey, error) {
|
func ListPublicKeys(uid int64) ([]*PublicKey, error) {
|
||||||
keys := make([]*PublicKey, 0, 5)
|
keys := make([]*PublicKey, 0, 5)
|
||||||
return keys, x.Where("owner_id = ?", uid).Find(&keys)
|
return keys, db.Where("owner_id = ?", uid).Find(&keys).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatePublicKey updates given public key.
|
// UpdatePublicKey updates given public key.
|
||||||
func UpdatePublicKey(key *PublicKey) error {
|
func UpdatePublicKey(key *PublicKey) error {
|
||||||
_, err := x.Id(key.ID).AllCols().Update(key)
|
return db.Model(key).Where("id = ?", key.ID).Updates(key).Error
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// deletePublicKeys does the actual key deletion but does not update authorized_keys file.
|
// deletePublicKeys does the actual key deletion but does not update authorized_keys file.
|
||||||
func deletePublicKeys(e *xorm.Session, keyIDs ...int64) error {
|
func deletePublicKeys(tx *gorm.DB, keyIDs ...int64) error {
|
||||||
if len(keyIDs) == 0 {
|
if len(keyIDs) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := e.In("id", keyIDs).Delete(new(PublicKey))
|
return tx.Where("id IN ?", keyIDs).Delete(new(PublicKey)).Error
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeletePublicKey deletes SSH key information both in database and authorized_keys file.
|
// DeletePublicKey deletes SSH key information both in database and authorized_keys file.
|
||||||
@@ -494,17 +491,10 @@ func DeletePublicKey(doer *User, id int64) (err error) {
|
|||||||
return ErrKeyAccessDenied{doer.ID, key.ID, "public"}
|
return ErrKeyAccessDenied{doer.ID, key.ID, "public"}
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
err = db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
return deletePublicKeys(tx, id)
|
||||||
if err = sess.Begin(); err != nil {
|
})
|
||||||
return err
|
if err != nil {
|
||||||
}
|
|
||||||
|
|
||||||
if err = deletePublicKeys(sess, id); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = sess.Commit(); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -531,14 +521,24 @@ func RewriteAuthorizedKeys() error {
|
|||||||
}
|
}
|
||||||
defer os.Remove(tmpPath)
|
defer os.Remove(tmpPath)
|
||||||
|
|
||||||
err = x.Iterate(new(PublicKey), func(idx int, bean any) (err error) {
|
// Use FindInBatches to process keys in chunks to avoid memory issues with large datasets
|
||||||
_, err = f.WriteString((bean.(*PublicKey)).AuthorizedString())
|
err = db.FindInBatches(&[]PublicKey{}, 100, func(tx *gorm.DB, batch int) error {
|
||||||
return err
|
var keys []PublicKey
|
||||||
})
|
if err := tx.Find(&keys).Error; err != nil {
|
||||||
_ = f.Close()
|
return err
|
||||||
|
}
|
||||||
|
for _, key := range keys {
|
||||||
|
if _, err := f.WriteString(key.AuthorizedString()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
_ = f.Close()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
_ = f.Close()
|
||||||
|
|
||||||
if com.IsExist(fpath) {
|
if com.IsExist(fpath) {
|
||||||
if err = os.Remove(fpath); err != nil {
|
if err = os.Remove(fpath); err != nil {
|
||||||
@@ -562,37 +562,40 @@ func RewriteAuthorizedKeys() error {
|
|||||||
// DeployKey represents deploy key information and its relation with repository.
|
// DeployKey represents deploy key information and its relation with repository.
|
||||||
type DeployKey struct {
|
type DeployKey struct {
|
||||||
ID int64
|
ID int64
|
||||||
KeyID int64 `xorm:"UNIQUE(s) INDEX"`
|
KeyID int64 `gorm:"uniqueIndex:s;index"`
|
||||||
RepoID int64 `xorm:"UNIQUE(s) INDEX"`
|
RepoID int64 `gorm:"uniqueIndex:s;index"`
|
||||||
Name string
|
Name string
|
||||||
Fingerprint string
|
Fingerprint string
|
||||||
Content string `xorm:"-" json:"-" gorm:"-"`
|
Content string `gorm:"-" json:"-"`
|
||||||
|
|
||||||
Created time.Time `xorm:"-" json:"-" gorm:"-"`
|
Created time.Time `gorm:"-" json:"-"`
|
||||||
CreatedUnix int64
|
CreatedUnix int64
|
||||||
Updated time.Time `xorm:"-" json:"-" gorm:"-"` // Note: Updated must below Created for AfterSet.
|
Updated time.Time `gorm:"-" json:"-"` // Note: Updated must below Created for AfterFind.
|
||||||
UpdatedUnix int64
|
UpdatedUnix int64
|
||||||
HasRecentActivity bool `xorm:"-" json:"-" gorm:"-"`
|
HasRecentActivity bool `gorm:"-" json:"-"`
|
||||||
HasUsed bool `xorm:"-" json:"-" gorm:"-"`
|
HasUsed bool `gorm:"-" json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *DeployKey) BeforeInsert() {
|
func (k *DeployKey) BeforeCreate(tx *gorm.DB) error {
|
||||||
k.CreatedUnix = time.Now().Unix()
|
if k.CreatedUnix == 0 {
|
||||||
|
k.CreatedUnix = tx.NowFunc().Unix()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *DeployKey) BeforeUpdate() {
|
func (k *DeployKey) BeforeUpdate(tx *gorm.DB) error {
|
||||||
k.UpdatedUnix = time.Now().Unix()
|
k.UpdatedUnix = tx.NowFunc().Unix()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *DeployKey) AfterSet(colName string, _ xorm.Cell) {
|
func (k *DeployKey) AfterFind(tx *gorm.DB) error {
|
||||||
switch colName {
|
k.Created = time.Unix(k.CreatedUnix, 0).Local()
|
||||||
case "created_unix":
|
if k.UpdatedUnix > 0 {
|
||||||
k.Created = time.Unix(k.CreatedUnix, 0).Local()
|
|
||||||
case "updated_unix":
|
|
||||||
k.Updated = time.Unix(k.UpdatedUnix, 0).Local()
|
k.Updated = time.Unix(k.UpdatedUnix, 0).Local()
|
||||||
k.HasUsed = k.Updated.After(k.Created)
|
k.HasUsed = k.Updated.After(k.Created)
|
||||||
k.HasRecentActivity = k.Updated.Add(7 * 24 * time.Hour).After(time.Now())
|
k.HasRecentActivity = k.Updated.Add(7 * 24 * time.Hour).After(tx.NowFunc())
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetContent gets associated public key content.
|
// GetContent gets associated public key content.
|
||||||
@@ -605,28 +608,28 @@ func (k *DeployKey) GetContent() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkDeployKey(e Engine, keyID, repoID int64, name string) error {
|
func checkDeployKey(tx *gorm.DB, keyID, repoID int64, name string) error {
|
||||||
// Note: We want error detail, not just true or false here.
|
// Note: We want error detail, not just true or false here.
|
||||||
has, err := e.Where("key_id = ? AND repo_id = ?", keyID, repoID).Get(new(DeployKey))
|
err := tx.Where("key_id = ? AND repo_id = ?", keyID, repoID).First(new(DeployKey)).Error
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return err
|
|
||||||
} else if has {
|
|
||||||
return ErrDeployKeyAlreadyExist{keyID, repoID}
|
return ErrDeployKeyAlreadyExist{keyID, repoID}
|
||||||
|
} else if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
has, err = e.Where("repo_id = ? AND name = ?", repoID, name).Get(new(DeployKey))
|
err = tx.Where("repo_id = ? AND name = ?", repoID, name).First(new(DeployKey)).Error
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return err
|
|
||||||
} else if has {
|
|
||||||
return ErrDeployKeyNameAlreadyUsed{repoID, name}
|
return ErrDeployKeyNameAlreadyUsed{repoID, name}
|
||||||
|
} else if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// addDeployKey adds new key-repo relation.
|
// addDeployKey adds new key-repo relation.
|
||||||
func addDeployKey(e *xorm.Session, keyID, repoID int64, name, fingerprint string) (*DeployKey, error) {
|
func addDeployKey(tx *gorm.DB, keyID, repoID int64, name, fingerprint string) (*DeployKey, error) {
|
||||||
if err := checkDeployKey(e, keyID, repoID, name); err != nil {
|
if err := checkDeployKey(tx, keyID, repoID, name); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -636,14 +639,14 @@ func addDeployKey(e *xorm.Session, keyID, repoID int64, name, fingerprint string
|
|||||||
Name: name,
|
Name: name,
|
||||||
Fingerprint: fingerprint,
|
Fingerprint: fingerprint,
|
||||||
}
|
}
|
||||||
_, err := e.Insert(key)
|
err := tx.Create(key).Error
|
||||||
return key, err
|
return key, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasDeployKey returns true if public key is a deploy key of given repository.
|
// HasDeployKey returns true if public key is a deploy key of given repository.
|
||||||
func HasDeployKey(keyID, repoID int64) bool {
|
func HasDeployKey(keyID, repoID int64) bool {
|
||||||
has, _ := x.Where("key_id = ? AND repo_id = ?", keyID, repoID).Get(new(DeployKey))
|
err := db.Where("key_id = ? AND repo_id = ?", keyID, repoID).First(new(DeployKey)).Error
|
||||||
return has
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddDeployKey add new deploy key to database and authorized_keys file.
|
// AddDeployKey add new deploy key to database and authorized_keys file.
|
||||||
@@ -657,30 +660,34 @@ func AddDeployKey(repoID int64, name, content string) (*DeployKey, error) {
|
|||||||
Mode: AccessModeRead,
|
Mode: AccessModeRead,
|
||||||
Type: KeyTypeDeploy,
|
Type: KeyTypeDeploy,
|
||||||
}
|
}
|
||||||
has, err := x.Get(pkey)
|
err := db.Where("content = ? AND mode = ? AND type = ?", content, AccessModeRead, KeyTypeDeploy).First(pkey).Error
|
||||||
if err != nil {
|
has := err == nil
|
||||||
|
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
var key *DeployKey
|
||||||
defer sess.Close()
|
err = db.Transaction(func(tx *gorm.DB) error {
|
||||||
if err = sess.Begin(); err != nil {
|
// First time use this deploy key.
|
||||||
return nil, err
|
if !has {
|
||||||
}
|
if err := addKey(tx, pkey); err != nil {
|
||||||
|
return errors.Newf("addKey: %v", err)
|
||||||
// First time use this deploy key.
|
}
|
||||||
if !has {
|
|
||||||
if err = addKey(sess, pkey); err != nil {
|
|
||||||
return nil, errors.Newf("addKey: %v", err)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
key, err := addDeployKey(sess, pkey.ID, repoID, name, pkey.Fingerprint)
|
var err error
|
||||||
|
key, err = addDeployKey(tx, pkey.ID, repoID, name, pkey.Fingerprint)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Newf("addDeployKey: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Newf("addDeployKey: %v", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return key, sess.Commit()
|
return key, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ errutil.NotFound = (*ErrDeployKeyNotExist)(nil)
|
var _ errutil.NotFound = (*ErrDeployKeyNotExist)(nil)
|
||||||
@@ -705,11 +712,12 @@ func (ErrDeployKeyNotExist) NotFound() bool {
|
|||||||
// GetDeployKeyByID returns deploy key by given ID.
|
// GetDeployKeyByID returns deploy key by given ID.
|
||||||
func GetDeployKeyByID(id int64) (*DeployKey, error) {
|
func GetDeployKeyByID(id int64) (*DeployKey, error) {
|
||||||
key := new(DeployKey)
|
key := new(DeployKey)
|
||||||
has, err := x.Id(id).Get(key)
|
err := db.Where("id = ?", id).First(key).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, ErrDeployKeyNotExist{args: map[string]any{"deployKeyID": id}}
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
|
||||||
return nil, ErrDeployKeyNotExist{args: map[string]any{"deployKeyID": id}}
|
|
||||||
}
|
}
|
||||||
return key, nil
|
return key, nil
|
||||||
}
|
}
|
||||||
@@ -720,19 +728,19 @@ func GetDeployKeyByRepo(keyID, repoID int64) (*DeployKey, error) {
|
|||||||
KeyID: keyID,
|
KeyID: keyID,
|
||||||
RepoID: repoID,
|
RepoID: repoID,
|
||||||
}
|
}
|
||||||
has, err := x.Get(key)
|
err := db.Where("key_id = ? AND repo_id = ?", keyID, repoID).First(key).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, ErrDeployKeyNotExist{args: map[string]any{"keyID": keyID, "repoID": repoID}}
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
|
||||||
return nil, ErrDeployKeyNotExist{args: map[string]any{"keyID": keyID, "repoID": repoID}}
|
|
||||||
}
|
}
|
||||||
return key, nil
|
return key, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateDeployKey updates deploy key information.
|
// UpdateDeployKey updates deploy key information.
|
||||||
func UpdateDeployKey(key *DeployKey) error {
|
func UpdateDeployKey(key *DeployKey) error {
|
||||||
_, err := x.Id(key.ID).AllCols().Update(key)
|
return db.Model(key).Where("id = ?", key.ID).Updates(key).Error
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteDeployKey deletes deploy key from its repository authorized_keys file if needed.
|
// DeleteDeployKey deletes deploy key from its repository authorized_keys file if needed.
|
||||||
@@ -761,31 +769,27 @@ func DeleteDeployKey(doer *User, id int64) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
if err := tx.Where("id = ?", key.ID).Delete(new(DeployKey)).Error; err != nil {
|
||||||
if err = sess.Begin(); err != nil {
|
return errors.Newf("delete deploy key [%d]: %v", key.ID, err)
|
||||||
return err
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = sess.ID(key.ID).Delete(new(DeployKey)); err != nil {
|
// Check if this is the last reference to same key content.
|
||||||
return errors.Newf("delete deploy key [%d]: %v", key.ID, err)
|
err := tx.Where("key_id = ?", key.KeyID).First(new(DeployKey)).Error
|
||||||
}
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
if err = deletePublicKeys(tx, key.KeyID); err != nil {
|
||||||
// Check if this is the last reference to same key content.
|
return err
|
||||||
has, err := sess.Where("key_id = ?", key.KeyID).Get(new(DeployKey))
|
}
|
||||||
if err != nil {
|
} else if err != nil {
|
||||||
return err
|
|
||||||
} else if !has {
|
|
||||||
if err = deletePublicKeys(sess, key.KeyID); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return sess.Commit()
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListDeployKeys returns all deploy keys by given repository ID.
|
// ListDeployKeys returns all deploy keys by given repository ID.
|
||||||
func ListDeployKeys(repoID int64) ([]*DeployKey, error) {
|
func ListDeployKeys(repoID int64) ([]*DeployKey, error) {
|
||||||
keys := make([]*DeployKey, 0, 5)
|
keys := make([]*DeployKey, 0, 5)
|
||||||
return keys, x.Where("repo_id = ?", repoID).Find(&keys)
|
return keys, db.Where("repo_id = ?", repoID).Find(&keys).Error
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/cockroachdb/errors"
|
"github.com/cockroachdb/errors"
|
||||||
"github.com/pquerna/otp/totp"
|
"github.com/pquerna/otp/totp"
|
||||||
"github.com/unknwon/com"
|
"github.com/unknwon/com"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
"gogs.io/gogs/internal/conf"
|
"gogs.io/gogs/internal/conf"
|
||||||
"gogs.io/gogs/internal/cryptoutil"
|
"gogs.io/gogs/internal/cryptoutil"
|
||||||
@@ -37,20 +38,16 @@ func (t *TwoFactor) ValidateTOTP(passcode string) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DeleteTwoFactor removes two-factor authentication token and recovery codes of given user.
|
// DeleteTwoFactor removes two-factor authentication token and recovery codes of given user.
|
||||||
func DeleteTwoFactor(userID int64) (err error) {
|
func DeleteTwoFactor(userID int64) error {
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
if err := tx.Where("user_id = ?", userID).Delete(new(TwoFactor)).Error; err != nil {
|
||||||
if err = sess.Begin(); err != nil {
|
return errors.Newf("delete two-factor: %v", err)
|
||||||
return err
|
}
|
||||||
}
|
if err := deleteRecoveryCodesByUserID(tx, userID); err != nil {
|
||||||
|
return errors.Newf("deleteRecoveryCodesByUserID: %v", err)
|
||||||
if _, err = sess.Where("user_id = ?", userID).Delete(new(TwoFactor)); err != nil {
|
}
|
||||||
return errors.Newf("delete two-factor: %v", err)
|
return nil
|
||||||
} else if err = deleteRecoveryCodesByUserID(sess, userID); err != nil {
|
})
|
||||||
return errors.Newf("deleteRecoveryCodesByUserID: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return sess.Commit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TwoFactorRecoveryCode represents a two-factor authentication recovery code.
|
// TwoFactorRecoveryCode represents a two-factor authentication recovery code.
|
||||||
@@ -64,12 +61,11 @@ type TwoFactorRecoveryCode struct {
|
|||||||
// GetRecoveryCodesByUserID returns all recovery codes of given user.
|
// GetRecoveryCodesByUserID returns all recovery codes of given user.
|
||||||
func GetRecoveryCodesByUserID(userID int64) ([]*TwoFactorRecoveryCode, error) {
|
func GetRecoveryCodesByUserID(userID int64) ([]*TwoFactorRecoveryCode, error) {
|
||||||
recoveryCodes := make([]*TwoFactorRecoveryCode, 0, 10)
|
recoveryCodes := make([]*TwoFactorRecoveryCode, 0, 10)
|
||||||
return recoveryCodes, x.Where("user_id = ?", userID).Find(&recoveryCodes)
|
return recoveryCodes, db.Where("user_id = ?", userID).Find(&recoveryCodes).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteRecoveryCodesByUserID(e Engine, userID int64) error {
|
func deleteRecoveryCodesByUserID(e *gorm.DB, userID int64) error {
|
||||||
_, err := e.Where("user_id = ?", userID).Delete(new(TwoFactorRecoveryCode))
|
return e.Where("user_id = ?", userID).Delete(&TwoFactorRecoveryCode{}).Error
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegenerateRecoveryCodes regenerates new set of recovery codes for given user.
|
// RegenerateRecoveryCodes regenerates new set of recovery codes for given user.
|
||||||
@@ -79,19 +75,15 @@ func RegenerateRecoveryCodes(userID int64) error {
|
|||||||
return errors.Newf("generateRecoveryCodes: %v", err)
|
return errors.Newf("generateRecoveryCodes: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
if err := deleteRecoveryCodesByUserID(tx, userID); err != nil {
|
||||||
if err = sess.Begin(); err != nil {
|
return errors.Newf("deleteRecoveryCodesByUserID: %v", err)
|
||||||
return err
|
}
|
||||||
}
|
if err := tx.Create(recoveryCodes).Error; err != nil {
|
||||||
|
return errors.Newf("insert new recovery codes: %v", err)
|
||||||
if err = deleteRecoveryCodesByUserID(sess, userID); err != nil {
|
}
|
||||||
return errors.Newf("deleteRecoveryCodesByUserID: %v", err)
|
return nil
|
||||||
} else if _, err = sess.Insert(recoveryCodes); err != nil {
|
})
|
||||||
return errors.Newf("insert new recovery codes: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return sess.Commit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ErrTwoFactorRecoveryCodeNotFound struct {
|
type ErrTwoFactorRecoveryCodeNotFound struct {
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ import (
|
|||||||
"github.com/cockroachdb/errors"
|
"github.com/cockroachdb/errors"
|
||||||
jsoniter "github.com/json-iterator/go"
|
jsoniter "github.com/json-iterator/go"
|
||||||
gouuid "github.com/satori/go.uuid"
|
gouuid "github.com/satori/go.uuid"
|
||||||
|
"gorm.io/gorm"
|
||||||
log "unknwon.dev/clog/v2"
|
log "unknwon.dev/clog/v2"
|
||||||
"xorm.io/xorm"
|
|
||||||
|
|
||||||
api "github.com/gogs/go-gogs-client"
|
api "github.com/gogs/go-gogs-client"
|
||||||
|
|
||||||
@@ -95,45 +95,42 @@ type Webhook struct {
|
|||||||
ID int64
|
ID int64
|
||||||
RepoID int64
|
RepoID int64
|
||||||
OrgID int64
|
OrgID int64
|
||||||
URL string `xorm:"url TEXT"`
|
URL string `gorm:"type:text;column:url"`
|
||||||
ContentType HookContentType
|
ContentType HookContentType
|
||||||
Secret string `xorm:"TEXT"`
|
Secret string `gorm:"type:text"`
|
||||||
Events string `xorm:"TEXT"`
|
Events string `gorm:"type:text"`
|
||||||
*HookEvent `xorm:"-"` // LEGACY [1.0]: Cannot ignore JSON (i.e. json:"-") here, it breaks old backup archive
|
*HookEvent `gorm:"-"` // LEGACY [1.0]: Cannot ignore JSON (i.e. json:"-") here, it breaks old backup archive
|
||||||
IsSSL bool `xorm:"is_ssl"`
|
IsSSL bool `gorm:"column:is_ssl"`
|
||||||
IsActive bool
|
IsActive bool
|
||||||
HookTaskType HookTaskType
|
HookTaskType HookTaskType
|
||||||
Meta string `xorm:"TEXT"` // store hook-specific attributes
|
Meta string `gorm:"type:text"` // store hook-specific attributes
|
||||||
LastStatus HookStatus // Last delivery status
|
LastStatus HookStatus // Last delivery status
|
||||||
|
|
||||||
Created time.Time `xorm:"-" json:"-" gorm:"-"`
|
Created time.Time `gorm:"-" json:"-"`
|
||||||
CreatedUnix int64
|
CreatedUnix int64
|
||||||
Updated time.Time `xorm:"-" json:"-" gorm:"-"`
|
Updated time.Time `gorm:"-" json:"-"`
|
||||||
UpdatedUnix int64
|
UpdatedUnix int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Webhook) BeforeInsert() {
|
func (w *Webhook) BeforeCreate(tx *gorm.DB) error {
|
||||||
w.CreatedUnix = time.Now().Unix()
|
w.CreatedUnix = tx.NowFunc().Unix()
|
||||||
w.UpdatedUnix = w.CreatedUnix
|
w.UpdatedUnix = w.CreatedUnix
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Webhook) BeforeUpdate() {
|
func (w *Webhook) BeforeUpdate(tx *gorm.DB) error {
|
||||||
w.UpdatedUnix = time.Now().Unix()
|
w.UpdatedUnix = tx.NowFunc().Unix()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Webhook) AfterSet(colName string, _ xorm.Cell) {
|
func (w *Webhook) AfterFind(tx *gorm.DB) error {
|
||||||
var err error
|
w.HookEvent = &HookEvent{}
|
||||||
switch colName {
|
if err := jsoniter.Unmarshal([]byte(w.Events), w.HookEvent); err != nil {
|
||||||
case "events":
|
log.Error("Unmarshal [%d]: %v", w.ID, err)
|
||||||
w.HookEvent = &HookEvent{}
|
|
||||||
if err = jsoniter.Unmarshal([]byte(w.Events), w.HookEvent); err != nil {
|
|
||||||
log.Error("Unmarshal [%d]: %v", w.ID, err)
|
|
||||||
}
|
|
||||||
case "created_unix":
|
|
||||||
w.Created = time.Unix(w.CreatedUnix, 0).Local()
|
|
||||||
case "updated_unix":
|
|
||||||
w.Updated = time.Unix(w.UpdatedUnix, 0).Local()
|
|
||||||
}
|
}
|
||||||
|
w.Created = time.Unix(w.CreatedUnix, 0).Local()
|
||||||
|
w.Updated = time.Unix(w.UpdatedUnix, 0).Local()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Webhook) SlackMeta() *SlackMeta {
|
func (w *Webhook) SlackMeta() *SlackMeta {
|
||||||
@@ -231,8 +228,7 @@ func (w *Webhook) EventsArray() []string {
|
|||||||
|
|
||||||
// CreateWebhook creates a new web hook.
|
// CreateWebhook creates a new web hook.
|
||||||
func CreateWebhook(w *Webhook) error {
|
func CreateWebhook(w *Webhook) error {
|
||||||
_, err := x.Insert(w)
|
return db.Create(w).Error
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ errutil.NotFound = (*ErrWebhookNotExist)(nil)
|
var _ errutil.NotFound = (*ErrWebhookNotExist)(nil)
|
||||||
@@ -257,11 +253,12 @@ func (ErrWebhookNotExist) NotFound() bool {
|
|||||||
// getWebhook uses argument bean as query condition,
|
// getWebhook uses argument bean as query condition,
|
||||||
// ID must be specified and do not assign unnecessary fields.
|
// ID must be specified and do not assign unnecessary fields.
|
||||||
func getWebhook(bean *Webhook) (*Webhook, error) {
|
func getWebhook(bean *Webhook) (*Webhook, error) {
|
||||||
has, err := x.Get(bean)
|
err := db.Where(bean).First(bean).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, ErrWebhookNotExist{args: map[string]any{"webhookID": bean.ID}}
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
|
||||||
return nil, ErrWebhookNotExist{args: map[string]any{"webhookID": bean.ID}}
|
|
||||||
}
|
}
|
||||||
return bean, nil
|
return bean, nil
|
||||||
}
|
}
|
||||||
@@ -292,39 +289,34 @@ func GetWebhookByOrgID(orgID, id int64) (*Webhook, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getActiveWebhooksByRepoID returns all active webhooks of repository.
|
// getActiveWebhooksByRepoID returns all active webhooks of repository.
|
||||||
func getActiveWebhooksByRepoID(e Engine, repoID int64) ([]*Webhook, error) {
|
func getActiveWebhooksByRepoID(tx *gorm.DB, repoID int64) ([]*Webhook, error) {
|
||||||
webhooks := make([]*Webhook, 0, 5)
|
webhooks := make([]*Webhook, 0, 5)
|
||||||
return webhooks, e.Where("repo_id = ?", repoID).And("is_active = ?", true).Find(&webhooks)
|
return webhooks, tx.Where("repo_id = ? AND is_active = ?", repoID, true).Find(&webhooks).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetWebhooksByRepoID returns all webhooks of a repository.
|
// GetWebhooksByRepoID returns all webhooks of a repository.
|
||||||
func GetWebhooksByRepoID(repoID int64) ([]*Webhook, error) {
|
func GetWebhooksByRepoID(repoID int64) ([]*Webhook, error) {
|
||||||
webhooks := make([]*Webhook, 0, 5)
|
webhooks := make([]*Webhook, 0, 5)
|
||||||
return webhooks, x.Find(&webhooks, &Webhook{RepoID: repoID})
|
return webhooks, db.Where("repo_id = ?", repoID).Find(&webhooks).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateWebhook updates information of webhook.
|
// UpdateWebhook updates information of webhook.
|
||||||
func UpdateWebhook(w *Webhook) error {
|
func UpdateWebhook(w *Webhook) error {
|
||||||
_, err := x.Id(w.ID).AllCols().Update(w)
|
return db.Model(w).Where("id = ?", w.ID).Updates(w).Error
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// deleteWebhook uses argument bean as query condition,
|
// deleteWebhook uses argument bean as query condition,
|
||||||
// ID must be specified and do not assign unnecessary fields.
|
// ID must be specified and do not assign unnecessary fields.
|
||||||
func deleteWebhook(bean *Webhook) (err error) {
|
func deleteWebhook(bean *Webhook) error {
|
||||||
sess := x.NewSession()
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
defer sess.Close()
|
if err := tx.Delete(bean).Error; err != nil {
|
||||||
if err = sess.Begin(); err != nil {
|
return err
|
||||||
return err
|
}
|
||||||
}
|
if err := tx.Where("hook_id = ?", bean.ID).Delete(&HookTask{}).Error; err != nil {
|
||||||
|
return err
|
||||||
if _, err = sess.Delete(bean); err != nil {
|
}
|
||||||
return err
|
return nil
|
||||||
} else if _, err = sess.Delete(&HookTask{HookID: bean.ID}); err != nil {
|
})
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return sess.Commit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteWebhookOfRepoByID deletes webhook of repository by given ID.
|
// DeleteWebhookOfRepoByID deletes webhook of repository by given ID.
|
||||||
@@ -345,14 +337,14 @@ func DeleteWebhookOfOrgByID(orgID, id int64) error {
|
|||||||
|
|
||||||
// GetWebhooksByOrgID returns all webhooks for an organization.
|
// GetWebhooksByOrgID returns all webhooks for an organization.
|
||||||
func GetWebhooksByOrgID(orgID int64) (ws []*Webhook, err error) {
|
func GetWebhooksByOrgID(orgID int64) (ws []*Webhook, err error) {
|
||||||
err = x.Find(&ws, &Webhook{OrgID: orgID})
|
err = db.Where("org_id = ?", orgID).Find(&ws).Error
|
||||||
return ws, err
|
return ws, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// getActiveWebhooksByOrgID returns all active webhooks for an organization.
|
// getActiveWebhooksByOrgID returns all active webhooks for an organization.
|
||||||
func getActiveWebhooksByOrgID(e Engine, orgID int64) ([]*Webhook, error) {
|
func getActiveWebhooksByOrgID(tx *gorm.DB, orgID int64) ([]*Webhook, error) {
|
||||||
ws := make([]*Webhook, 0, 3)
|
ws := make([]*Webhook, 0, 3)
|
||||||
return ws, e.Where("org_id=?", orgID).And("is_active=?", true).Find(&ws)
|
return ws, tx.Where("org_id = ? AND is_active = ?", orgID, true).Find(&ws).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// ___ ___ __ ___________ __
|
// ___ ___ __ ___________ __
|
||||||
@@ -431,64 +423,56 @@ type HookResponse struct {
|
|||||||
// HookTask represents a hook task.
|
// HookTask represents a hook task.
|
||||||
type HookTask struct {
|
type HookTask struct {
|
||||||
ID int64
|
ID int64
|
||||||
RepoID int64 `xorm:"INDEX"`
|
RepoID int64 `gorm:"index"`
|
||||||
HookID int64
|
HookID int64
|
||||||
UUID string
|
UUID string
|
||||||
Type HookTaskType
|
Type HookTaskType
|
||||||
URL string `xorm:"TEXT"`
|
URL string `gorm:"type:text"`
|
||||||
Signature string `xorm:"TEXT"`
|
Signature string `gorm:"type:text"`
|
||||||
api.Payloader `xorm:"-" json:"-" gorm:"-"`
|
api.Payloader `gorm:"-" json:"-"`
|
||||||
PayloadContent string `xorm:"TEXT"`
|
PayloadContent string `gorm:"type:text"`
|
||||||
ContentType HookContentType
|
ContentType HookContentType
|
||||||
EventType HookEventType
|
EventType HookEventType
|
||||||
IsSSL bool
|
IsSSL bool
|
||||||
IsDelivered bool
|
IsDelivered bool
|
||||||
Delivered int64
|
Delivered int64
|
||||||
DeliveredString string `xorm:"-" json:"-" gorm:"-"`
|
DeliveredString string `gorm:"-" json:"-"`
|
||||||
|
|
||||||
// History info.
|
// History info.
|
||||||
IsSucceed bool
|
IsSucceed bool
|
||||||
RequestContent string `xorm:"TEXT"`
|
RequestContent string `gorm:"type:text"`
|
||||||
RequestInfo *HookRequest `xorm:"-" json:"-" gorm:"-"`
|
RequestInfo *HookRequest `gorm:"-" json:"-"`
|
||||||
ResponseContent string `xorm:"TEXT"`
|
ResponseContent string `gorm:"type:text"`
|
||||||
ResponseInfo *HookResponse `xorm:"-" json:"-" gorm:"-"`
|
ResponseInfo *HookResponse `gorm:"-" json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *HookTask) BeforeUpdate() {
|
func (t *HookTask) BeforeUpdate(tx *gorm.DB) error {
|
||||||
if t.RequestInfo != nil {
|
if t.RequestInfo != nil {
|
||||||
t.RequestContent = t.ToJSON(t.RequestInfo)
|
t.RequestContent = t.ToJSON(t.RequestInfo)
|
||||||
}
|
}
|
||||||
if t.ResponseInfo != nil {
|
if t.ResponseInfo != nil {
|
||||||
t.ResponseContent = t.ToJSON(t.ResponseInfo)
|
t.ResponseContent = t.ToJSON(t.ResponseInfo)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *HookTask) AfterSet(colName string, _ xorm.Cell) {
|
func (t *HookTask) AfterFind(tx *gorm.DB) error {
|
||||||
var err error
|
t.DeliveredString = time.Unix(0, t.Delivered).Format("2006-01-02 15:04:05 MST")
|
||||||
switch colName {
|
|
||||||
case "delivered":
|
|
||||||
t.DeliveredString = time.Unix(0, t.Delivered).Format("2006-01-02 15:04:05 MST")
|
|
||||||
|
|
||||||
case "request_content":
|
|
||||||
if t.RequestContent == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if t.RequestContent != "" {
|
||||||
t.RequestInfo = &HookRequest{}
|
t.RequestInfo = &HookRequest{}
|
||||||
if err = jsoniter.Unmarshal([]byte(t.RequestContent), t.RequestInfo); err != nil {
|
if err := jsoniter.Unmarshal([]byte(t.RequestContent), t.RequestInfo); err != nil {
|
||||||
log.Error("Unmarshal[%d]: %v", t.ID, err)
|
log.Error("Unmarshal[%d]: %v", t.ID, err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case "response_content":
|
if t.ResponseContent != "" {
|
||||||
if t.ResponseContent == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
t.ResponseInfo = &HookResponse{}
|
t.ResponseInfo = &HookResponse{}
|
||||||
if err = jsoniter.Unmarshal([]byte(t.ResponseContent), t.ResponseInfo); err != nil {
|
if err := jsoniter.Unmarshal([]byte(t.ResponseContent), t.ResponseInfo); err != nil {
|
||||||
log.Error("Unmarshal [%d]: %v", t.ID, err)
|
log.Error("Unmarshal [%d]: %v", t.ID, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *HookTask) ToJSON(v any) string {
|
func (t *HookTask) ToJSON(v any) string {
|
||||||
@@ -502,20 +486,19 @@ func (t *HookTask) ToJSON(v any) string {
|
|||||||
// HookTasks returns a list of hook tasks by given conditions.
|
// HookTasks returns a list of hook tasks by given conditions.
|
||||||
func HookTasks(hookID int64, page int) ([]*HookTask, error) {
|
func HookTasks(hookID int64, page int) ([]*HookTask, error) {
|
||||||
tasks := make([]*HookTask, 0, conf.Webhook.PagingNum)
|
tasks := make([]*HookTask, 0, conf.Webhook.PagingNum)
|
||||||
return tasks, x.Limit(conf.Webhook.PagingNum, (page-1)*conf.Webhook.PagingNum).Where("hook_id=?", hookID).Desc("id").Find(&tasks)
|
return tasks, db.Where("hook_id = ?", hookID).Order("id DESC").Limit(conf.Webhook.PagingNum).Offset((page - 1) * conf.Webhook.PagingNum).Find(&tasks).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// createHookTask creates a new hook task,
|
// createHookTask creates a new hook task,
|
||||||
// it handles conversion from Payload to PayloadContent.
|
// it handles conversion from Payload to PayloadContent.
|
||||||
func createHookTask(e Engine, t *HookTask) error {
|
func createHookTask(tx *gorm.DB, t *HookTask) error {
|
||||||
data, err := t.JSONPayload()
|
data, err := t.JSONPayload()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
t.UUID = gouuid.NewV4().String()
|
t.UUID = gouuid.NewV4().String()
|
||||||
t.PayloadContent = string(data)
|
t.PayloadContent = string(data)
|
||||||
_, err = e.Insert(t)
|
return tx.Create(t).Error
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ errutil.NotFound = (*ErrHookTaskNotExist)(nil)
|
var _ errutil.NotFound = (*ErrHookTaskNotExist)(nil)
|
||||||
@@ -543,23 +526,23 @@ func GetHookTaskOfWebhookByUUID(webhookID int64, uuid string) (*HookTask, error)
|
|||||||
HookID: webhookID,
|
HookID: webhookID,
|
||||||
UUID: uuid,
|
UUID: uuid,
|
||||||
}
|
}
|
||||||
has, err := x.Get(hookTask)
|
err := db.Where("hook_id = ? AND uuid = ?", webhookID, uuid).First(hookTask).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, ErrHookTaskNotExist{args: map[string]any{"webhookID": webhookID, "uuid": uuid}}
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
|
||||||
return nil, ErrHookTaskNotExist{args: map[string]any{"webhookID": webhookID, "uuid": uuid}}
|
|
||||||
}
|
}
|
||||||
return hookTask, nil
|
return hookTask, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateHookTask updates information of hook task.
|
// UpdateHookTask updates information of hook task.
|
||||||
func UpdateHookTask(t *HookTask) error {
|
func UpdateHookTask(t *HookTask) error {
|
||||||
_, err := x.Id(t.ID).AllCols().Update(t)
|
return db.Model(t).Where("id = ?", t.ID).Updates(t).Error
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepareHookTasks adds list of webhooks to task queue.
|
// prepareHookTasks adds list of webhooks to task queue.
|
||||||
func prepareHookTasks(e Engine, repo *Repository, event HookEventType, p api.Payloader, webhooks []*Webhook) (err error) {
|
func prepareHookTasks(tx *gorm.DB, repo *Repository, event HookEventType, p api.Payloader, webhooks []*Webhook) (err error) {
|
||||||
if len(webhooks) == 0 {
|
if len(webhooks) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -633,7 +616,7 @@ func prepareHookTasks(e Engine, repo *Repository, event HookEventType, p api.Pay
|
|||||||
signature = hex.EncodeToString(sig.Sum(nil))
|
signature = hex.EncodeToString(sig.Sum(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = createHookTask(e, &HookTask{
|
if err = createHookTask(tx, &HookTask{
|
||||||
RepoID: repo.ID,
|
RepoID: repo.ID,
|
||||||
HookID: w.ID,
|
HookID: w.ID,
|
||||||
Type: w.HookTaskType,
|
Type: w.HookTaskType,
|
||||||
@@ -655,32 +638,32 @@ func prepareHookTasks(e Engine, repo *Repository, event HookEventType, p api.Pay
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareWebhooks(e Engine, repo *Repository, event HookEventType, p api.Payloader) error {
|
func prepareWebhooks(tx *gorm.DB, repo *Repository, event HookEventType, p api.Payloader) error {
|
||||||
webhooks, err := getActiveWebhooksByRepoID(e, repo.ID)
|
webhooks, err := getActiveWebhooksByRepoID(tx, repo.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Newf("getActiveWebhooksByRepoID [%d]: %v", repo.ID, err)
|
return errors.Newf("getActiveWebhooksByRepoID [%d]: %v", repo.ID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if repo belongs to org and append additional webhooks
|
// check if repo belongs to org and append additional webhooks
|
||||||
if repo.mustOwner(e).IsOrganization() {
|
if repo.mustOwner(tx).IsOrganization() {
|
||||||
// get hooks for org
|
// get hooks for org
|
||||||
orgws, err := getActiveWebhooksByOrgID(e, repo.OwnerID)
|
orgws, err := getActiveWebhooksByOrgID(tx, repo.OwnerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Newf("getActiveWebhooksByOrgID [%d]: %v", repo.OwnerID, err)
|
return errors.Newf("getActiveWebhooksByOrgID [%d]: %v", repo.OwnerID, err)
|
||||||
}
|
}
|
||||||
webhooks = append(webhooks, orgws...)
|
webhooks = append(webhooks, orgws...)
|
||||||
}
|
}
|
||||||
return prepareHookTasks(e, repo, event, p, webhooks)
|
return prepareHookTasks(tx, repo, event, p, webhooks)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrepareWebhooks adds all active webhooks to task queue.
|
// PrepareWebhooks adds all active webhooks to task queue.
|
||||||
func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) error {
|
func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) error {
|
||||||
// NOTE: To prevent too many cascading changes in a single refactoring PR, we
|
// NOTE: To prevent too many cascading changes in a single refactoring PR, we
|
||||||
// choose to ignore this function in tests.
|
// choose to ignore this function in tests.
|
||||||
if x == nil && testutil.InTest {
|
if db == nil && testutil.InTest {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return prepareWebhooks(x, repo, event, p)
|
return prepareWebhooks(db, repo, event, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestWebhook adds the test webhook matches the ID to task queue.
|
// TestWebhook adds the test webhook matches the ID to task queue.
|
||||||
@@ -689,7 +672,7 @@ func TestWebhook(repo *Repository, event HookEventType, p api.Payloader, webhook
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Newf("GetWebhookOfRepoByID [repo_id: %d, id: %d]: %v", repo.ID, webhookID, err)
|
return errors.Newf("GetWebhookOfRepoByID [repo_id: %d, id: %d]: %v", repo.ID, webhookID, err)
|
||||||
}
|
}
|
||||||
return prepareHookTasks(x, repo, event, p, []*Webhook{webhook})
|
return prepareHookTasks(db, repo, event, p, []*Webhook{webhook})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *HookTask) deliver() {
|
func (t *HookTask) deliver() {
|
||||||
@@ -784,18 +767,15 @@ func (t *HookTask) deliver() {
|
|||||||
// TODO: shoot more hooks at same time.
|
// TODO: shoot more hooks at same time.
|
||||||
func DeliverHooks() {
|
func DeliverHooks() {
|
||||||
tasks := make([]*HookTask, 0, 10)
|
tasks := make([]*HookTask, 0, 10)
|
||||||
_ = x.Where("is_delivered = ?", false).Iterate(new(HookTask),
|
err := db.Where("is_delivered = ?", false).Find(&tasks).Error
|
||||||
func(idx int, bean any) error {
|
if err != nil {
|
||||||
t := bean.(*HookTask)
|
log.Error("Find undelivered hook tasks: %v", err)
|
||||||
|
} else {
|
||||||
|
for _, t := range tasks {
|
||||||
t.deliver()
|
t.deliver()
|
||||||
tasks = append(tasks, t)
|
if err := UpdateHookTask(t); err != nil {
|
||||||
return nil
|
log.Error("UpdateHookTask [%d]: %v", t.ID, err)
|
||||||
})
|
}
|
||||||
|
|
||||||
// Update hook task status.
|
|
||||||
for _, t := range tasks {
|
|
||||||
if err := UpdateHookTask(t); err != nil {
|
|
||||||
log.Error("UpdateHookTask [%d]: %v", t.ID, err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -805,7 +785,7 @@ func DeliverHooks() {
|
|||||||
HookQueue.Remove(repoID)
|
HookQueue.Remove(repoID)
|
||||||
|
|
||||||
tasks = make([]*HookTask, 0, 5)
|
tasks = make([]*HookTask, 0, 5)
|
||||||
if err := x.Where("repo_id = ?", repoID).And("is_delivered = ?", false).Find(&tasks); err != nil {
|
if err := db.Where("repo_id = ? AND is_delivered = ?", repoID, false).Find(&tasks).Error; err != nil {
|
||||||
log.Error("Get repository [%s] hook tasks: %v", repoID, err)
|
log.Error("Get repository [%s] hook tasks: %v", repoID, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user