diff --git a/.gitignore b/.gitignore index b3e6e89..32b1972 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,6 @@ config.yml # Dependency directories (remove the comment below to include it) # vendor/ + +# Go workspace file +go.work* \ No newline at end of file diff --git a/cmd/server.go b/cmd/server.go index 645dc4d..ae3c8e8 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -22,24 +22,18 @@ THE SOFTWARE. package cmd import ( - "fmt" - - "github.com/gin-gonic/gin" - "github.com/saltbo/gopkg/ginutil" + "github.com/saltbo/zpan/internal/app" "github.com/spf13/cobra" "github.com/spf13/viper" - - "github.com/saltbo/zpan/internal/app/api" - "github.com/saltbo/zpan/internal/app/dao" - "github.com/saltbo/zpan/web" ) // serverCmd represents the server command var serverCmd = &cobra.Command{ Use: "server", Short: "A cloud disk base on the cloud service.", - Run: func(cmd *cobra.Command, args []string) { - serverRun() + RunE: func(cmd *cobra.Command, args []string) error { + s := app.NewServer() + return s.Run() }, } @@ -48,28 +42,10 @@ func init() { serverCmd.Flags().Int("port", 8222, "server port") - viper.BindPFlags(serverCmd.Flags()) -} - -func serverRun() { - //gin.SetMode(gin.ReleaseMode) - if viper.IsSet("installed") { - dao.Init(viper.GetString("database.driver"), viper.GetString("database.dsn")) - } - - //if conf.TLS.Enabled { - // //go startTls(ge, tlsAddr, conf.TLS.Auto, conf.TLS.CacheDir, conf.Server.Domain, conf.TLS.CertPath, conf.TLS.CertkeyPath) - // go startTls(ge, conf) - //} - - ge := gin.Default() - api.SetupRoutes(ge) - web.SetupRoutes(ge) - addr := fmt.Sprintf(":%d", viper.GetInt("port")) - ginutil.Startup(ge, addr) + _ = viper.BindPFlags(serverCmd.Flags()) } -//func startTls(e *gin.Engine, conf *config.Config) { +// func startTls(e *gin.Engine, conf *config.Config) { // tlsAddr := fmt.Sprintf(":%d", conf.Server.SSLPort) // if conf.TLS.Auto { // m := autocert.Manager{ @@ -110,4 +86,4 @@ func serverRun() { // }() // httputil.SetupGracefulStop(srv) // } -//} +// } diff --git a/go.mod b/go.mod index 888b282..5029258 100644 --- a/go.mod +++ b/go.mod @@ -11,25 +11,33 @@ require ( github.com/gin-gonic/gin v1.9.1 github.com/go-oauth2/oauth2/v4 v4.5.0 github.com/golang-jwt/jwt v3.2.2+incompatible - github.com/google/uuid v1.1.1 - github.com/saltbo/gopkg v0.0.0-20210807060851-127038a22f0d + github.com/google/uuid v1.3.0 + github.com/google/wire v0.5.0 + github.com/saltbo/gopkg v0.0.0-20230725153125-0d57fc71396d + github.com/saltbo/gopkg/ginutil v0.0.0-20230725153125-0d57fc71396d + github.com/saltbo/gopkg/httputil v0.0.0-20230725152854-70fe999b57ba + github.com/saltbo/gopkg/strutil v0.0.0-20230725151952-d01c3f6b1539 + github.com/samber/lo v1.38.1 github.com/spf13/cobra v1.0.0 github.com/spf13/viper v1.7.1 github.com/storyicon/grbac v0.0.0-20200224041032-a0461737df7e github.com/stretchr/testify v1.8.3 - github.com/swaggo/swag v1.7.0 + github.com/swaggo/swag v1.8.12 github.com/tencentyun/cos-go-sdk-v5 v0.7.18 github.com/upyun/go-sdk/v3 v3.0.2 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gopkg.in/yaml.v3 v3.0.1 - gorm.io/driver/mysql v1.0.3 - gorm.io/driver/postgres v1.0.6 - gorm.io/driver/sqlite v1.1.4 - gorm.io/driver/sqlserver v1.0.5 - gorm.io/gorm v1.20.11 + gorm.io/driver/mysql v1.5.1 + gorm.io/driver/postgres v1.5.0 + gorm.io/driver/sqlite v1.5.0 + gorm.io/driver/sqlserver v1.4.1 + gorm.io/gen v0.3.23 + gorm.io/gorm v1.25.2 + gorm.io/plugin/dbresolver v1.3.0 ) require ( + github.com/DATA-DOG/go-sqlmock v1.5.0 // indirect github.com/KyleBanks/depth v1.2.1 // indirect github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect @@ -37,21 +45,21 @@ require ( github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc // indirect github.com/fsnotify/fsnotify v1.4.9 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect - github.com/go-openapi/jsonpointer v0.19.3 // indirect - github.com/go-openapi/jsonreference v0.19.4 // indirect - github.com/go-openapi/spec v0.19.14 // indirect - github.com/go-openapi/swag v0.19.11 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.19.6 // indirect + github.com/go-openapi/spec v0.20.4 // indirect + github.com/go-openapi/swag v0.19.15 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect - github.com/go-resty/resty/v2 v2.3.0 // indirect - github.com/go-sql-driver/mysql v1.5.0 // indirect + github.com/go-resty/resty/v2 v2.7.0 // indirect + github.com/go-sql-driver/mysql v1.7.1 // indirect github.com/goccy/go-json v0.10.2 // indirect - github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect + github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect + github.com/golang-sql/sqlexp v0.1.0 // indirect github.com/google/go-querystring v1.0.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-immutable-radix v1.1.0 // indirect @@ -59,26 +67,22 @@ require ( github.com/hashicorp/golang-lru v0.5.1 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect - github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.8.0 // indirect - github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.0.6 // indirect - github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect - github.com/jackc/pgtype v1.6.2 // indirect - github.com/jackc/pgx/v4 v4.10.1 // indirect + github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect + github.com/jackc/pgx/v5 v5.3.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect - github.com/jinzhu/now v1.1.1 // indirect + github.com/jinzhu/now v1.1.5 // indirect github.com/jmespath/go-jmespath v0.3.0 // indirect + github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect - github.com/kr/pretty v0.3.0 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/magiconair/properties v1.8.1 // indirect - github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e // indirect + github.com/mailru/easyjson v0.7.6 // indirect github.com/mattn/go-isatty v0.0.19 // indirect - github.com/mattn/go-sqlite3 v1.14.5 // indirect + github.com/mattn/go-sqlite3 v1.14.16 // indirect + github.com/microsoft/go-mssqldb v0.17.0 // indirect github.com/mitchellh/mapstructure v1.1.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -87,6 +91,8 @@ require ( github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.8.0 // indirect + github.com/saltbo/gopkg/sliceutil v0.0.0-20221024031008-7af9787873bd // indirect + github.com/satori/go.uuid v1.2.0 // indirect github.com/sirupsen/logrus v1.4.2 // indirect github.com/spf13/afero v1.1.2 // indirect github.com/spf13/cast v1.3.0 // indirect @@ -105,18 +111,20 @@ require ( github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect golang.org/x/arch v0.3.0 // indirect - golang.org/x/crypto v0.9.0 // indirect - golang.org/x/net v0.10.0 // indirect - golang.org/x/sys v0.8.0 // indirect - golang.org/x/text v0.9.0 // indirect + golang.org/x/crypto v0.11.0 // indirect + golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect + golang.org/x/mod v0.12.0 // indirect + golang.org/x/net v0.12.0 // indirect + golang.org/x/sys v0.10.0 // indirect + golang.org/x/text v0.11.0 // indirect golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect - golang.org/x/tools v0.6.0 // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + golang.org/x/tools v0.11.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/ini.v1 v1.51.0 // indirect - gopkg.in/yaml.v2 v2.3.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gorm.io/datatypes v1.1.1-0.20230130040222-c43177d3cf8c // indirect + gorm.io/hints v1.1.0 // indirect ) //replace github.com/saltbo/gopkg => /opt/works/gopkg diff --git a/go.sum b/go.sum index b0dfa77..ab28583 100644 --- a/go.sum +++ b/go.sum @@ -11,13 +11,18 @@ cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqCl cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +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 v1.0.0/go.mod h1:+6sju8gk8FRmSajX3Oz4G5Gm7P+mbqE9FVaXXFYTkCM= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/AzureAD/microsoft-authentication-library-for-go v0.4.0/go.mod h1:Vt9sXTKwMyGcOxSmLDMnGPgqsUg7m8pe215qMLrDXw4= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= +github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= @@ -32,9 +37,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/aliyun/aliyun-oss-go-sdk v2.1.6+incompatible h1:Ft+KeWIJxFP76LqgJbvtOA1qBIoC8vGkTV3QeCOeJC4= github.com/aliyun/aliyun-oss-go-sdk v2.1.6+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= -github.com/andybalholm/brotli v1.0.0 h1:7UCwP93aiSfvWpapti8g88vVVGp2qqtGyePsSuDafo4= github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= -github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= +github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= @@ -57,29 +61,22 @@ github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= -github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc h1:VRRKCwnzqk8QCaRC4os14xoKDdbHqqlJtJA0oc1ZAjg= -github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= +github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= @@ -111,19 +108,20 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-oauth2/oauth2/v4 v4.5.0 h1:hqU33eixHIZCqRU0IuV7A1GMplNb1Wcw8gQhCqSGpBA= github.com/go-oauth2/oauth2/v4 v4.5.0/go.mod h1:NR9Hugz5/Qe2OGxoPBhsTRNjnm/amC+z9+XTwt63rhs= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.19.4 h1:3Vw+rh13uq2JFNxgnMTGE1rnoieU9FmyE1gvnyylsYg= -github.com/go-openapi/jsonreference v0.19.4/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= +github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= +github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.19.14 h1:r4fbYFo6N4ZelmSX8G6p+cv/hZRXzcuqQIADGT1iNKM= -github.com/go-openapi/spec v0.19.14/go.mod h1:gwrgJS15eCUgjLpMjBJmbZezCsw88LmgeEip0M63doA= +github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M= +github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.11 h1:RFTu/dlFySpyVvJDfp/7674JY4SDglYWKztbiIGFpmc= -github.com/go-openapi/swag v0.19.11/go.mod h1:Uc0gKkdR+ojzsEpjh39QChyu92vPgIr72POcgHMAgSY= +github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= @@ -135,23 +133,28 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= -github.com/go-resty/resty/v2 v2.3.0 h1:JOOeAvjSlapTT92p8xiS19Zxev1neGikoHsXJeOq8So= -github.com/go-resty/resty/v2 v2.3.0/go.mod h1:UpN9CgLZNsv4e9XG50UU8xdI0F43UQ4HmxLBDwaroHU= +github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY= +github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= github.com/go-session/session v3.1.2+incompatible/go.mod h1:8B3iivBQjrz/JtC68Np2T1yBBLxTan3mn/3OM0CyRt0= -github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= +github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE= -github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= 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-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= +github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= 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/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +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/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -183,8 +186,12 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8= +github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= @@ -227,65 +234,30 @@ github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= -github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= -github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= -github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= -github.com/jackc/pgconn v1.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5lahk= -github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= -github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= -github.com/jackc/pgconn v1.8.0 h1:FmjZ0rOyXTr1wfWs45i4a9vjnjWUAGpMuQLD9OSs+lw= -github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= -github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= +github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= -github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2 h1:JVX6jT/XfzNqIjye4717ITLaNwV9mWbJx0dLCpcRzdA= -github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= -github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.0.6 h1:b1105ZGEMFe7aCvrT1Cca3VoVb4ZFMaFJLJcg/3zD+8= -github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= -github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= -github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= -github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= -github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0= -github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po= -github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ= -github.com/jackc/pgtype v1.6.2 h1:b3pDeuhbbzBYcg5kwNmNDun4pFUD/0AAr1kLXZLeNt8= -github.com/jackc/pgtype v1.6.2/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig= -github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= -github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= -github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= -github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXgo+kA= -github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o= -github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg= -github.com/jackc/pgx/v4 v4.10.1 h1:/6Q3ye4myIj6AaplUm+eRcz4OhK9HAvFf4ePsG40LJY= -github.com/jackc/pgx/v4 v4.10.1/go.mod h1:QlrWebbs3kqEZPHCTGyxecvzG6tvIsYu+A5b1raylkA= -github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= +github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw= +github.com/jackc/pgx/v5 v5.3.0 h1:/NQi8KHMpKWHInxXesC8yD4DhkXPrVhmnwYkjp9AmBA= +github.com/jackc/pgx/v5 v5.3.0/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= +github.com/jackc/puddle/v2 v2.2.0/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E= -github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc= github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -299,8 +271,8 @@ github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.10.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.10.10 h1:a/y8CglcM7gLGYmlbP/stPE5sR3hbhFRUjCBfd/0B3I= github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= @@ -313,44 +285,37 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU= -github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= -github.com/mattn/go-sqlite3 v1.14.5 h1:1IdxlwTNazvbKJQSxoJ5/9ECbEeaTTyeU7sEAZ5KKTQ= -github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= +github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +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/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -368,11 +333,14 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= +github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mozillazg/go-httpheader v0.2.1 h1:geV7TrjbL8KXSyvghnFm+NyTux/hxwueTSrwhe88TQQ= github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -385,10 +353,11 @@ github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +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/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.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -408,25 +377,28 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= -github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= -github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= -github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/saltbo/gopkg v0.0.0-20210807060851-127038a22f0d h1:3cCJV0+apAqcEzLGYgNhW+e2Bp79Wv1yrj8WUVvth+E= -github.com/saltbo/gopkg v0.0.0-20210807060851-127038a22f0d/go.mod h1:Ctr0X3ZT5ZXCJ0Pate7kuntXVHy28tAsoPzrqwigKko= +github.com/saltbo/gopkg v0.0.0-20230725153125-0d57fc71396d h1:mt7ohLvhxC1dlsVsO4k29S/zmFxpa7ZOf2WnA8N2MF4= +github.com/saltbo/gopkg v0.0.0-20230725153125-0d57fc71396d/go.mod h1:q6cyqnJHAfPnZbb/rpxOvDgVbmktTQOuT2YupaTC0sk= +github.com/saltbo/gopkg/ginutil v0.0.0-20230725153125-0d57fc71396d h1:PVU2qsEvfBA4fs6k8mbYJqGRYeKnvOl01UqMVGObH+E= +github.com/saltbo/gopkg/ginutil v0.0.0-20230725153125-0d57fc71396d/go.mod h1:qBEc5bP3nCEkEQncYyWDHEmEv/VSwf28azYQKhh2/5Y= +github.com/saltbo/gopkg/httputil v0.0.0-20230725152854-70fe999b57ba h1:Dnslzcnq+HzWlMC10j5X+yHu2g3qlx2i198nmfmemJU= +github.com/saltbo/gopkg/httputil v0.0.0-20230725152854-70fe999b57ba/go.mod h1:uSe71JfWm6u1ak86Wd5d54NYHz3+7Yom5O5U4ROwBW4= +github.com/saltbo/gopkg/sliceutil v0.0.0-20221024031008-7af9787873bd h1:0ttQVi+8YR3mux4/7lsSKGmFCvxHnH6CzAU+Er2P+mk= +github.com/saltbo/gopkg/sliceutil v0.0.0-20221024031008-7af9787873bd/go.mod h1:yY7eKXQ15uO7eD7EJXcWYOQMtONdxcb5wjSZ3pescUA= +github.com/saltbo/gopkg/strutil v0.0.0-20230725151952-d01c3f6b1539 h1:EFamJqSGhWywD9XDHv1IXzhkILee/LBnqwW2qyAJ7Qo= +github.com/saltbo/gopkg/strutil v0.0.0-20230725151952-d01c3f6b1539/go.mod h1:baiQSZ/KA1+Rx/C2f4+7xT7y5ye/B9X+ynNyCEcU7/c= +github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= +github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc h1:jUIKcSPO9MoMJBbEoyE/RJoE8vz7Mb8AjvifMMwSyvY= -github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= @@ -452,7 +424,6 @@ github.com/storyicon/grbac v0.0.0-20200224041032-a0461737df7e h1:v/SEKCJ/DsYAl51 github.com/storyicon/grbac v0.0.0-20200224041032-a0461737df7e/go.mod h1:bkwjmFAuumy2DsLyhHzgPWC6hEFjevSmI7iabVzBJ7A= 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.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= 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/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -472,8 +443,8 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69 github.com/swaggo/gin-swagger v1.2.0 h1:YskZXEiv51fjOMTsXrOetAjrMDfFaXD79PEoQBOe2W0= github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05Nn6vPhc7OI= github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= -github.com/swaggo/swag v1.7.0 h1:5bCA/MTLQoIqDXXyHfOpMeDvL9j68OY/udlK4pQoo4E= -github.com/swaggo/swag v1.7.0/go.mod h1:BdPIL73gvS9NBsdi7M1JOxLvlbfvNRaBP8m6WT6Aajo= +github.com/swaggo/swag v1.8.12 h1:pctzkNPu0AlQP2royqX3apjKCQonAnf7KGoxeO4y64w= +github.com/swaggo/swag v1.8.12/go.mod h1:lNfm6Gg+oAq3zRJQNEMBE66LIJKM44mxFqhEEgy2its= github.com/tencentyun/cos-go-sdk-v5 v0.7.18 h1:hiHAC24LWVIeE5JriNUmCqe2BVLtN0RRsCjyE2glpEg= github.com/tencentyun/cos-go-sdk-v5 v0.7.18/go.mod h1:wQBO5HdAkLjj2q6XQiIfDSP8DXDNrppDRw2Kp/1BODA= github.com/tidwall/btree v0.0.0-20191029221954-400434d76274 h1:G6Z6HvJuPjG6XfNGi/feOATzeJrfgTNJY+rGrHbA04E= @@ -509,7 +480,6 @@ github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZ github.com/upyun/go-sdk/v3 v3.0.2 h1:Ke+iOipK5CT0xzMwsgJsi7faJV7ID4lAs+wrH1RH0dA= github.com/upyun/go-sdk/v3 v3.0.2/go.mod h1:P/SnuuwhrIgAVRd/ZpzDWqCsBAf/oHg7UggbAxyZa0E= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.14.0 h1:67bfuW9azCMwW/Jlq/C+VeihNpAuJMWkYPBig1gdi3A= @@ -530,43 +500,37 @@ github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FB github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/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-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM= +golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -580,9 +544,9 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= -golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 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= @@ -601,17 +565,20 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= +golang.org/x/net v0.0.0-20211029224645-99673261e6eb/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-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= 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/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -621,7 +588,9 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ 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-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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= @@ -633,7 +602,6 @@ golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5h 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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -642,8 +610,6 @@ golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -653,17 +619,33 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +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.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -675,8 +657,8 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 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-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= @@ -684,20 +666,14 @@ golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8= +golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/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-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -739,6 +715,7 @@ gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= @@ -747,39 +724,50 @@ gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8 gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= -gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/mysql v1.0.3 h1:+JKBYPfn1tygR1/of/Fh2T8iwuVwzt+PEJmKaXzMQXg= -gorm.io/driver/mysql v1.0.3/go.mod h1:twGxftLBlFgNVNakL7F+P/x9oYqoymG3YYT8cAfI9oI= -gorm.io/driver/postgres v1.0.6 h1:9sqNcNC9PCkZ6tMzWF1cEE2PARlCONgSqRobszSTffw= -gorm.io/driver/postgres v1.0.6/go.mod h1:r0nvX27yHDNbVeXMM9Y+9i5xSePcT18RfH8clP6wpwI= -gorm.io/driver/sqlite v1.1.4 h1:PDzwYE+sI6De2+mxAneV9Xs11+ZyKV6oxD3wDGkaNvM= -gorm.io/driver/sqlite v1.1.4/go.mod h1:mJCeTFr7+crvS+TRnWc5Z3UvwxUN1BGBLMrf5LA9DYw= -gorm.io/driver/sqlserver v1.0.5 h1:n5knSvyaEwufxl0aROEW90pn+aLoV9h+vahYJk1x5l4= -gorm.io/driver/sqlserver v1.0.5/go.mod h1:WI/bfZ+s9TigYXe3hb3XjNaUP0TqmTdXl11pECyLATs= -gorm.io/gorm v1.20.2/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= -gorm.io/gorm v1.20.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= -gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= -gorm.io/gorm v1.20.8/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= -gorm.io/gorm v1.20.11 h1:jYHQ0LLUViV85V8dM1TP9VBBkfzKTnuTXDjYObkI6yc= -gorm.io/gorm v1.20.11/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= +gorm.io/datatypes v1.1.1-0.20230130040222-c43177d3cf8c h1:jWdr7cHgl8c/ua5vYbR2WhSp+NQmzhsj0xoY3foTzW8= +gorm.io/datatypes v1.1.1-0.20230130040222-c43177d3cf8c/go.mod h1:SH2K9R+2RMjuX1CkCONrPwoe9JzVv2hkQvEu4bXGojE= +gorm.io/driver/mysql v1.3.2/go.mod h1:ChK6AHbHgDCFZyJp0F+BmVGb06PSIoh9uVYKAlRbb2U= +gorm.io/driver/mysql v1.5.1 h1:WUEH5VF9obL/lTtzjmML/5e6VfFR/788coz2uaVCAZw= +gorm.io/driver/mysql v1.5.1/go.mod h1:Jo3Xu7mMhCyj8dlrb3WoCaRd1FhsVh+yMXb1jUInf5o= +gorm.io/driver/postgres v1.5.0 h1:u2FXTy14l45qc3UeCJ7QaAXZmZfDDv0YrthvmRq1l0U= +gorm.io/driver/postgres v1.5.0/go.mod h1:FUZXzO+5Uqg5zzwzv4KK49R8lvGIyscBOqYrtI1Ce9A= +gorm.io/driver/sqlite v1.1.6/go.mod h1:W8LmC/6UvVbHKah0+QOC7Ja66EaZXHwUTjgXY8YNWX8= +gorm.io/driver/sqlite v1.5.0 h1:zKYbzRCpBrT1bNijRnxLDJWPjVfImGEn0lSnUY5gZ+c= +gorm.io/driver/sqlite v1.5.0/go.mod h1:kDMDfntV9u/vuMmz8APHtHF0b4nyBB7sfCieC6G8k8I= +gorm.io/driver/sqlserver v1.4.1 h1:t4r4r6Jam5E6ejqP7N82qAJIJAht27EGT41HyPfXRw0= +gorm.io/driver/sqlserver v1.4.1/go.mod h1:DJ4P+MeZbc5rvY58PnmN1Lnyvb5gw5NPzGshHDnJLig= +gorm.io/gen v0.3.23 h1:TL+q3bXvOzeIXBRp9vqIaD4/iaEzdU1Kgy5QSHsxDEQ= +gorm.io/gen v0.3.23/go.mod h1:G9uxGfkfNFxPoOrV5P6KQxRMgZsQSCyp9vJP8xiKTGg= +gorm.io/gorm v1.21.15/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= +gorm.io/gorm v1.22.2/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= +gorm.io/gorm v1.23.1/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= +gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gorm.io/gorm v1.25.2 h1:gs1o6Vsa+oVKG/a9ElL3XgyGfghFfkKA2SInQaCyMho= +gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gorm.io/hints v1.1.0 h1:Lp4z3rxREufSdxn4qmkK3TLDltrM10FLTHiuqwDPvXw= +gorm.io/hints v1.1.0/go.mod h1:lKQ0JjySsPBj3uslFzY3JhYDtqEwzm+G1hv8rWujB6Y= +gorm.io/plugin/dbresolver v1.3.0 h1:uFDX3bIuH9Lhj5LY2oyqR/bU6pqWuDgas35NAPF4X3M= +gorm.io/plugin/dbresolver v1.3.0/go.mod h1:Pr7p5+JFlgDaiM6sOrli5olekJD16YRunMyA2S7ZfKk= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/hack/gen/main.go b/hack/gen/main.go new file mode 100644 index 0000000..5117172 --- /dev/null +++ b/hack/gen/main.go @@ -0,0 +1,19 @@ +package main + +import ( + "github.com/saltbo/zpan/internal/app/entity" + "gorm.io/gen" +) + +func main() { + g := gen.NewGenerator(gen.Config{ + OutPath: "./internal/app/repo/query", + Mode: gen.WithoutContext | gen.WithDefaultQuery | gen.WithQueryInterface, // generate mode + }) + + // Generate basic type-safe DAO API for struct `model.User` following conventions + g.ApplyBasic(entity.Storage{}, entity.Matter{}, entity.RecycleBin{}) + + // Generate the code + g.Execute() +} diff --git a/internal/app/api/matter.go b/internal/app/api/matter.go index bac6e0b..f7cee55 100644 --- a/internal/app/api/matter.go +++ b/internal/app/api/matter.go @@ -3,20 +3,20 @@ package api import ( "github.com/gin-gonic/gin" "github.com/saltbo/gopkg/ginutil" - + "github.com/saltbo/zpan/internal/app/repo" + "github.com/saltbo/zpan/internal/app/usecase/uploader" + "github.com/saltbo/zpan/internal/app/usecase/vfs" "github.com/saltbo/zpan/internal/pkg/authed" "github.com/saltbo/zpan/internal/pkg/bind" - "github.com/saltbo/zpan/internal/pkg/fakefs" ) type FileResource struct { - fs *fakefs.FakeFS + fs vfs.VirtualFs + up uploader.Uploader } -func NewFileResource() ginutil.Resource { - return &FileResource{ - fs: fakefs.New(), - } +func NewFileResource(fs vfs.VirtualFs, up uploader.Uploader) *FileResource { + return &FileResource{fs: fs, up: up} } func (rs *FileResource) Register(router *gin.RouterGroup) { @@ -29,17 +29,17 @@ func (rs *FileResource) Register(router *gin.RouterGroup) { router.PATCH("/matters/:alias/location", rs.move) router.PATCH("/matters/:alias/duplicate", rs.copy) router.DELETE("/matters/:alias", rs.delete) - rs.fs.StartFileAutoDoneWorker() + // rs.fs.StartFileAutoDoneWorker() } func (rs *FileResource) findAll(c *gin.Context) { - p := new(bind.QueryFiles) + p := new(repo.MatterListOption) if err := c.BindQuery(p); err != nil { ginutil.JSONBadRequest(c, err) return } - list, total, err := rs.fs.List(authed.UidGet(c), p) + list, total, err := rs.fs.List(c, p) if err != nil { ginutil.JSONServerError(c, err) return @@ -56,7 +56,7 @@ func (rs *FileResource) findAll(c *gin.Context) { // @Produce json // @Security OAuth2Application[matter, admin] // @Param body body bind.BodyMatter true "参数" -// @Success 200 {object} httputil.JSONResponse{data=model.User} +// @Success 200 {object} httputil.JSONResponse{data=entity.Matter} // @Failure 400 {object} httputil.JSONResponse // @Failure 500 {object} httputil.JSONResponse // @Router /matters [post] @@ -68,25 +68,27 @@ func (rs *FileResource) create(c *gin.Context) { } m := p.ToMatter(authed.UidGet(c)) - op := rs.fs.CreateFile - if m.IsDir() { - op = rs.fs.CreateFolder - } - - data, err := op(m) - if err != nil { + if err := rs.fs.Create(c, m); err != nil { ginutil.JSONServerError(c, err) return } - ginutil.JSONData(c, data) + ginutil.JSONData(c, gin.H{ + "matter": m, + "uplink": m.Uploader["upURL"], + "headers": m.Uploader["upHeaders"], + }) } func (rs *FileResource) uploaded(c *gin.Context) { - uid := authed.UidGet(c) alias := c.Param("alias") - m, err := rs.fs.TagUploadDone(uid, alias) + m, err := rs.fs.Get(c, alias) if err != nil { + ginutil.JSONBadRequest(c, err) + return + } + + if err := rs.up.UploadDone(c, m); err != nil { ginutil.JSONServerError(c, err) return } @@ -95,7 +97,7 @@ func (rs *FileResource) uploaded(c *gin.Context) { } func (rs *FileResource) find(c *gin.Context) { - matter, err := rs.fs.GetFileInfo(authed.UidGet(c), c.Param("alias")) + matter, err := rs.fs.Get(c, c.Param("alias")) if err != nil { ginutil.JSONServerError(c, err) return @@ -111,9 +113,7 @@ func (rs *FileResource) rename(c *gin.Context) { return } - uid := authed.UidGet(c) - alias := c.Param("alias") - if err := rs.fs.Rename(uid, alias, p.NewName); err != nil { + if err := rs.fs.Rename(c, c.Param("alias"), p.NewName); err != nil { ginutil.JSONServerError(c, err) return } @@ -128,9 +128,7 @@ func (rs *FileResource) move(c *gin.Context) { return } - uid := authed.UidGet(c) - alias := c.Param("alias") - if err := rs.fs.Move(uid, alias, p.NewDir); err != nil { + if err := rs.fs.Move(c, c.Param("alias"), p.NewDir); err != nil { ginutil.JSONServerError(c, err) return } @@ -145,20 +143,17 @@ func (rs *FileResource) copy(c *gin.Context) { return } - uid := authed.UidGet(c) - alias := c.Param("alias") - if err := rs.fs.Copy(uid, alias, p.NewPath); err != nil { + m, err := rs.fs.Copy(c, c.Param("alias"), p.NewPath) + if err != nil { ginutil.JSONServerError(c, err) return } - ginutil.JSON(c) + ginutil.JSONData(c, m) } func (rs *FileResource) delete(c *gin.Context) { - uid := authed.UidGet(c) - alias := c.Param("alias") - if err := rs.fs.Delete(uid, alias); err != nil { + if err := rs.fs.Delete(c, c.Param("alias")); err != nil { ginutil.JSONServerError(c, err) return } @@ -167,11 +162,11 @@ func (rs *FileResource) delete(c *gin.Context) { } func (rs *FileResource) ulink(c *gin.Context) { - data, err := rs.fs.GetSaveRequest(authed.UidGet(c), c.Param("alias")) - if err != nil { - ginutil.JSONServerError(c, err) - return - } - - ginutil.JSONData(c, data) + // data, err := rs.up.GetPreSign(authed.UidGet(c), c.Param("alias")) + // if err != nil { + // ginutil.JSONServerError(c, err) + // return + // } + // + // ginutil.JSONData(c, data) } diff --git a/internal/app/api/recyclebin.go b/internal/app/api/recyclebin.go index e9d8f50..aee3530 100644 --- a/internal/app/api/recyclebin.go +++ b/internal/app/api/recyclebin.go @@ -1,24 +1,20 @@ package api import ( - "strconv" - "github.com/gin-gonic/gin" "github.com/saltbo/gopkg/ginutil" - - "github.com/saltbo/zpan/internal/pkg/authed" + "github.com/saltbo/zpan/internal/app/repo" + "github.com/saltbo/zpan/internal/app/usecase/vfs" "github.com/saltbo/zpan/internal/pkg/bind" - "github.com/saltbo/zpan/internal/app/service" ) type RecycleBinResource struct { - rb *service.RecycleBin + rbr repo.RecycleBin + rbf vfs.RecycleBinFs } -func NewRecycleBinResource() ginutil.Resource { - return &RecycleBinResource{ - rb: service.NewRecycleBin(), - } +func NewRecycleBinResource(rbr repo.RecycleBin, rbf vfs.RecycleBinFs) *RecycleBinResource { + return &RecycleBinResource{rbr: rbr, rbf: rbf} } func (rs *RecycleBinResource) Register(router *gin.RouterGroup) { @@ -35,7 +31,7 @@ func (rs *RecycleBinResource) findAll(c *gin.Context) { return } - list, total, err := rs.rb.FindAll(authed.UidGet(c), p.Sid, p.Offset, p.Limit) + list, total, err := rs.rbr.FindAll(c, &repo.RecycleBinFindOptions{QueryPage: repo.QueryPage(p.QueryPage), Sid: p.Sid}) if err != nil { ginutil.JSONServerError(c, err) return @@ -44,10 +40,9 @@ func (rs *RecycleBinResource) findAll(c *gin.Context) { ginutil.JSONList(c, list, total) } -func (rs RecycleBinResource) recovery(c *gin.Context) { - uid := authed.UidGet(c) +func (rs *RecycleBinResource) recovery(c *gin.Context) { alias := c.Param("alias") - if err := rs.rb.Recovery(uid, alias); err != nil { + if err := rs.rbf.Recovery(c, alias); err != nil { ginutil.JSONServerError(c, err) return } @@ -56,9 +51,8 @@ func (rs RecycleBinResource) recovery(c *gin.Context) { } func (rs *RecycleBinResource) delete(c *gin.Context) { - uid := authed.UidGet(c) alias := c.Param("alias") - if err := rs.rb.Delete(uid, alias); err != nil { + if err := rs.rbf.Delete(c, alias); err != nil { ginutil.JSONServerError(c, err) return } @@ -67,9 +61,7 @@ func (rs *RecycleBinResource) delete(c *gin.Context) { } func (rs *RecycleBinResource) clean(c *gin.Context) { - uid := authed.UidGet(c) - sid, _ := strconv.ParseInt(c.Query("sid"), 10, 64) - if err := rs.rb.Clean(uid, sid); err != nil { + if err := rs.rbf.Clean(c, ginutil.QueryInt64(c, "sid")); err != nil { ginutil.JSONServerError(c, err) return } diff --git a/internal/app/api/router.go b/internal/app/api/router.go index db124c5..8cb4d9c 100644 --- a/internal/app/api/router.go +++ b/internal/app/api/router.go @@ -25,18 +25,18 @@ import ( // @license.name GPL 3.0 // @license.url https://github.com/saltbo/zpan/blob/master/LICENSE -func SetupRoutes(ge *gin.Engine) { +func SetupRoutes(ge *gin.Engine, repository *Repository) { ginutil.SetupSwagger(ge) apiRouter := ge.Group("/api") ginutil.SetupResource(apiRouter, - NewOptionResource(), - NewUserResource(), - NewUserKeyResource(), - NewTokenResource(), - NewStorageResource(), - NewFileResource(), - NewShareResource(), - NewRecycleBinResource(), + repository.option, + repository.file, + repository.storage, + repository.share, + repository.token, + repository.user, + repository.userKey, + repository.recycleBin, ) } diff --git a/internal/app/api/share.go b/internal/app/api/share.go index d15103d..15bd857 100644 --- a/internal/app/api/share.go +++ b/internal/app/api/share.go @@ -10,7 +10,7 @@ import ( "github.com/saltbo/gopkg/ginutil" "github.com/saltbo/gopkg/jwtutil" "github.com/saltbo/gopkg/strutil" - "github.com/saltbo/zpan/internal/pkg/fakefs" + "github.com/saltbo/zpan/internal/app/repo" "gorm.io/gorm" "github.com/saltbo/zpan/internal/app/dao" @@ -24,16 +24,14 @@ const ShareCookieTokenKey = "share-token" type ShareResource struct { jwtutil.JWTUtil - fs *fakefs.FakeFS dShare *dao.Share - dMatter *dao.Matter + dMatter repo.Matter } -func NewShareResource() ginutil.Resource { +func NewShareResource(dMatter repo.Matter) *ShareResource { return &ShareResource{ - fs: fakefs.New(), dShare: dao.NewShare(), - dMatter: dao.NewMatter(), + dMatter: dMatter, } } @@ -86,7 +84,7 @@ func (rs *ShareResource) create(c *gin.Context) { return } - mMatter, err := rs.dMatter.Find(p.Matter) + mMatter, err := rs.dMatter.FindByAlias(c, p.Matter) if err != nil { ginutil.JSONBadRequest(c, err) return @@ -195,7 +193,7 @@ func (rs *ShareResource) findMatter(c *gin.Context) { return } - mMatter, err := rs.fs.GetFileInfo(share.Uid, share.Matter) + mMatter, err := rs.dMatter.FindByAlias(c, share.Matter) if err != nil { ginutil.JSONServerError(c, err) return @@ -222,19 +220,18 @@ func (rs *ShareResource) findMatters(c *gin.Context) { return } - mMatter, err := rs.dMatter.Find(share.Matter) + mMatter, err := rs.dMatter.FindByAlias(c, share.Matter) if errors.Is(err, gorm.ErrRecordNotFound) { ginutil.JSONBadRequest(c, fmt.Errorf("matter not found")) return } dir := fmt.Sprintf("%s%s", mMatter.FullPath(), p.Dir) // 设置父级目录 - query := dao.NewQuery() - query.WithEq("uid", mMatter.Uid) - query.WithEq("parent", dir) - query.Offset = p.Offset - query.Limit = p.Limit - list, total, err := rs.dMatter.FindAll(query) + list, total, err := rs.dMatter.FindAll(c, &repo.MatterListOption{ + QueryPage: repo.QueryPage{Offset: p.Offset, Limit: p.Limit}, + Uid: mMatter.Uid, + Dir: dir, + }) if err != nil { ginutil.JSONServerError(c, err) return diff --git a/internal/app/api/storage.go b/internal/app/api/storage.go index 1f5439a..f006c59 100644 --- a/internal/app/api/storage.go +++ b/internal/app/api/storage.go @@ -4,21 +4,26 @@ import ( "github.com/gin-gonic/gin" "github.com/saltbo/gopkg/ginutil" "github.com/saltbo/gopkg/jwtutil" + "github.com/saltbo/zpan/internal/app/entity" + "github.com/saltbo/zpan/internal/app/repo" + "github.com/saltbo/zpan/internal/app/usecase/storage" + "github.com/samber/lo" - "github.com/saltbo/zpan/internal/app/dao" "github.com/saltbo/zpan/internal/pkg/bind" - "github.com/saltbo/zpan/internal/app/service" ) -type Storage struct { +type StorageResource struct { jwtutil.JWTUtil + + storageRepo repo.Storage + storageUc storage.Storage } -func NewStorageResource() *Storage { - return &Storage{} +func NewStorageResource(storageRepo repo.Storage, storageUc storage.Storage) *StorageResource { + return &StorageResource{storageRepo: storageRepo, storageUc: storageUc} } -func (rs *Storage) Register(router *gin.RouterGroup) { +func (rs *StorageResource) Register(router *gin.RouterGroup) { router.GET("/storages/:id", rs.find) router.GET("/storages", rs.findAll) router.POST("/storages", rs.create) @@ -26,42 +31,46 @@ func (rs *Storage) Register(router *gin.RouterGroup) { router.DELETE("/storages/:id", rs.delete) } -func (rs *Storage) find(c *gin.Context) { - storage, err := dao.NewStorage().Find(c.Param("id")) +func (rs *StorageResource) find(c *gin.Context) { + ret, err := rs.storageRepo.Find(c, ginutil.ParamInt64(c, "id")) if err != nil { ginutil.JSONServerError(c, err) return } - ginutil.JSONData(c, storage) + ginutil.JSONData(c, ret) } -func (rs *Storage) findAll(c *gin.Context) { +func (rs *StorageResource) findAll(c *gin.Context) { p := new(bind.StorageQuery) if err := c.Bind(p); err != nil { ginutil.JSONBadRequest(c, err) return } - list, total, err := dao.NewStorage().FindAll(p.Limit, p.Offset) + list, total, err := rs.storageRepo.FindAll(c, &repo.StorageFindOptions{Limit: p.Limit, Offset: p.Offset}) if err != nil { ginutil.JSONServerError(c, err) return } + lo.Map(list, func(item *entity.Storage, index int) *entity.Storage { + item.SecretKey = item.SKAsterisk() + return item + }) + ginutil.JSONList(c, list, total) } -func (rs *Storage) create(c *gin.Context) { +func (rs *StorageResource) create(c *gin.Context) { p := new(bind.StorageBody) if err := c.Bind(p); err != nil { ginutil.JSONBadRequest(c, err) return } - sStorage := service.NewStorage() - if err := sStorage.Create(p.Model()); err != nil { + if err := rs.storageUc.Create(c, p.Model()); err != nil { ginutil.JSONServerError(c, err) return } @@ -69,15 +78,14 @@ func (rs *Storage) create(c *gin.Context) { ginutil.JSON(c) } -func (rs *Storage) update(c *gin.Context) { +func (rs *StorageResource) update(c *gin.Context) { p := new(bind.StorageBody) if err := c.Bind(p); err != nil { ginutil.JSONBadRequest(c, err) return } - sStorage := dao.NewStorage() - if err := sStorage.Update(c.Param("id"), p.Model()); err != nil { + if err := rs.storageRepo.Update(c, ginutil.ParamInt64(c, "id"), p.Model()); err != nil { ginutil.JSONServerError(c, err) return } @@ -85,9 +93,8 @@ func (rs *Storage) update(c *gin.Context) { ginutil.JSON(c) } -func (rs *Storage) delete(c *gin.Context) { - sStorage := dao.NewStorage() - if err := sStorage.Delete(c.Param("id")); err != nil { +func (rs *StorageResource) delete(c *gin.Context) { + if err := rs.storageRepo.Delete(c, ginutil.ParamInt64(c, "id")); err != nil { ginutil.JSONServerError(c, err) return } diff --git a/internal/app/api/system.go b/internal/app/api/system.go index d019080..bdd4677 100644 --- a/internal/app/api/system.go +++ b/internal/app/api/system.go @@ -7,6 +7,7 @@ import ( "github.com/saltbo/gopkg/ginutil" "github.com/saltbo/gopkg/jwtutil" "github.com/saltbo/gopkg/strutil" + "github.com/saltbo/zpan/internal/app/entity" "github.com/spf13/viper" "github.com/saltbo/zpan/internal/app/dao" @@ -137,5 +138,5 @@ func (rs *Option) update(c *gin.Context) { } func (rs *Option) matterPathEnvs(c *gin.Context) { - ginutil.JSONData(c, model.SupportEnvs) + ginutil.JSONData(c, entity.SupportEnvs) } diff --git a/internal/app/api/wire.go b/internal/app/api/wire.go new file mode 100644 index 0000000..7f2e57d --- /dev/null +++ b/internal/app/api/wire.go @@ -0,0 +1,30 @@ +package api + +import "github.com/google/wire" + +type Repository struct { + file *FileResource + recycleBin *RecycleBinResource + share *ShareResource + storage *StorageResource + option *Option + token *TokenResource + user *UserResource + userKey *UserKeyResource +} + +func NewRepository(file *FileResource, recycleBin *RecycleBinResource, share *ShareResource, storage *StorageResource, option *Option, token *TokenResource, user *UserResource, userKey *UserKeyResource) *Repository { + return &Repository{file: file, recycleBin: recycleBin, share: share, storage: storage, option: option, token: token, user: user, userKey: userKey} +} + +var ProviderSet = wire.NewSet( + NewStorageResource, + NewFileResource, + NewRecycleBinResource, + NewOptionResource, + NewUserResource, + NewUserKeyResource, + NewTokenResource, + NewShareResource, + NewRepository, +) diff --git a/internal/app/dao/dao.go b/internal/app/dao/dao.go index a873f40..a328440 100644 --- a/internal/app/dao/dao.go +++ b/internal/app/dao/dao.go @@ -1,6 +1,10 @@ package dao import ( + "log" + + "github.com/saltbo/zpan/internal/app/repo/query" + "github.com/spf13/viper" "gorm.io/gorm" "github.com/saltbo/zpan/internal/app/model" @@ -31,6 +35,16 @@ func Init(driver, dsn string) error { return nil } +func GetDBQuery() *query.Query { + if viper.IsSet("installed") { + if err := Init(viper.GetString("database.driver"), viper.GetString("database.dsn")); err != nil { + log.Fatalln(err) + } + } + + return query.Use(gdb) +} + func Transaction(fc func(tx *gorm.DB) error) error { return gdb.Transaction(fc) } diff --git a/internal/app/dao/matter.go b/internal/app/dao/matter.go deleted file mode 100644 index 1fb9a3e..0000000 --- a/internal/app/dao/matter.go +++ /dev/null @@ -1,196 +0,0 @@ -package dao - -import ( - "errors" - "fmt" - "strings" - "time" - - "gorm.io/gorm" - - "github.com/saltbo/zpan/internal/app/model" -) - -type Matter struct { -} - -func NewMatter() *Matter { - return &Matter{} -} - -func (ms *Matter) Exist(uid int64, name, parent string) (*model.Matter, bool) { - m := new(model.Matter) - err := gdb.Where("uid=? and name=? and parent=?", uid, name, parent).First(m).Error - return m, !errors.Is(err, gorm.ErrRecordNotFound) -} - -func (ms *Matter) ParentExist(uid int64, parentDir string) bool { - if parentDir == "" { - return true - } - - // parent matter exist, eg: test123/234/ - items := strings.Split(parentDir, "/") - name := items[len(items)-2] // -> 234 - parent := strings.TrimSuffix(parentDir, name+"/") // -> test123/ - pm, exist := ms.Exist(uid, name, parent) - if exist && pm.IsDir() { - return true - } - - return false -} - -func (ms *Matter) FindAll(query *Query) (list []model.Matter, total int64, err error) { - sn := gdb.Where(query.SQL()+" and uploaded_at is not null", query.Params...) - sn.Model(model.Matter{}).Count(&total) - sn = sn.Order("dirtype desc") - err = sn.Offset(query.Offset).Limit(query.Limit).Find(&list).Error - return -} - -func (ms *Matter) FindChildren(uid int64, parent string) (children []model.Matter, err error) { - err = gdb.Debug().Where("uid=? and parent like ?", uid, parent+"%").Find(&children).Error - return -} - -func (ms *Matter) UnscopedChildren(uid int64, recycleAlias string) (children []model.Matter, err error) { - err = gdb.Unscoped().Where("uid=? and trashed_by=?", uid, recycleAlias).Find(&children).Error - return -} - -func (ms *Matter) Create(matter *model.Matter) error { - if _, ok := ms.Exist(matter.Uid, matter.Name, matter.Parent); ok { - return fmt.Errorf("matter already exist") - } - - if !ms.ParentExist(matter.Uid, matter.Parent) { - return fmt.Errorf("parent dir not exist") - } - - return gdb.Create(matter).Error -} - -func (ms *Matter) Find(alias string) (*model.Matter, error) { - m := new(model.Matter) - if err := gdb.First(m, "alias=?", alias).Error; errors.Is(err, gorm.ErrRecordNotFound) { - return nil, fmt.Errorf("file not exist") - } - - return m, nil -} - -func (ms *Matter) FindUserMatter(uid int64, alias string) (*model.Matter, error) { - m, err := ms.Find(alias) - if err != nil { - return nil, err - } else if !m.UserAccessible(uid) { - return nil, fmt.Errorf("not accessible") - } - - return m, nil -} - -func (ms *Matter) Uploaded(matter *model.Matter, incrUsed bool) error { - fc := func(tx *gorm.DB) error { - if err := tx.First(matter).Where("uploaded_at is null").Update("uploaded_at", time.Now()).Error; err != nil { - return err - } - - if !incrUsed { - return nil - } - - // update the storage used of the user - expr := gorm.Expr("used+?", matter.Size) - return tx.Model(&model.UserStorage{}).Where("uid=?", matter.Uid).Update("used", expr).Error - } - - return gdb.Transaction(fc) -} - -func (ms *Matter) Rename(alias, name string) error { - m := gdb.Model(&model.Matter{}) - return m.Where("alias=?", alias).Update("name", name).Error -} - -func (ms *Matter) Move(alias, parent string) error { - m := gdb.Model(&model.Matter{}) - return m.Where("alias=?", alias).Update("parent", parent).Error -} - -func (ms *Matter) Copy(alias, parent string) error { - m, err := ms.Find(alias) - if err != nil { - return err - } - - nm := m.Clone() - nm.Parent = parent - return ms.Create(nm) -} - -func (ms *Matter) Remove(mid int64, trashedBy string) error { - deletedAt := gorm.DeletedAt{Time: time.Now(), Valid: true} - values := model.Matter{TrashedBy: trashedBy, DeletedAt: deletedAt} - return gdb.Model(&model.Matter{Id: mid}).Updates(values).Error -} - -func (ms *Matter) RemoveToRecycle(m *model.Matter) error { - // soft delete the matter - if err := ms.Remove(m.Id, m.Alias); err != nil { - return err - } - - // create a recycle record - rm := &model.Recycle{ - Uid: m.Uid, - Sid: m.Sid, - Alias: m.Alias, - Name: m.Name, - Type: m.Type, - Size: m.Size, - DirType: m.DirType, - Parent: m.Parent, - Object: m.Object, - } - return gdb.Create(rm).Error -} - -func (ms *Matter) Recovery(m *model.Recycle) error { - fc := func(tx *gorm.DB) error { - // remove the delete tag - sn := tx.Model(&model.Matter{}).Where("uid=? and trashed_by=?", m.Uid, m.Alias) - values := map[string]interface{}{"trashed_by": "", "deleted_at": nil} - if err := sn.Unscoped().Updates(values).Error; err != nil { - return err - } - - // delete the recycle record - return tx.Delete(&model.Recycle{}, "alias=?", m.Alias).Error - } - - return gdb.Debug().Transaction(fc) -} - -func (ms *Matter) RenameChildren(m *model.Matter, newName string) error { - children, err := ms.FindChildren(m.Uid, m.FullPath()) - if err != nil { - return err - } - - oldParent := fmt.Sprintf("%s%s/", m.Parent, m.Name) - newParent := fmt.Sprintf("%s%s/", m.Parent, newName) - fc := func(tx *gorm.DB) error { - for _, v := range children { - parent := strings.Replace(v.Parent, oldParent, newParent, 1) - if err := tx.Model(v).Update("parent", parent).Error; err != nil { - return err - } - } - - return nil - } - - return gdb.Transaction(fc) -} diff --git a/internal/app/dao/recyclebin.go b/internal/app/dao/recyclebin.go deleted file mode 100644 index f951e73..0000000 --- a/internal/app/dao/recyclebin.go +++ /dev/null @@ -1,58 +0,0 @@ -package dao - -import ( - "errors" - "fmt" - - "gorm.io/gorm" - - "github.com/saltbo/zpan/internal/app/model" -) - -type RecycleBin struct { -} - -func NewRecycleBin() *RecycleBin { - return &RecycleBin{ - } -} - -func (rb *RecycleBin) FindAll(q *Query) (list []model.Recycle, total int64, err error) { - sn := gdb.Where(q.SQL(), q.Params...) - sn.Model(model.Recycle{}).Count(&total) - sn = sn.Order("dirtype desc") - if q.Offset > 0 { - sn = sn.Offset(q.Offset) - } - if q.Limit > 0 { - sn = sn.Limit(q.Limit) - } - err = sn.Find(&list).Error - return -} - -func (rb *RecycleBin) Find(uid int64, alias string) (*model.Recycle, error) { - m := new(model.Recycle) - if err := gdb.Unscoped().First(m, "alias=?", alias).Error; errors.Is(err, gorm.ErrRecordNotFound) { - return nil, fmt.Errorf("file not exist") - } else if !m.UserAccessible(uid) { - return nil, fmt.Errorf("not accessible") - } - - return m, nil -} - -func (rb *RecycleBin) Release(uid, size int64, query interface{}, args ...interface{}) error { - fc := func(tx *gorm.DB) error { - // release the user storage - expr := gorm.Expr("used-?", size) - if err := tx.Model(&model.UserStorage{}).Where("uid=?", uid).Update("used", expr).Error; err != nil { - return err - } - - // clean the RecycleBin - return tx.Where(query, args...).Delete(&model.Recycle{}).Error - } - - return gdb.Transaction(fc) -} diff --git a/internal/app/dao/share.go b/internal/app/dao/share.go index 459437f..46e36b9 100644 --- a/internal/app/dao/share.go +++ b/internal/app/dao/share.go @@ -21,7 +21,7 @@ func (s *Share) Create(share *model.Share) error { } func (s *Share) Update(id int64, share *model.Share) error { - if err := gdb.First(&model.Storage{}, id).Error; errors.Is(err, gorm.ErrRecordNotFound) { + if err := gdb.First(&model.Share{}, id).Error; errors.Is(err, gorm.ErrRecordNotFound) { return fmt.Errorf("share not found") } diff --git a/internal/app/dao/storage.go b/internal/app/dao/storage.go deleted file mode 100644 index 134b8d5..0000000 --- a/internal/app/dao/storage.go +++ /dev/null @@ -1,67 +0,0 @@ -package dao - -import ( - "errors" - "fmt" - "strconv" - - "gorm.io/gorm" - - "github.com/saltbo/zpan/internal/app/model" -) - -type Storage struct { -} - -func NewStorage() *Storage { - return &Storage{} -} - -func (s *Storage) Find(id interface{}) (*model.Storage, error) { - storage := new(model.Storage) - if err := gdb.First(storage, id).Error; errors.Is(err, gorm.ErrRecordNotFound) { - return nil, fmt.Errorf("storage not exist") - } - - return storage, nil -} - -func (s *Storage) FindAll(offset, limit int) (storages []model.Storage, total int64, err error) { - gdb.Model(model.Storage{}).Count(&total) - err = gdb.Find(&storages).Offset(offset).Limit(limit).Error - for idx, storage := range storages { - storages[idx].SecretKey = storage.SKAsterisk() // 对外隐藏SK - } - return -} - -func (s *Storage) Create(storage *model.Storage) error { - if err := gdb.First(storage, "name=?", storage.Name).Error; !errors.Is(err, gorm.ErrRecordNotFound) { - return fmt.Errorf("storage already exist") - } - - return gdb.Create(storage).Error -} - -func (s *Storage) Update(id string, storage *model.Storage) error { - existStorage := new(model.Storage) - if err := gdb.First(existStorage, id).Error; errors.Is(err, gorm.ErrRecordNotFound) { - return fmt.Errorf("storage not found") - } - - storage.Id, _ = strconv.ParseInt(id, 10, 64) - // 如果SK没有发生改变则不允许更新SK,避免改错SK - if storage.SecretKey == existStorage.SKAsterisk() { - storage.SecretKey = existStorage.SecretKey - } - return gdb.Save(storage).Error -} - -func (s *Storage) Delete(id string) error { - storage := new(model.Storage) - if err := gdb.First(storage, id).Error; errors.Is(err, gorm.ErrRecordNotFound) { - return fmt.Errorf("storage not exist") - } - - return gdb.Delete(storage).Error -} diff --git a/internal/app/model/matter.go b/internal/app/entity/matter.go similarity index 78% rename from internal/app/model/matter.go rename to internal/app/entity/matter.go index 5483ed5..b321036 100644 --- a/internal/app/model/matter.go +++ b/internal/app/entity/matter.go @@ -1,6 +1,7 @@ -package model +package entity import ( + "path" "path/filepath" "strings" "time" @@ -37,23 +38,29 @@ type Matter struct { Parent string `json:"parent" gorm:"not null"` Object string `json:"object" gorm:"not null"` URL string `json:"url" gorm:"-"` + Uploader map[string]any `json:"uploader" gorm:"-"` CreatedAt time.Time `json:"created" gorm:"not null"` UpdatedAt time.Time `json:"updated" gorm:"not null"` - UploadedAt *time.Time `json:"uploaded"` + UploadedAt time.Time `json:"uploaded"` DeletedAt gorm.DeletedAt `json:"-"` TrashedBy string `json:"-" gorm:"size:16;not null"` } +func (m *Matter) GetID() int64 { + return m.Id +} + func NewMatter(uid, sid int64, name string) *Matter { return &Matter{ - Uid: uid, - Sid: sid, - Alias: strutil.RandomText(16), - Name: strings.TrimSpace(name), + Uid: uid, + Sid: sid, + Alias: strutil.RandomText(16), + Name: strings.TrimSpace(name), + Uploader: make(map[string]any), } } -func (Matter) TableName() string { +func (m *Matter) TableName() string { return "zp_matter" } @@ -65,7 +72,7 @@ func (m *Matter) Clone() *Matter { } func (m *Matter) FullPath() string { - fp := m.Parent + m.Name + fp := path.Join(m.Parent, m.Name) if m.IsDir() { fp += "/" } @@ -97,3 +104,16 @@ func (m *Matter) renderPath(path string) string { return strings.NewReplacer(ons...).Replace(path) } + +func (m *Matter) BuildRecycleBinItem() *RecycleBin { + return &RecycleBin{ + Uid: m.Uid, + Sid: m.Sid, + Mid: m.Id, + Alias: strutil.RandomText(16), + Name: m.Name, + Type: m.Type, + Size: m.Size, + DirType: m.DirType, + } +} diff --git a/internal/app/model/matter_env.go b/internal/app/entity/matter_env.go similarity index 99% rename from internal/app/model/matter_env.go rename to internal/app/entity/matter_env.go index 243a764..db51050 100644 --- a/internal/app/model/matter_env.go +++ b/internal/app/entity/matter_env.go @@ -1,4 +1,4 @@ -package model +package entity import ( "fmt" diff --git a/internal/app/entity/recycle.go b/internal/app/entity/recycle.go new file mode 100644 index 0000000..15d9274 --- /dev/null +++ b/internal/app/entity/recycle.go @@ -0,0 +1,44 @@ +package entity + +import ( + "time" + + "gorm.io/gorm" +) + +type RecycleBin struct { + Id int64 `json:"id"` + Uid int64 `json:"uid" gorm:"not null"` + Sid int64 `json:"sid" gorm:"not null"` // storage_id + Mid int64 `json:"mid" gorm:"not null;default:0"` // matter_id + Alias string `json:"alias" gorm:"size:16;not null"` + Name string `json:"name" gorm:"not null"` + Type string `json:"type" gorm:"not null"` + Size int64 `json:"size" gorm:"not null"` + DirType int8 `json:"dirtype" gorm:"column:dirtype;not null"` + + // Deprecated: 弃用 + Parent string `json:"parent" gorm:"not null"` + + // Deprecated: 弃用,不在存储具体对象 + Object string `json:"object" gorm:"not null"` + + CreatedAt time.Time `json:"created" gorm:"not null"` + DeletedAt gorm.DeletedAt `json:"-"` +} + +func (m *RecycleBin) GetID() string { + return m.Alias +} + +func (m *RecycleBin) TableName() string { + return "zp_recycle" +} + +func (m *RecycleBin) IsDir() bool { + return m.DirType > 0 +} + +func (m *RecycleBin) UserAccessible(uid int64) bool { + return m.Uid == uid +} diff --git a/internal/app/model/storage.go b/internal/app/entity/storage.go similarity index 93% rename from internal/app/model/storage.go rename to internal/app/entity/storage.go index 73f13ac..a73d637 100644 --- a/internal/app/model/storage.go +++ b/internal/app/entity/storage.go @@ -1,4 +1,4 @@ -package model +package entity import ( "time" @@ -37,7 +37,11 @@ type Storage struct { Deleted gorm.DeletedAt `json:"-"` } -func (Storage) TableName() string { +func (s *Storage) GetID() int64 { + return s.Id +} + +func (s *Storage) TableName() string { return "zp_storage" } diff --git a/internal/app/model/base.go b/internal/app/model/base.go index b0bb6f0..74e6976 100644 --- a/internal/app/model/base.go +++ b/internal/app/model/base.go @@ -1,5 +1,7 @@ package model +import "github.com/saltbo/zpan/internal/app/entity" + func Tables() []interface{} { return []interface{}{ new(Option), @@ -7,9 +9,9 @@ func Tables() []interface{} { new(UserKey), new(UserProfile), new(UserStorage), - new(Storage), - new(Matter), + new(entity.Storage), + new(entity.Matter), new(Share), - new(Recycle), + new(entity.RecycleBin), } } diff --git a/internal/app/model/recycle.go b/internal/app/model/recycle.go deleted file mode 100644 index 4d1af74..0000000 --- a/internal/app/model/recycle.go +++ /dev/null @@ -1,39 +0,0 @@ -package model - -import "time" - -type Recycle struct { - Id int64 `json:"id"` - Uid int64 `json:"uid" gorm:"not null"` - Sid int64 `json:"sid" gorm:"not null"` // storage_id - Alias string `json:"alias" gorm:"size:16;not null"` - Name string `json:"name" gorm:"not null"` - Type string `json:"type" gorm:"not null"` - Size int64 `json:"size" gorm:"not null"` - DirType int8 `json:"dirtype" gorm:"column:dirtype;not null"` - Parent string `json:"parent" gorm:"not null"` - Object string `json:"object" gorm:"not null"` - CreatedAt time.Time `json:"created" gorm:"not null"` - DeletedAt *time.Time `json:"deleted"` -} - -func (Recycle) TableName() string { - return "zp_recycle" -} - -func (m *Recycle) FullPath() string { - fp := m.Parent + m.Name - if m.DirType > 0 { - fp += "/" - } - - return fp -} - -func (m *Recycle) IsDir() bool { - return m.DirType > 0 -} - -func (m *Recycle) UserAccessible(uid int64) bool { - return m.Uid == uid -} diff --git a/internal/app/repo/base.go b/internal/app/repo/base.go new file mode 100644 index 0000000..b40633d --- /dev/null +++ b/internal/app/repo/base.go @@ -0,0 +1,46 @@ +package repo + +import ( + "context" +) + +type QueryPage struct { + Offset int `form:"offset"` + Limit int `form:"limit,default=500"` +} + +type Opt[p any] interface { + apply(*p) +} + +type IDType interface { + int64 | string +} + +type BasicOP[T comparable, ID IDType, O any] interface { + Writer[T, ID] + Reader[T, ID, O] +} + +type Writer[T comparable, ID IDType] interface { + Creator[T] + Updater[T, ID] + Deleter[ID] +} + +type Reader[T comparable, ID IDType, O any] interface { + Find(ctx context.Context, id ID) (T, error) + FindAll(ctx context.Context, opts O) ([]T, int64, error) +} + +type Creator[T comparable] interface { + Create(ctx context.Context, entity T) error +} + +type Updater[T comparable, ID IDType] interface { + Update(ctx context.Context, id ID, entity T) error +} + +type Deleter[ID IDType] interface { + Delete(ctx context.Context, id ID) error +} diff --git a/internal/app/repo/matter.go b/internal/app/repo/matter.go new file mode 100644 index 0000000..3980aec --- /dev/null +++ b/internal/app/repo/matter.go @@ -0,0 +1,262 @@ +package repo + +import ( + "context" + "fmt" + "path" + "strings" + + "github.com/google/uuid" + "github.com/saltbo/zpan/internal/app/entity" + "github.com/saltbo/zpan/internal/app/repo/query" + "github.com/samber/lo" + "gorm.io/gen" + "gorm.io/gorm" +) + +type MatterListOption struct { + QueryPage + Sid int64 `form:"sid" binding:"required"` + Uid int64 `form:"uid"` + Dir string `form:"dir"` + Type string `form:"type"` + Keyword string `form:"kw"` +} + +type MatterFindWithOption struct { + Id int64 + Alias string + Deleted bool +} + +type Matter interface { + BasicOP[*entity.Matter, int64, *MatterListOption] + + FindWith(ctx context.Context, opt *MatterFindWithOption) (*entity.Matter, error) + FindByAlias(ctx context.Context, alias string) (*entity.Matter, error) + PathExist(ctx context.Context, path string) bool + Copy(ctx context.Context, id int64, to string) (*entity.Matter, error) + Recovery(ctx context.Context, id int64) error + GetObjects(ctx context.Context, id int64) ([]string, error) +} + +var _ Matter = (*MatterDBQuery)(nil) + +type MatterDBQuery struct { + q *query.Query +} + +func NewMatterDBQuery(q *query.Query) *MatterDBQuery { + return &MatterDBQuery{q: q} +} + +func (db *MatterDBQuery) Find(ctx context.Context, id int64) (*entity.Matter, error) { + return db.q.Matter.WithContext(ctx).Where(db.q.Matter.Id.Eq(id)).First() +} + +func (db *MatterDBQuery) FindWith(ctx context.Context, opt *MatterFindWithOption) (*entity.Matter, error) { + conds := make([]gen.Condition, 0) + if opt.Id != 0 { + conds = append(conds, db.q.Matter.Id.Eq(opt.Id)) + } + if opt.Alias != "" { + conds = append(conds, db.q.Matter.Alias_.Eq(opt.Alias)) + } + + q := db.q.Matter.WithContext(ctx) + if opt.Deleted { + q = q.Unscoped() + } + + return q.Where(conds...).First() +} + +func (db *MatterDBQuery) FindByAlias(ctx context.Context, alias string) (*entity.Matter, error) { + return db.q.Matter.WithContext(ctx).Where(db.q.Matter.Alias_.Eq(alias)).First() +} + +func (db *MatterDBQuery) PathExist(ctx context.Context, filepath string) bool { + if filepath == "" { + return true + } + + var name, parent string + if strings.HasSuffix(filepath, "/") { + name = path.Base(filepath) + parent = strings.TrimSuffix(filepath, name+"/") + } else { + parent, name = path.Split(filepath) + } + + conds := []gen.Condition{db.q.Matter.Name.Eq(name)} + if parent != name { + conds = append(conds, db.q.Matter.Parent.Eq(strings.TrimPrefix(parent, "/"))) + } + + _, err := db.q.Matter.WithContext(ctx).Where(conds...).First() + return err == nil +} + +func (db *MatterDBQuery) FindAll(ctx context.Context, opts *MatterListOption) ([]*entity.Matter, int64, error) { + conds := make([]gen.Condition, 0) + if opts.Uid != 0 { + conds = append(conds, db.q.Matter.Uid.Eq(opts.Uid)) + } + if opts.Sid != 0 { + conds = append(conds, db.q.Matter.Sid.Eq(opts.Sid)) + } + + if opts.Keyword != "" { + conds = append(conds, db.q.Matter.Name.Like(fmt.Sprintf("%%%s%%", opts.Keyword))) + } else { + conds = append(conds, db.q.Matter.Parent.Eq(opts.Dir)) + } + + if opts.Type == "doc" { + conds = append(conds, db.q.Matter.Type.In(entity.DocTypes...)) + } else if opts.Type != "" { + conds = append(conds, db.q.Matter.Type.Like(fmt.Sprintf("%%%s%%", opts.Type))) + } + + return db.q.Matter.Where(conds...).Order(db.q.Matter.DirType.Desc()).FindByPage(opts.Offset, opts.Limit) +} + +func (db *MatterDBQuery) Create(ctx context.Context, m *entity.Matter) error { + if exist := db.PathExist(ctx, m.FullPath()); exist { + return fmt.Errorf("matter %s already exist", m.FullPath()) + } + + if exist := db.PathExist(ctx, m.Parent); !exist { + return fmt.Errorf("base dir not exist") + } + + return db.q.Matter.Create(m) +} + +func (db *MatterDBQuery) Copy(ctx context.Context, id int64, to string) (*entity.Matter, error) { + em, err := db.Find(ctx, id) + if err != nil { + return nil, err + } + + if exist := db.PathExist(ctx, path.Join(to, em.Name)); exist { + return nil, fmt.Errorf("dir already has the same name file") + } + + newMatter := em.Clone() + newMatter.Parent = to + if !em.IsDir() { + // 如果是文件则只创建新的文件即可 + return newMatter, db.q.Matter.Create(newMatter) + } + + // 如果是文件夹则查找所有子文件/文件夹一起复制 + matters, err := db.findChildren(ctx, em, false) + if err != nil { + return nil, err + } + + newMatters := lo.Map(matters, func(item *entity.Matter, index int) *entity.Matter { + newMatter := em.Clone() + newMatter.Parent = to + return newMatter + }) + + return newMatter, db.q.Matter.Create(newMatters...) +} + +func (db *MatterDBQuery) Update(ctx context.Context, id int64, m *entity.Matter) error { + em, err := db.Find(ctx, id) + if err != nil { + return err + } + + return db.q.Transaction(func(tx *query.Query) error { + tq := tx.Matter.WithContext(ctx) + if m.IsDir() { + // 如果是目录,则需要把该目录下的子文件/目录一并修改 + cond := tx.Matter.Parent.Like(em.FullPath() + "%") + updated := map[string]any{"parent": gorm.Expr("REPLACE(parent, ?, ?)", em.FullPath(), m.FullPath())} + if _, err := tq.Select(tx.Matter.Parent).Where(cond).Updates(updated); err != nil { + return err + } + } + + _, err := tq.Select(tx.Matter.Name, tx.Matter.Parent).Updates(m) + return err + }) +} + +func (db *MatterDBQuery) Delete(ctx context.Context, id int64) error { + m, err := db.Find(ctx, id) + if err != nil { + return err + } + + m.TrashedBy = uuid.New().String() + return db.q.Transaction(func(tx *query.Query) error { + tq := tx.Matter.WithContext(ctx) + if m.IsDir() { + // 如果是目录,则需要把该目录下的子文件/目录一并删除 + cond := tx.Matter.Parent.Like(m.Name + "/%") + if _, err := tq.Where(cond).Update(tx.Matter.TrashedBy, m.TrashedBy); err != nil { + return err + } + if _, err := tq.Where(cond).Delete(); err != nil { + return err + } + } + + if _, err := tq.Select(tx.Matter.TrashedBy).Updates(m); err != nil { + return err + } + _, err := tq.Delete(m) + return err + }) +} + +func (db *MatterDBQuery) Recovery(ctx context.Context, id int64) error { + m, err := db.q.Matter.WithContext(ctx).Unscoped().Where(db.q.Matter.Id.Eq(id)).First() + if err != nil { + return err + } + + if !db.PathExist(ctx, m.Parent) { + return fmt.Errorf("recovery: file parent[%s] not found", m.Parent) + } + + _, err = db.q.Matter.WithContext(ctx).Unscoped().Where(db.q.Matter.TrashedBy.Eq(m.TrashedBy)). + UpdateSimple(db.q.Matter.TrashedBy.Value(""), db.q.Matter.DeletedAt.Null()) + return err +} + +func (db *MatterDBQuery) GetObjects(ctx context.Context, id int64) ([]string, error) { + m, err := db.FindWith(ctx, &MatterFindWithOption{Id: id, Deleted: true}) + if err != nil { + return nil, err + } + + if !m.IsDir() { + return []string{m.Object}, nil + } + + matters, err := db.findChildren(ctx, m, true) + if err != nil { + return nil, err + } + + return lo.Map(lo.Filter(append(matters, m), func(item *entity.Matter, index int) bool { + return item.Object != "" + }), func(item *entity.Matter, index int) string { + return item.Object + }), nil +} + +func (db *MatterDBQuery) findChildren(ctx context.Context, m *entity.Matter, withDeleted bool) ([]*entity.Matter, error) { + q := db.q.Matter.WithContext(ctx) + if withDeleted { + q = q.Unscoped() + } + + return q.Where(db.q.Matter.Parent.Like(m.FullPath() + "%")).Find() +} diff --git a/internal/app/repo/matter_test.go b/internal/app/repo/matter_test.go new file mode 100644 index 0000000..f3e2c5f --- /dev/null +++ b/internal/app/repo/matter_test.go @@ -0,0 +1,105 @@ +package repo + +import ( + "context" + "database/sql/driver" + "testing" + "time" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/saltbo/zpan/internal/app/entity" + "github.com/saltbo/zpan/internal/app/repo/query" + "github.com/stretchr/testify/assert" + "gorm.io/driver/mysql" + "gorm.io/gorm" +) + +var nowFunc = func() time.Time { + return time.Unix(0, 0) +} + +func newMockDB(t *testing.T) (sqlmock.Sqlmock, *gorm.DB) { + rdb, mock, err := sqlmock.New() + assert.NoError(t, err) + gdb, err := gorm.Open(mysql.New(mysql.Config{Conn: rdb, DriverName: "mysql", SkipInitializeWithVersion: true}), &gorm.Config{ + NowFunc: nowFunc, + }) + assert.NoError(t, err) + return mock, gdb.Debug() +} + +func TestMatterDBQuery_PathExist(t *testing.T) { + mock, gdb := newMockDB(t) + q := NewMatterDBQuery(query.Use(gdb)) + mock.ExpectQuery("SELECT").WithArgs("to", "path/") + q.PathExist(context.Background(), "/path/to/") + + mock.ExpectQuery("SELECT").WithArgs("a.txt", "path/to/") + q.PathExist(context.Background(), "/path/to/a.txt") + + mock.ExpectQuery("SELECT").WithArgs("path", "") + q.PathExist(context.Background(), "/path") + + // we make sure that all expectations were met + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expectations: %s", err) + } +} + +func TestMatterDBQuery_Update(t *testing.T) { + testCases := map[string]struct { + target *entity.Matter + rows *sqlmock.Rows + + expectChildrenArgs []driver.Value // newParent, updated, oldParent + expectChildrenResult driver.Result + + expectMainArgs []driver.Value // name, parent, updated, id + expectMainResult driver.Result + }{ + "update name with children": { + target: &entity.Matter{Id: 1, Name: "dir1-1", Parent: "dir0/", DirType: entity.DirTypeUser}, + rows: sqlmock.NewRows([]string{"id", "name", "parent", "dirtype"}). + AddRow(1, "dir1", "dir0", 1), + + expectChildrenArgs: []driver.Value{"dir0/dir1/", "dir0/dir1-1/", nowFunc(), "dir0/dir1/%"}, + expectChildrenResult: sqlmock.NewResult(1, 1), + + expectMainArgs: []driver.Value{"dir1-1", "dir0/", nowFunc(), 1}, + expectMainResult: sqlmock.NewResult(1, 1), + }, + "update parent with children": { + target: &entity.Matter{Id: 2, Name: "dir2", Parent: "dir1/", DirType: entity.DirTypeUser}, // 把dir2移动到目录dir1里 + rows: sqlmock.NewRows([]string{"id", "name", "parent", "dirtype"}). + AddRow(2, "dir2", "", 2), + + expectChildrenArgs: []driver.Value{"dir2/", "dir1/dir2/", nowFunc(), "dir2/%"}, + expectChildrenResult: sqlmock.NewResult(1, 1), + + expectMainArgs: []driver.Value{"dir2", "dir1/", nowFunc(), 2}, + expectMainResult: sqlmock.NewResult(1, 1), + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + mock, gdb := newMockDB(t) + mock.ExpectQuery("SELECT").WithArgs(tc.target.Id). + WillReturnRows(tc.rows) + + mock.ExpectBegin() + mock.ExpectExec("UPDATE"). + WithArgs(tc.expectChildrenArgs...). + WillReturnResult(tc.expectChildrenResult) + + mock.ExpectExec("UPDATE"). + WithArgs(tc.expectMainArgs...). + WillReturnResult(tc.expectMainResult) + mock.ExpectCommit() + + q := NewMatterDBQuery(query.Use(gdb)) + ctx := context.Background() + assert.NoError(t, q.Update(ctx, tc.target.Id, tc.target)) + }) + } +} diff --git a/internal/app/repo/query/gen.go b/internal/app/repo/query/gen.go new file mode 100644 index 0000000..4f35b8c --- /dev/null +++ b/internal/app/repo/query/gen.go @@ -0,0 +1,119 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package query + +import ( + "context" + "database/sql" + + "gorm.io/gorm" + + "gorm.io/gen" + + "gorm.io/plugin/dbresolver" +) + +var ( + Q = new(Query) + Matter *matter + RecycleBin *recycleBin + Storage *storage +) + +func SetDefault(db *gorm.DB, opts ...gen.DOOption) { + *Q = *Use(db, opts...) + Matter = &Q.Matter + RecycleBin = &Q.RecycleBin + Storage = &Q.Storage +} + +func Use(db *gorm.DB, opts ...gen.DOOption) *Query { + return &Query{ + db: db, + Matter: newMatter(db, opts...), + RecycleBin: newRecycleBin(db, opts...), + Storage: newStorage(db, opts...), + } +} + +type Query struct { + db *gorm.DB + + Matter matter + RecycleBin recycleBin + Storage storage +} + +func (q *Query) Available() bool { return q.db != nil } + +func (q *Query) clone(db *gorm.DB) *Query { + return &Query{ + db: db, + Matter: q.Matter.clone(db), + RecycleBin: q.RecycleBin.clone(db), + Storage: q.Storage.clone(db), + } +} + +func (q *Query) ReadDB() *Query { + return q.ReplaceDB(q.db.Clauses(dbresolver.Read)) +} + +func (q *Query) WriteDB() *Query { + return q.ReplaceDB(q.db.Clauses(dbresolver.Write)) +} + +func (q *Query) ReplaceDB(db *gorm.DB) *Query { + return &Query{ + db: db, + Matter: q.Matter.replaceDB(db), + RecycleBin: q.RecycleBin.replaceDB(db), + Storage: q.Storage.replaceDB(db), + } +} + +type queryCtx struct { + Matter IMatterDo + RecycleBin IRecycleBinDo + Storage IStorageDo +} + +func (q *Query) WithContext(ctx context.Context) *queryCtx { + return &queryCtx{ + Matter: q.Matter.WithContext(ctx), + RecycleBin: q.RecycleBin.WithContext(ctx), + Storage: q.Storage.WithContext(ctx), + } +} + +func (q *Query) Transaction(fc func(tx *Query) error, opts ...*sql.TxOptions) error { + return q.db.Transaction(func(tx *gorm.DB) error { return fc(q.clone(tx)) }, opts...) +} + +func (q *Query) Begin(opts ...*sql.TxOptions) *QueryTx { + tx := q.db.Begin(opts...) + return &QueryTx{Query: q.clone(tx), Error: tx.Error} +} + +type QueryTx struct { + *Query + Error error +} + +func (q *QueryTx) Commit() error { + return q.db.Commit().Error +} + +func (q *QueryTx) Rollback() error { + return q.db.Rollback().Error +} + +func (q *QueryTx) SavePoint(name string) error { + return q.db.SavePoint(name).Error +} + +func (q *QueryTx) RollbackTo(name string) error { + return q.db.RollbackTo(name).Error +} diff --git a/internal/app/repo/query/zp_matter.gen.go b/internal/app/repo/query/zp_matter.gen.go new file mode 100644 index 0000000..f82065e --- /dev/null +++ b/internal/app/repo/query/zp_matter.gen.go @@ -0,0 +1,436 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package query + +import ( + "context" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/schema" + + "gorm.io/gen" + "gorm.io/gen/field" + + "gorm.io/plugin/dbresolver" + + "github.com/saltbo/zpan/internal/app/entity" +) + +func newMatter(db *gorm.DB, opts ...gen.DOOption) matter { + _matter := matter{} + + _matter.matterDo.UseDB(db, opts...) + _matter.matterDo.UseModel(&entity.Matter{}) + + tableName := _matter.matterDo.TableName() + _matter.ALL = field.NewAsterisk(tableName) + _matter.Id = field.NewInt64(tableName, "id") + _matter.Uid = field.NewInt64(tableName, "uid") + _matter.Sid = field.NewInt64(tableName, "sid") + _matter.Alias_ = field.NewString(tableName, "alias") + _matter.Name = field.NewString(tableName, "name") + _matter.Type = field.NewString(tableName, "type") + _matter.Size = field.NewInt64(tableName, "size") + _matter.DirType = field.NewInt8(tableName, "dirtype") + _matter.Parent = field.NewString(tableName, "parent") + _matter.Object = field.NewString(tableName, "object") + _matter.CreatedAt = field.NewTime(tableName, "created_at") + _matter.UpdatedAt = field.NewTime(tableName, "updated_at") + _matter.UploadedAt = field.NewTime(tableName, "uploaded_at") + _matter.DeletedAt = field.NewField(tableName, "deleted_at") + _matter.TrashedBy = field.NewString(tableName, "trashed_by") + + _matter.fillFieldMap() + + return _matter +} + +type matter struct { + matterDo + + ALL field.Asterisk + Id field.Int64 + Uid field.Int64 + Sid field.Int64 + Alias_ field.String + Name field.String + Type field.String + Size field.Int64 + DirType field.Int8 + Parent field.String + Object field.String + CreatedAt field.Time + UpdatedAt field.Time + UploadedAt field.Time + DeletedAt field.Field + TrashedBy field.String + + fieldMap map[string]field.Expr +} + +func (m matter) Table(newTableName string) *matter { + m.matterDo.UseTable(newTableName) + return m.updateTableName(newTableName) +} + +func (m matter) As(alias string) *matter { + m.matterDo.DO = *(m.matterDo.As(alias).(*gen.DO)) + return m.updateTableName(alias) +} + +func (m *matter) updateTableName(table string) *matter { + m.ALL = field.NewAsterisk(table) + m.Id = field.NewInt64(table, "id") + m.Uid = field.NewInt64(table, "uid") + m.Sid = field.NewInt64(table, "sid") + m.Alias_ = field.NewString(table, "alias") + m.Name = field.NewString(table, "name") + m.Type = field.NewString(table, "type") + m.Size = field.NewInt64(table, "size") + m.DirType = field.NewInt8(table, "dirtype") + m.Parent = field.NewString(table, "parent") + m.Object = field.NewString(table, "object") + m.CreatedAt = field.NewTime(table, "created_at") + m.UpdatedAt = field.NewTime(table, "updated_at") + m.UploadedAt = field.NewTime(table, "uploaded_at") + m.DeletedAt = field.NewField(table, "deleted_at") + m.TrashedBy = field.NewString(table, "trashed_by") + + m.fillFieldMap() + + return m +} + +func (m *matter) GetFieldByName(fieldName string) (field.OrderExpr, bool) { + _f, ok := m.fieldMap[fieldName] + if !ok || _f == nil { + return nil, false + } + _oe, ok := _f.(field.OrderExpr) + return _oe, ok +} + +func (m *matter) fillFieldMap() { + m.fieldMap = make(map[string]field.Expr, 15) + m.fieldMap["id"] = m.Id + m.fieldMap["uid"] = m.Uid + m.fieldMap["sid"] = m.Sid + m.fieldMap["alias"] = m.Alias_ + m.fieldMap["name"] = m.Name + m.fieldMap["type"] = m.Type + m.fieldMap["size"] = m.Size + m.fieldMap["dirtype"] = m.DirType + m.fieldMap["parent"] = m.Parent + m.fieldMap["object"] = m.Object + m.fieldMap["created_at"] = m.CreatedAt + m.fieldMap["updated_at"] = m.UpdatedAt + m.fieldMap["uploaded_at"] = m.UploadedAt + m.fieldMap["deleted_at"] = m.DeletedAt + m.fieldMap["trashed_by"] = m.TrashedBy +} + +func (m matter) clone(db *gorm.DB) matter { + m.matterDo.ReplaceConnPool(db.Statement.ConnPool) + return m +} + +func (m matter) replaceDB(db *gorm.DB) matter { + m.matterDo.ReplaceDB(db) + return m +} + +type matterDo struct{ gen.DO } + +type IMatterDo interface { + gen.SubQuery + Debug() IMatterDo + WithContext(ctx context.Context) IMatterDo + WithResult(fc func(tx gen.Dao)) gen.ResultInfo + ReplaceDB(db *gorm.DB) + ReadDB() IMatterDo + WriteDB() IMatterDo + As(alias string) gen.Dao + Session(config *gorm.Session) IMatterDo + Columns(cols ...field.Expr) gen.Columns + Clauses(conds ...clause.Expression) IMatterDo + Not(conds ...gen.Condition) IMatterDo + Or(conds ...gen.Condition) IMatterDo + Select(conds ...field.Expr) IMatterDo + Where(conds ...gen.Condition) IMatterDo + Order(conds ...field.Expr) IMatterDo + Distinct(cols ...field.Expr) IMatterDo + Omit(cols ...field.Expr) IMatterDo + Join(table schema.Tabler, on ...field.Expr) IMatterDo + LeftJoin(table schema.Tabler, on ...field.Expr) IMatterDo + RightJoin(table schema.Tabler, on ...field.Expr) IMatterDo + Group(cols ...field.Expr) IMatterDo + Having(conds ...gen.Condition) IMatterDo + Limit(limit int) IMatterDo + Offset(offset int) IMatterDo + Count() (count int64, err error) + Scopes(funcs ...func(gen.Dao) gen.Dao) IMatterDo + Unscoped() IMatterDo + Create(values ...*entity.Matter) error + CreateInBatches(values []*entity.Matter, batchSize int) error + Save(values ...*entity.Matter) error + First() (*entity.Matter, error) + Take() (*entity.Matter, error) + Last() (*entity.Matter, error) + Find() ([]*entity.Matter, error) + FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*entity.Matter, err error) + FindInBatches(result *[]*entity.Matter, batchSize int, fc func(tx gen.Dao, batch int) error) error + Pluck(column field.Expr, dest interface{}) error + Delete(...*entity.Matter) (info gen.ResultInfo, err error) + Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error) + UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error) + Updates(value interface{}) (info gen.ResultInfo, err error) + UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error) + UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error) + UpdateColumns(value interface{}) (info gen.ResultInfo, err error) + UpdateFrom(q gen.SubQuery) gen.Dao + Attrs(attrs ...field.AssignExpr) IMatterDo + Assign(attrs ...field.AssignExpr) IMatterDo + Joins(fields ...field.RelationField) IMatterDo + Preload(fields ...field.RelationField) IMatterDo + FirstOrInit() (*entity.Matter, error) + FirstOrCreate() (*entity.Matter, error) + FindByPage(offset int, limit int) (result []*entity.Matter, count int64, err error) + ScanByPage(result interface{}, offset int, limit int) (count int64, err error) + Scan(result interface{}) (err error) + Returning(value interface{}, columns ...string) IMatterDo + UnderlyingDB() *gorm.DB + schema.Tabler +} + +func (m matterDo) Debug() IMatterDo { + return m.withDO(m.DO.Debug()) +} + +func (m matterDo) WithContext(ctx context.Context) IMatterDo { + return m.withDO(m.DO.WithContext(ctx)) +} + +func (m matterDo) ReadDB() IMatterDo { + return m.Clauses(dbresolver.Read) +} + +func (m matterDo) WriteDB() IMatterDo { + return m.Clauses(dbresolver.Write) +} + +func (m matterDo) Session(config *gorm.Session) IMatterDo { + return m.withDO(m.DO.Session(config)) +} + +func (m matterDo) Clauses(conds ...clause.Expression) IMatterDo { + return m.withDO(m.DO.Clauses(conds...)) +} + +func (m matterDo) Returning(value interface{}, columns ...string) IMatterDo { + return m.withDO(m.DO.Returning(value, columns...)) +} + +func (m matterDo) Not(conds ...gen.Condition) IMatterDo { + return m.withDO(m.DO.Not(conds...)) +} + +func (m matterDo) Or(conds ...gen.Condition) IMatterDo { + return m.withDO(m.DO.Or(conds...)) +} + +func (m matterDo) Select(conds ...field.Expr) IMatterDo { + return m.withDO(m.DO.Select(conds...)) +} + +func (m matterDo) Where(conds ...gen.Condition) IMatterDo { + return m.withDO(m.DO.Where(conds...)) +} + +func (m matterDo) Order(conds ...field.Expr) IMatterDo { + return m.withDO(m.DO.Order(conds...)) +} + +func (m matterDo) Distinct(cols ...field.Expr) IMatterDo { + return m.withDO(m.DO.Distinct(cols...)) +} + +func (m matterDo) Omit(cols ...field.Expr) IMatterDo { + return m.withDO(m.DO.Omit(cols...)) +} + +func (m matterDo) Join(table schema.Tabler, on ...field.Expr) IMatterDo { + return m.withDO(m.DO.Join(table, on...)) +} + +func (m matterDo) LeftJoin(table schema.Tabler, on ...field.Expr) IMatterDo { + return m.withDO(m.DO.LeftJoin(table, on...)) +} + +func (m matterDo) RightJoin(table schema.Tabler, on ...field.Expr) IMatterDo { + return m.withDO(m.DO.RightJoin(table, on...)) +} + +func (m matterDo) Group(cols ...field.Expr) IMatterDo { + return m.withDO(m.DO.Group(cols...)) +} + +func (m matterDo) Having(conds ...gen.Condition) IMatterDo { + return m.withDO(m.DO.Having(conds...)) +} + +func (m matterDo) Limit(limit int) IMatterDo { + return m.withDO(m.DO.Limit(limit)) +} + +func (m matterDo) Offset(offset int) IMatterDo { + return m.withDO(m.DO.Offset(offset)) +} + +func (m matterDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IMatterDo { + return m.withDO(m.DO.Scopes(funcs...)) +} + +func (m matterDo) Unscoped() IMatterDo { + return m.withDO(m.DO.Unscoped()) +} + +func (m matterDo) Create(values ...*entity.Matter) error { + if len(values) == 0 { + return nil + } + return m.DO.Create(values) +} + +func (m matterDo) CreateInBatches(values []*entity.Matter, batchSize int) error { + return m.DO.CreateInBatches(values, batchSize) +} + +// Save : !!! underlying implementation is different with GORM +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) +func (m matterDo) Save(values ...*entity.Matter) error { + if len(values) == 0 { + return nil + } + return m.DO.Save(values) +} + +func (m matterDo) First() (*entity.Matter, error) { + if result, err := m.DO.First(); err != nil { + return nil, err + } else { + return result.(*entity.Matter), nil + } +} + +func (m matterDo) Take() (*entity.Matter, error) { + if result, err := m.DO.Take(); err != nil { + return nil, err + } else { + return result.(*entity.Matter), nil + } +} + +func (m matterDo) Last() (*entity.Matter, error) { + if result, err := m.DO.Last(); err != nil { + return nil, err + } else { + return result.(*entity.Matter), nil + } +} + +func (m matterDo) Find() ([]*entity.Matter, error) { + result, err := m.DO.Find() + return result.([]*entity.Matter), err +} + +func (m matterDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*entity.Matter, err error) { + buf := make([]*entity.Matter, 0, batchSize) + err = m.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { + defer func() { results = append(results, buf...) }() + return fc(tx, batch) + }) + return results, err +} + +func (m matterDo) FindInBatches(result *[]*entity.Matter, batchSize int, fc func(tx gen.Dao, batch int) error) error { + return m.DO.FindInBatches(result, batchSize, fc) +} + +func (m matterDo) Attrs(attrs ...field.AssignExpr) IMatterDo { + return m.withDO(m.DO.Attrs(attrs...)) +} + +func (m matterDo) Assign(attrs ...field.AssignExpr) IMatterDo { + return m.withDO(m.DO.Assign(attrs...)) +} + +func (m matterDo) Joins(fields ...field.RelationField) IMatterDo { + for _, _f := range fields { + m = *m.withDO(m.DO.Joins(_f)) + } + return &m +} + +func (m matterDo) Preload(fields ...field.RelationField) IMatterDo { + for _, _f := range fields { + m = *m.withDO(m.DO.Preload(_f)) + } + return &m +} + +func (m matterDo) FirstOrInit() (*entity.Matter, error) { + if result, err := m.DO.FirstOrInit(); err != nil { + return nil, err + } else { + return result.(*entity.Matter), nil + } +} + +func (m matterDo) FirstOrCreate() (*entity.Matter, error) { + if result, err := m.DO.FirstOrCreate(); err != nil { + return nil, err + } else { + return result.(*entity.Matter), nil + } +} + +func (m matterDo) FindByPage(offset int, limit int) (result []*entity.Matter, count int64, err error) { + result, err = m.Offset(offset).Limit(limit).Find() + if err != nil { + return + } + + if size := len(result); 0 < limit && 0 < size && size < limit { + count = int64(size + offset) + return + } + + count, err = m.Offset(-1).Limit(-1).Count() + return +} + +func (m matterDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { + count, err = m.Count() + if err != nil { + return + } + + err = m.Offset(offset).Limit(limit).Scan(result) + return +} + +func (m matterDo) Scan(result interface{}) (err error) { + return m.DO.Scan(result) +} + +func (m matterDo) Delete(models ...*entity.Matter) (result gen.ResultInfo, err error) { + return m.DO.Delete(models) +} + +func (m *matterDo) withDO(do gen.Dao) *matterDo { + m.DO = *do.(*gen.DO) + return m +} diff --git a/internal/app/repo/query/zp_recycle.gen.go b/internal/app/repo/query/zp_recycle.gen.go new file mode 100644 index 0000000..e7fed39 --- /dev/null +++ b/internal/app/repo/query/zp_recycle.gen.go @@ -0,0 +1,428 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package query + +import ( + "context" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/schema" + + "gorm.io/gen" + "gorm.io/gen/field" + + "gorm.io/plugin/dbresolver" + + "github.com/saltbo/zpan/internal/app/entity" +) + +func newRecycleBin(db *gorm.DB, opts ...gen.DOOption) recycleBin { + _recycleBin := recycleBin{} + + _recycleBin.recycleBinDo.UseDB(db, opts...) + _recycleBin.recycleBinDo.UseModel(&entity.RecycleBin{}) + + tableName := _recycleBin.recycleBinDo.TableName() + _recycleBin.ALL = field.NewAsterisk(tableName) + _recycleBin.Id = field.NewInt64(tableName, "id") + _recycleBin.Uid = field.NewInt64(tableName, "uid") + _recycleBin.Sid = field.NewInt64(tableName, "sid") + _recycleBin.Mid = field.NewInt64(tableName, "mid") + _recycleBin.Alias_ = field.NewString(tableName, "alias") + _recycleBin.Name = field.NewString(tableName, "name") + _recycleBin.Type = field.NewString(tableName, "type") + _recycleBin.Size = field.NewInt64(tableName, "size") + _recycleBin.DirType = field.NewInt8(tableName, "dirtype") + _recycleBin.Parent = field.NewString(tableName, "parent") + _recycleBin.Object = field.NewString(tableName, "object") + _recycleBin.CreatedAt = field.NewTime(tableName, "created_at") + _recycleBin.DeletedAt = field.NewField(tableName, "deleted_at") + + _recycleBin.fillFieldMap() + + return _recycleBin +} + +type recycleBin struct { + recycleBinDo + + ALL field.Asterisk + Id field.Int64 + Uid field.Int64 + Sid field.Int64 + Mid field.Int64 + Alias_ field.String + Name field.String + Type field.String + Size field.Int64 + DirType field.Int8 + Parent field.String + Object field.String + CreatedAt field.Time + DeletedAt field.Field + + fieldMap map[string]field.Expr +} + +func (r recycleBin) Table(newTableName string) *recycleBin { + r.recycleBinDo.UseTable(newTableName) + return r.updateTableName(newTableName) +} + +func (r recycleBin) As(alias string) *recycleBin { + r.recycleBinDo.DO = *(r.recycleBinDo.As(alias).(*gen.DO)) + return r.updateTableName(alias) +} + +func (r *recycleBin) updateTableName(table string) *recycleBin { + r.ALL = field.NewAsterisk(table) + r.Id = field.NewInt64(table, "id") + r.Uid = field.NewInt64(table, "uid") + r.Sid = field.NewInt64(table, "sid") + r.Mid = field.NewInt64(table, "mid") + r.Alias_ = field.NewString(table, "alias") + r.Name = field.NewString(table, "name") + r.Type = field.NewString(table, "type") + r.Size = field.NewInt64(table, "size") + r.DirType = field.NewInt8(table, "dirtype") + r.Parent = field.NewString(table, "parent") + r.Object = field.NewString(table, "object") + r.CreatedAt = field.NewTime(table, "created_at") + r.DeletedAt = field.NewField(table, "deleted_at") + + r.fillFieldMap() + + return r +} + +func (r *recycleBin) GetFieldByName(fieldName string) (field.OrderExpr, bool) { + _f, ok := r.fieldMap[fieldName] + if !ok || _f == nil { + return nil, false + } + _oe, ok := _f.(field.OrderExpr) + return _oe, ok +} + +func (r *recycleBin) fillFieldMap() { + r.fieldMap = make(map[string]field.Expr, 13) + r.fieldMap["id"] = r.Id + r.fieldMap["uid"] = r.Uid + r.fieldMap["sid"] = r.Sid + r.fieldMap["mid"] = r.Mid + r.fieldMap["alias"] = r.Alias_ + r.fieldMap["name"] = r.Name + r.fieldMap["type"] = r.Type + r.fieldMap["size"] = r.Size + r.fieldMap["dirtype"] = r.DirType + r.fieldMap["parent"] = r.Parent + r.fieldMap["object"] = r.Object + r.fieldMap["created_at"] = r.CreatedAt + r.fieldMap["deleted_at"] = r.DeletedAt +} + +func (r recycleBin) clone(db *gorm.DB) recycleBin { + r.recycleBinDo.ReplaceConnPool(db.Statement.ConnPool) + return r +} + +func (r recycleBin) replaceDB(db *gorm.DB) recycleBin { + r.recycleBinDo.ReplaceDB(db) + return r +} + +type recycleBinDo struct{ gen.DO } + +type IRecycleBinDo interface { + gen.SubQuery + Debug() IRecycleBinDo + WithContext(ctx context.Context) IRecycleBinDo + WithResult(fc func(tx gen.Dao)) gen.ResultInfo + ReplaceDB(db *gorm.DB) + ReadDB() IRecycleBinDo + WriteDB() IRecycleBinDo + As(alias string) gen.Dao + Session(config *gorm.Session) IRecycleBinDo + Columns(cols ...field.Expr) gen.Columns + Clauses(conds ...clause.Expression) IRecycleBinDo + Not(conds ...gen.Condition) IRecycleBinDo + Or(conds ...gen.Condition) IRecycleBinDo + Select(conds ...field.Expr) IRecycleBinDo + Where(conds ...gen.Condition) IRecycleBinDo + Order(conds ...field.Expr) IRecycleBinDo + Distinct(cols ...field.Expr) IRecycleBinDo + Omit(cols ...field.Expr) IRecycleBinDo + Join(table schema.Tabler, on ...field.Expr) IRecycleBinDo + LeftJoin(table schema.Tabler, on ...field.Expr) IRecycleBinDo + RightJoin(table schema.Tabler, on ...field.Expr) IRecycleBinDo + Group(cols ...field.Expr) IRecycleBinDo + Having(conds ...gen.Condition) IRecycleBinDo + Limit(limit int) IRecycleBinDo + Offset(offset int) IRecycleBinDo + Count() (count int64, err error) + Scopes(funcs ...func(gen.Dao) gen.Dao) IRecycleBinDo + Unscoped() IRecycleBinDo + Create(values ...*entity.RecycleBin) error + CreateInBatches(values []*entity.RecycleBin, batchSize int) error + Save(values ...*entity.RecycleBin) error + First() (*entity.RecycleBin, error) + Take() (*entity.RecycleBin, error) + Last() (*entity.RecycleBin, error) + Find() ([]*entity.RecycleBin, error) + FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*entity.RecycleBin, err error) + FindInBatches(result *[]*entity.RecycleBin, batchSize int, fc func(tx gen.Dao, batch int) error) error + Pluck(column field.Expr, dest interface{}) error + Delete(...*entity.RecycleBin) (info gen.ResultInfo, err error) + Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error) + UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error) + Updates(value interface{}) (info gen.ResultInfo, err error) + UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error) + UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error) + UpdateColumns(value interface{}) (info gen.ResultInfo, err error) + UpdateFrom(q gen.SubQuery) gen.Dao + Attrs(attrs ...field.AssignExpr) IRecycleBinDo + Assign(attrs ...field.AssignExpr) IRecycleBinDo + Joins(fields ...field.RelationField) IRecycleBinDo + Preload(fields ...field.RelationField) IRecycleBinDo + FirstOrInit() (*entity.RecycleBin, error) + FirstOrCreate() (*entity.RecycleBin, error) + FindByPage(offset int, limit int) (result []*entity.RecycleBin, count int64, err error) + ScanByPage(result interface{}, offset int, limit int) (count int64, err error) + Scan(result interface{}) (err error) + Returning(value interface{}, columns ...string) IRecycleBinDo + UnderlyingDB() *gorm.DB + schema.Tabler +} + +func (r recycleBinDo) Debug() IRecycleBinDo { + return r.withDO(r.DO.Debug()) +} + +func (r recycleBinDo) WithContext(ctx context.Context) IRecycleBinDo { + return r.withDO(r.DO.WithContext(ctx)) +} + +func (r recycleBinDo) ReadDB() IRecycleBinDo { + return r.Clauses(dbresolver.Read) +} + +func (r recycleBinDo) WriteDB() IRecycleBinDo { + return r.Clauses(dbresolver.Write) +} + +func (r recycleBinDo) Session(config *gorm.Session) IRecycleBinDo { + return r.withDO(r.DO.Session(config)) +} + +func (r recycleBinDo) Clauses(conds ...clause.Expression) IRecycleBinDo { + return r.withDO(r.DO.Clauses(conds...)) +} + +func (r recycleBinDo) Returning(value interface{}, columns ...string) IRecycleBinDo { + return r.withDO(r.DO.Returning(value, columns...)) +} + +func (r recycleBinDo) Not(conds ...gen.Condition) IRecycleBinDo { + return r.withDO(r.DO.Not(conds...)) +} + +func (r recycleBinDo) Or(conds ...gen.Condition) IRecycleBinDo { + return r.withDO(r.DO.Or(conds...)) +} + +func (r recycleBinDo) Select(conds ...field.Expr) IRecycleBinDo { + return r.withDO(r.DO.Select(conds...)) +} + +func (r recycleBinDo) Where(conds ...gen.Condition) IRecycleBinDo { + return r.withDO(r.DO.Where(conds...)) +} + +func (r recycleBinDo) Order(conds ...field.Expr) IRecycleBinDo { + return r.withDO(r.DO.Order(conds...)) +} + +func (r recycleBinDo) Distinct(cols ...field.Expr) IRecycleBinDo { + return r.withDO(r.DO.Distinct(cols...)) +} + +func (r recycleBinDo) Omit(cols ...field.Expr) IRecycleBinDo { + return r.withDO(r.DO.Omit(cols...)) +} + +func (r recycleBinDo) Join(table schema.Tabler, on ...field.Expr) IRecycleBinDo { + return r.withDO(r.DO.Join(table, on...)) +} + +func (r recycleBinDo) LeftJoin(table schema.Tabler, on ...field.Expr) IRecycleBinDo { + return r.withDO(r.DO.LeftJoin(table, on...)) +} + +func (r recycleBinDo) RightJoin(table schema.Tabler, on ...field.Expr) IRecycleBinDo { + return r.withDO(r.DO.RightJoin(table, on...)) +} + +func (r recycleBinDo) Group(cols ...field.Expr) IRecycleBinDo { + return r.withDO(r.DO.Group(cols...)) +} + +func (r recycleBinDo) Having(conds ...gen.Condition) IRecycleBinDo { + return r.withDO(r.DO.Having(conds...)) +} + +func (r recycleBinDo) Limit(limit int) IRecycleBinDo { + return r.withDO(r.DO.Limit(limit)) +} + +func (r recycleBinDo) Offset(offset int) IRecycleBinDo { + return r.withDO(r.DO.Offset(offset)) +} + +func (r recycleBinDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IRecycleBinDo { + return r.withDO(r.DO.Scopes(funcs...)) +} + +func (r recycleBinDo) Unscoped() IRecycleBinDo { + return r.withDO(r.DO.Unscoped()) +} + +func (r recycleBinDo) Create(values ...*entity.RecycleBin) error { + if len(values) == 0 { + return nil + } + return r.DO.Create(values) +} + +func (r recycleBinDo) CreateInBatches(values []*entity.RecycleBin, batchSize int) error { + return r.DO.CreateInBatches(values, batchSize) +} + +// Save : !!! underlying implementation is different with GORM +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) +func (r recycleBinDo) Save(values ...*entity.RecycleBin) error { + if len(values) == 0 { + return nil + } + return r.DO.Save(values) +} + +func (r recycleBinDo) First() (*entity.RecycleBin, error) { + if result, err := r.DO.First(); err != nil { + return nil, err + } else { + return result.(*entity.RecycleBin), nil + } +} + +func (r recycleBinDo) Take() (*entity.RecycleBin, error) { + if result, err := r.DO.Take(); err != nil { + return nil, err + } else { + return result.(*entity.RecycleBin), nil + } +} + +func (r recycleBinDo) Last() (*entity.RecycleBin, error) { + if result, err := r.DO.Last(); err != nil { + return nil, err + } else { + return result.(*entity.RecycleBin), nil + } +} + +func (r recycleBinDo) Find() ([]*entity.RecycleBin, error) { + result, err := r.DO.Find() + return result.([]*entity.RecycleBin), err +} + +func (r recycleBinDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*entity.RecycleBin, err error) { + buf := make([]*entity.RecycleBin, 0, batchSize) + err = r.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { + defer func() { results = append(results, buf...) }() + return fc(tx, batch) + }) + return results, err +} + +func (r recycleBinDo) FindInBatches(result *[]*entity.RecycleBin, batchSize int, fc func(tx gen.Dao, batch int) error) error { + return r.DO.FindInBatches(result, batchSize, fc) +} + +func (r recycleBinDo) Attrs(attrs ...field.AssignExpr) IRecycleBinDo { + return r.withDO(r.DO.Attrs(attrs...)) +} + +func (r recycleBinDo) Assign(attrs ...field.AssignExpr) IRecycleBinDo { + return r.withDO(r.DO.Assign(attrs...)) +} + +func (r recycleBinDo) Joins(fields ...field.RelationField) IRecycleBinDo { + for _, _f := range fields { + r = *r.withDO(r.DO.Joins(_f)) + } + return &r +} + +func (r recycleBinDo) Preload(fields ...field.RelationField) IRecycleBinDo { + for _, _f := range fields { + r = *r.withDO(r.DO.Preload(_f)) + } + return &r +} + +func (r recycleBinDo) FirstOrInit() (*entity.RecycleBin, error) { + if result, err := r.DO.FirstOrInit(); err != nil { + return nil, err + } else { + return result.(*entity.RecycleBin), nil + } +} + +func (r recycleBinDo) FirstOrCreate() (*entity.RecycleBin, error) { + if result, err := r.DO.FirstOrCreate(); err != nil { + return nil, err + } else { + return result.(*entity.RecycleBin), nil + } +} + +func (r recycleBinDo) FindByPage(offset int, limit int) (result []*entity.RecycleBin, count int64, err error) { + result, err = r.Offset(offset).Limit(limit).Find() + if err != nil { + return + } + + if size := len(result); 0 < limit && 0 < size && size < limit { + count = int64(size + offset) + return + } + + count, err = r.Offset(-1).Limit(-1).Count() + return +} + +func (r recycleBinDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { + count, err = r.Count() + if err != nil { + return + } + + err = r.Offset(offset).Limit(limit).Scan(result) + return +} + +func (r recycleBinDo) Scan(result interface{}) (err error) { + return r.DO.Scan(result) +} + +func (r recycleBinDo) Delete(models ...*entity.RecycleBin) (result gen.ResultInfo, err error) { + return r.DO.Delete(models) +} + +func (r *recycleBinDo) withDO(do gen.Dao) *recycleBinDo { + r.DO = *do.(*gen.DO) + return r +} diff --git a/internal/app/repo/query/zp_storage.gen.go b/internal/app/repo/query/zp_storage.gen.go new file mode 100644 index 0000000..c6935f5 --- /dev/null +++ b/internal/app/repo/query/zp_storage.gen.go @@ -0,0 +1,448 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package query + +import ( + "context" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/schema" + + "gorm.io/gen" + "gorm.io/gen/field" + + "gorm.io/plugin/dbresolver" + + "github.com/saltbo/zpan/internal/app/entity" +) + +func newStorage(db *gorm.DB, opts ...gen.DOOption) storage { + _storage := storage{} + + _storage.storageDo.UseDB(db, opts...) + _storage.storageDo.UseModel(&entity.Storage{}) + + tableName := _storage.storageDo.TableName() + _storage.ALL = field.NewAsterisk(tableName) + _storage.Id = field.NewInt64(tableName, "id") + _storage.Mode = field.NewInt8(tableName, "mode") + _storage.Name = field.NewString(tableName, "name") + _storage.Title = field.NewString(tableName, "title") + _storage.IDirs = field.NewString(tableName, "idirs") + _storage.Bucket = field.NewString(tableName, "bucket") + _storage.Provider = field.NewString(tableName, "provider") + _storage.Endpoint = field.NewString(tableName, "endpoint") + _storage.Region = field.NewString(tableName, "region") + _storage.AccessKey = field.NewString(tableName, "access_key") + _storage.SecretKey = field.NewString(tableName, "secret_key") + _storage.CustomHost = field.NewString(tableName, "custom_host") + _storage.RootPath = field.NewString(tableName, "root_path") + _storage.FilePath = field.NewString(tableName, "file_path") + _storage.Status = field.NewInt8(tableName, "status") + _storage.Created = field.NewTime(tableName, "created") + _storage.Updated = field.NewTime(tableName, "updated") + _storage.Deleted = field.NewField(tableName, "deleted") + + _storage.fillFieldMap() + + return _storage +} + +type storage struct { + storageDo + + ALL field.Asterisk + Id field.Int64 + Mode field.Int8 + Name field.String + Title field.String + IDirs field.String + Bucket field.String + Provider field.String + Endpoint field.String + Region field.String + AccessKey field.String + SecretKey field.String + CustomHost field.String + RootPath field.String + FilePath field.String + Status field.Int8 + Created field.Time + Updated field.Time + Deleted field.Field + + fieldMap map[string]field.Expr +} + +func (s storage) Table(newTableName string) *storage { + s.storageDo.UseTable(newTableName) + return s.updateTableName(newTableName) +} + +func (s storage) As(alias string) *storage { + s.storageDo.DO = *(s.storageDo.As(alias).(*gen.DO)) + return s.updateTableName(alias) +} + +func (s *storage) updateTableName(table string) *storage { + s.ALL = field.NewAsterisk(table) + s.Id = field.NewInt64(table, "id") + s.Mode = field.NewInt8(table, "mode") + s.Name = field.NewString(table, "name") + s.Title = field.NewString(table, "title") + s.IDirs = field.NewString(table, "idirs") + s.Bucket = field.NewString(table, "bucket") + s.Provider = field.NewString(table, "provider") + s.Endpoint = field.NewString(table, "endpoint") + s.Region = field.NewString(table, "region") + s.AccessKey = field.NewString(table, "access_key") + s.SecretKey = field.NewString(table, "secret_key") + s.CustomHost = field.NewString(table, "custom_host") + s.RootPath = field.NewString(table, "root_path") + s.FilePath = field.NewString(table, "file_path") + s.Status = field.NewInt8(table, "status") + s.Created = field.NewTime(table, "created") + s.Updated = field.NewTime(table, "updated") + s.Deleted = field.NewField(table, "deleted") + + s.fillFieldMap() + + return s +} + +func (s *storage) GetFieldByName(fieldName string) (field.OrderExpr, bool) { + _f, ok := s.fieldMap[fieldName] + if !ok || _f == nil { + return nil, false + } + _oe, ok := _f.(field.OrderExpr) + return _oe, ok +} + +func (s *storage) fillFieldMap() { + s.fieldMap = make(map[string]field.Expr, 18) + s.fieldMap["id"] = s.Id + s.fieldMap["mode"] = s.Mode + s.fieldMap["name"] = s.Name + s.fieldMap["title"] = s.Title + s.fieldMap["idirs"] = s.IDirs + s.fieldMap["bucket"] = s.Bucket + s.fieldMap["provider"] = s.Provider + s.fieldMap["endpoint"] = s.Endpoint + s.fieldMap["region"] = s.Region + s.fieldMap["access_key"] = s.AccessKey + s.fieldMap["secret_key"] = s.SecretKey + s.fieldMap["custom_host"] = s.CustomHost + s.fieldMap["root_path"] = s.RootPath + s.fieldMap["file_path"] = s.FilePath + s.fieldMap["status"] = s.Status + s.fieldMap["created"] = s.Created + s.fieldMap["updated"] = s.Updated + s.fieldMap["deleted"] = s.Deleted +} + +func (s storage) clone(db *gorm.DB) storage { + s.storageDo.ReplaceConnPool(db.Statement.ConnPool) + return s +} + +func (s storage) replaceDB(db *gorm.DB) storage { + s.storageDo.ReplaceDB(db) + return s +} + +type storageDo struct{ gen.DO } + +type IStorageDo interface { + gen.SubQuery + Debug() IStorageDo + WithContext(ctx context.Context) IStorageDo + WithResult(fc func(tx gen.Dao)) gen.ResultInfo + ReplaceDB(db *gorm.DB) + ReadDB() IStorageDo + WriteDB() IStorageDo + As(alias string) gen.Dao + Session(config *gorm.Session) IStorageDo + Columns(cols ...field.Expr) gen.Columns + Clauses(conds ...clause.Expression) IStorageDo + Not(conds ...gen.Condition) IStorageDo + Or(conds ...gen.Condition) IStorageDo + Select(conds ...field.Expr) IStorageDo + Where(conds ...gen.Condition) IStorageDo + Order(conds ...field.Expr) IStorageDo + Distinct(cols ...field.Expr) IStorageDo + Omit(cols ...field.Expr) IStorageDo + Join(table schema.Tabler, on ...field.Expr) IStorageDo + LeftJoin(table schema.Tabler, on ...field.Expr) IStorageDo + RightJoin(table schema.Tabler, on ...field.Expr) IStorageDo + Group(cols ...field.Expr) IStorageDo + Having(conds ...gen.Condition) IStorageDo + Limit(limit int) IStorageDo + Offset(offset int) IStorageDo + Count() (count int64, err error) + Scopes(funcs ...func(gen.Dao) gen.Dao) IStorageDo + Unscoped() IStorageDo + Create(values ...*entity.Storage) error + CreateInBatches(values []*entity.Storage, batchSize int) error + Save(values ...*entity.Storage) error + First() (*entity.Storage, error) + Take() (*entity.Storage, error) + Last() (*entity.Storage, error) + Find() ([]*entity.Storage, error) + FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*entity.Storage, err error) + FindInBatches(result *[]*entity.Storage, batchSize int, fc func(tx gen.Dao, batch int) error) error + Pluck(column field.Expr, dest interface{}) error + Delete(...*entity.Storage) (info gen.ResultInfo, err error) + Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error) + UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error) + Updates(value interface{}) (info gen.ResultInfo, err error) + UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error) + UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error) + UpdateColumns(value interface{}) (info gen.ResultInfo, err error) + UpdateFrom(q gen.SubQuery) gen.Dao + Attrs(attrs ...field.AssignExpr) IStorageDo + Assign(attrs ...field.AssignExpr) IStorageDo + Joins(fields ...field.RelationField) IStorageDo + Preload(fields ...field.RelationField) IStorageDo + FirstOrInit() (*entity.Storage, error) + FirstOrCreate() (*entity.Storage, error) + FindByPage(offset int, limit int) (result []*entity.Storage, count int64, err error) + ScanByPage(result interface{}, offset int, limit int) (count int64, err error) + Scan(result interface{}) (err error) + Returning(value interface{}, columns ...string) IStorageDo + UnderlyingDB() *gorm.DB + schema.Tabler +} + +func (s storageDo) Debug() IStorageDo { + return s.withDO(s.DO.Debug()) +} + +func (s storageDo) WithContext(ctx context.Context) IStorageDo { + return s.withDO(s.DO.WithContext(ctx)) +} + +func (s storageDo) ReadDB() IStorageDo { + return s.Clauses(dbresolver.Read) +} + +func (s storageDo) WriteDB() IStorageDo { + return s.Clauses(dbresolver.Write) +} + +func (s storageDo) Session(config *gorm.Session) IStorageDo { + return s.withDO(s.DO.Session(config)) +} + +func (s storageDo) Clauses(conds ...clause.Expression) IStorageDo { + return s.withDO(s.DO.Clauses(conds...)) +} + +func (s storageDo) Returning(value interface{}, columns ...string) IStorageDo { + return s.withDO(s.DO.Returning(value, columns...)) +} + +func (s storageDo) Not(conds ...gen.Condition) IStorageDo { + return s.withDO(s.DO.Not(conds...)) +} + +func (s storageDo) Or(conds ...gen.Condition) IStorageDo { + return s.withDO(s.DO.Or(conds...)) +} + +func (s storageDo) Select(conds ...field.Expr) IStorageDo { + return s.withDO(s.DO.Select(conds...)) +} + +func (s storageDo) Where(conds ...gen.Condition) IStorageDo { + return s.withDO(s.DO.Where(conds...)) +} + +func (s storageDo) Order(conds ...field.Expr) IStorageDo { + return s.withDO(s.DO.Order(conds...)) +} + +func (s storageDo) Distinct(cols ...field.Expr) IStorageDo { + return s.withDO(s.DO.Distinct(cols...)) +} + +func (s storageDo) Omit(cols ...field.Expr) IStorageDo { + return s.withDO(s.DO.Omit(cols...)) +} + +func (s storageDo) Join(table schema.Tabler, on ...field.Expr) IStorageDo { + return s.withDO(s.DO.Join(table, on...)) +} + +func (s storageDo) LeftJoin(table schema.Tabler, on ...field.Expr) IStorageDo { + return s.withDO(s.DO.LeftJoin(table, on...)) +} + +func (s storageDo) RightJoin(table schema.Tabler, on ...field.Expr) IStorageDo { + return s.withDO(s.DO.RightJoin(table, on...)) +} + +func (s storageDo) Group(cols ...field.Expr) IStorageDo { + return s.withDO(s.DO.Group(cols...)) +} + +func (s storageDo) Having(conds ...gen.Condition) IStorageDo { + return s.withDO(s.DO.Having(conds...)) +} + +func (s storageDo) Limit(limit int) IStorageDo { + return s.withDO(s.DO.Limit(limit)) +} + +func (s storageDo) Offset(offset int) IStorageDo { + return s.withDO(s.DO.Offset(offset)) +} + +func (s storageDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IStorageDo { + return s.withDO(s.DO.Scopes(funcs...)) +} + +func (s storageDo) Unscoped() IStorageDo { + return s.withDO(s.DO.Unscoped()) +} + +func (s storageDo) Create(values ...*entity.Storage) error { + if len(values) == 0 { + return nil + } + return s.DO.Create(values) +} + +func (s storageDo) CreateInBatches(values []*entity.Storage, batchSize int) error { + return s.DO.CreateInBatches(values, batchSize) +} + +// Save : !!! underlying implementation is different with GORM +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) +func (s storageDo) Save(values ...*entity.Storage) error { + if len(values) == 0 { + return nil + } + return s.DO.Save(values) +} + +func (s storageDo) First() (*entity.Storage, error) { + if result, err := s.DO.First(); err != nil { + return nil, err + } else { + return result.(*entity.Storage), nil + } +} + +func (s storageDo) Take() (*entity.Storage, error) { + if result, err := s.DO.Take(); err != nil { + return nil, err + } else { + return result.(*entity.Storage), nil + } +} + +func (s storageDo) Last() (*entity.Storage, error) { + if result, err := s.DO.Last(); err != nil { + return nil, err + } else { + return result.(*entity.Storage), nil + } +} + +func (s storageDo) Find() ([]*entity.Storage, error) { + result, err := s.DO.Find() + return result.([]*entity.Storage), err +} + +func (s storageDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*entity.Storage, err error) { + buf := make([]*entity.Storage, 0, batchSize) + err = s.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { + defer func() { results = append(results, buf...) }() + return fc(tx, batch) + }) + return results, err +} + +func (s storageDo) FindInBatches(result *[]*entity.Storage, batchSize int, fc func(tx gen.Dao, batch int) error) error { + return s.DO.FindInBatches(result, batchSize, fc) +} + +func (s storageDo) Attrs(attrs ...field.AssignExpr) IStorageDo { + return s.withDO(s.DO.Attrs(attrs...)) +} + +func (s storageDo) Assign(attrs ...field.AssignExpr) IStorageDo { + return s.withDO(s.DO.Assign(attrs...)) +} + +func (s storageDo) Joins(fields ...field.RelationField) IStorageDo { + for _, _f := range fields { + s = *s.withDO(s.DO.Joins(_f)) + } + return &s +} + +func (s storageDo) Preload(fields ...field.RelationField) IStorageDo { + for _, _f := range fields { + s = *s.withDO(s.DO.Preload(_f)) + } + return &s +} + +func (s storageDo) FirstOrInit() (*entity.Storage, error) { + if result, err := s.DO.FirstOrInit(); err != nil { + return nil, err + } else { + return result.(*entity.Storage), nil + } +} + +func (s storageDo) FirstOrCreate() (*entity.Storage, error) { + if result, err := s.DO.FirstOrCreate(); err != nil { + return nil, err + } else { + return result.(*entity.Storage), nil + } +} + +func (s storageDo) FindByPage(offset int, limit int) (result []*entity.Storage, count int64, err error) { + result, err = s.Offset(offset).Limit(limit).Find() + if err != nil { + return + } + + if size := len(result); 0 < limit && 0 < size && size < limit { + count = int64(size + offset) + return + } + + count, err = s.Offset(-1).Limit(-1).Count() + return +} + +func (s storageDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { + count, err = s.Count() + if err != nil { + return + } + + err = s.Offset(offset).Limit(limit).Scan(result) + return +} + +func (s storageDo) Scan(result interface{}) (err error) { + return s.DO.Scan(result) +} + +func (s storageDo) Delete(models ...*entity.Storage) (result gen.ResultInfo, err error) { + return s.DO.Delete(models) +} + +func (s *storageDo) withDO(do gen.Dao) *storageDo { + s.DO = *do.(*gen.DO) + return s +} diff --git a/internal/app/repo/recyclebin.go b/internal/app/repo/recyclebin.go new file mode 100644 index 0000000..86f79dd --- /dev/null +++ b/internal/app/repo/recyclebin.go @@ -0,0 +1,59 @@ +package repo + +import ( + "context" + + "github.com/saltbo/zpan/internal/app/entity" + "github.com/saltbo/zpan/internal/app/repo/query" +) + +type RecycleBinFindOptions struct { + QueryPage + + Sid int64 +} + +type RecycleBin interface { + Reader[*entity.RecycleBin, string, *RecycleBinFindOptions] + Creator[*entity.RecycleBin] + Deleter[string] +} + +var _ RecycleBin = (*RecycleBinDBQuery)(nil) + +type RecycleBinDBQuery struct { + q *query.Query +} + +func NewRecycleBinDBQuery(q *query.Query) *RecycleBinDBQuery { + return &RecycleBinDBQuery{q: q} +} + +func (r *RecycleBinDBQuery) Find(ctx context.Context, alias string) (*entity.RecycleBin, error) { + return r.q.RecycleBin.WithContext(ctx).Where(r.q.RecycleBin.Alias_.Eq(alias)).First() +} + +func (r *RecycleBinDBQuery) FindAll(ctx context.Context, opts *RecycleBinFindOptions) (rows []*entity.RecycleBin, total int64, err error) { + q := r.q.RecycleBin.WithContext(ctx).Where(r.q.RecycleBin.Sid.Eq(opts.Sid)).Order(r.q.RecycleBin.Id.Desc()) + + if opts.Limit == 0 { + rows, err = q.Find() + return + } + + return q.FindByPage(opts.Offset, opts.Limit) +} + +func (r *RecycleBinDBQuery) Create(ctx context.Context, m *entity.RecycleBin) error { + return r.q.RecycleBin.WithContext(ctx).Create(m) +} + +func (r *RecycleBinDBQuery) Delete(ctx context.Context, alias string) error { + m, err := r.Find(ctx, alias) + if err != nil { + return err + } + + _, err = r.q.RecycleBin.WithContext(ctx).Delete(m) + return err +} diff --git a/internal/app/repo/storage.go b/internal/app/repo/storage.go new file mode 100644 index 0000000..578ddc1 --- /dev/null +++ b/internal/app/repo/storage.go @@ -0,0 +1,71 @@ +package repo + +import ( + "context" + "errors" + "fmt" + + "github.com/saltbo/zpan/internal/app/entity" + "github.com/saltbo/zpan/internal/app/repo/query" + "gorm.io/gorm" +) + +type StorageFindOptions struct { + Offset int + Limit int +} + +type Storage interface { + BasicOP[*entity.Storage, int64, *StorageFindOptions] +} + +var _ Storage = (*StorageDBQuery)(nil) + +type StorageDBQuery struct { + q *query.Query +} + +func NewStorageDBQuery(q *query.Query) *StorageDBQuery { + return &StorageDBQuery{q: q} +} + +func (s *StorageDBQuery) Find(ctx context.Context, id int64) (*entity.Storage, error) { + return s.q.Storage.WithContext(ctx).Where(s.q.Storage.Id.Eq(id)).First() +} + +func (s *StorageDBQuery) FindAll(ctx context.Context, opts *StorageFindOptions) (storages []*entity.Storage, total int64, err error) { + return s.q.Storage.WithContext(ctx).FindByPage(opts.Offset, opts.Limit) +} + +func (s *StorageDBQuery) Create(ctx context.Context, storage *entity.Storage) error { + if _, err := s.q.Storage.Where(s.q.Storage.Name.Eq(storage.Name)).First(); !errors.Is(err, gorm.ErrRecordNotFound) { + return fmt.Errorf("storage already exist") + } + + return s.q.Storage.WithContext(ctx).Create(storage) +} + +func (s *StorageDBQuery) Update(ctx context.Context, id int64, storage *entity.Storage) error { + existStorage := new(entity.Storage) + if _, err := s.Find(ctx, id); errors.Is(err, gorm.ErrRecordNotFound) { + return fmt.Errorf("storage not found") + } + + storage.Id = id + // 如果SK没有发生改变则不允许更新SK,避免改错SK + if storage.SecretKey == existStorage.SKAsterisk() { + storage.SecretKey = existStorage.SecretKey + } + + return s.q.Storage.WithContext(ctx).Save(storage) +} + +func (s *StorageDBQuery) Delete(ctx context.Context, id int64) error { + storage := new(entity.Storage) + if _, err := s.Find(ctx, id); errors.Is(err, gorm.ErrRecordNotFound) { + return fmt.Errorf("storage not exist") + } + + _, err := s.q.Storage.WithContext(ctx).Delete(storage) + return err +} diff --git a/internal/app/repo/wire.go b/internal/app/repo/wire.go new file mode 100644 index 0000000..51e42fe --- /dev/null +++ b/internal/app/repo/wire.go @@ -0,0 +1,24 @@ +package repo + +import "github.com/google/wire" + +type Repository struct { + Storage Storage + Matter Matter + RecycleBin RecycleBin +} + +func NewRepository(storage Storage, matter Matter, recycleBin RecycleBin) *Repository { + return &Repository{Storage: storage, Matter: matter, RecycleBin: recycleBin} +} + +var ProviderSet = wire.NewSet( + NewStorageDBQuery, + NewMatterDBQuery, + NewRecycleBinDBQuery, + + wire.Bind(new(Storage), new(*StorageDBQuery)), + wire.Bind(new(Matter), new(*MatterDBQuery)), + wire.Bind(new(RecycleBin), new(*RecycleBinDBQuery)), + NewRepository, +) diff --git a/internal/app/server.go b/internal/app/server.go new file mode 100644 index 0000000..2557378 --- /dev/null +++ b/internal/app/server.go @@ -0,0 +1,42 @@ +//go:build wireinject +// +build wireinject + +package app + +import ( + "fmt" + + "github.com/gin-gonic/gin" + "github.com/google/wire" + "github.com/saltbo/gopkg/ginutil" + "github.com/saltbo/zpan/internal/app/api" + "github.com/saltbo/zpan/internal/app/dao" + "github.com/saltbo/zpan/internal/app/repo" + "github.com/saltbo/zpan/internal/app/usecase" + "github.com/saltbo/zpan/web" + "github.com/spf13/viper" +) + +type Server struct { + uc *usecase.Repository + rp *repo.Repository + ap *api.Repository +} + +func newServer(rp *repo.Repository, uc *usecase.Repository, ap *api.Repository) *Server { + return &Server{rp: rp, uc: uc, ap: ap} +} + +func NewServer() *Server { + wire.Build(dao.GetDBQuery, repo.ProviderSet, usecase.ProviderSet, api.ProviderSet, newServer) + return &Server{} +} + +func (s *Server) Run() error { + // gin.SetMode(gin.ReleaseMode) + ge := gin.Default() + api.SetupRoutes(ge, s.ap) + web.SetupRoutes(ge) + ginutil.Startup(ge, fmt.Sprintf(":%d", viper.GetInt("port"))) + return nil +} diff --git a/internal/app/service/recyclebin.go b/internal/app/service/recyclebin.go deleted file mode 100644 index 90b5f09..0000000 --- a/internal/app/service/recyclebin.go +++ /dev/null @@ -1,134 +0,0 @@ -package service - -import ( - "fmt" - - "github.com/saltbo/zpan/internal/app/dao" - "github.com/saltbo/zpan/internal/app/model" -) - -type RecycleBin struct { - dMatter *dao.Matter - dRecycleBin *dao.RecycleBin - - sStorage *Storage -} - -func NewRecycleBin() *RecycleBin { - return &RecycleBin{ - dMatter: dao.NewMatter(), - dRecycleBin: dao.NewRecycleBin(), - - sStorage: NewStorage(), - } -} - -func (rb *RecycleBin) FindAll(uid int64, sid int64, offset int, limit int) (list []model.Recycle, total int64, err error) { - query := dao.NewQuery() - query.WithEq("uid", uid) - query.WithEq("sid", sid) - query.Offset = offset - query.Limit = limit - return rb.dRecycleBin.FindAll(query) -} - -func (rb *RecycleBin) Recovery(uid int64, alias string) error { - m, err := rb.dRecycleBin.Find(uid, alias) - if err != nil { - return err - } - - return rb.dMatter.Recovery(m) -} - -func (rb *RecycleBin) Delete(uid int64, alias string) error { - m, err := rb.dRecycleBin.Find(uid, alias) - if err != nil { - return err - } - - provider, err := rb.sStorage.GetProvider(m.Sid) - if err != nil { - return err - } - - if !m.IsDir() { - // delete the remote object - if err := provider.ObjectDelete(m.Object); err != nil { - return err - } - } else { - // get all files removed to the recycle bin - children, err := rb.dMatter.UnscopedChildren(m.Uid, alias) - if err != nil { - return err - } - - objects := make([]string, 0, len(children)) - for _, child := range children { - if child.IsDir() { - continue - } - - m.Size += child.Size // calc all the space occupied by the folder - objects = append(objects, child.Object) - } - - // delete the remote objects - if err := provider.ObjectsDelete(objects); err != nil { - return err - } - } - - return rb.dRecycleBin.Release(m.Uid, m.Size, "alias=?", m.Alias) -} - -func (rb *RecycleBin) Clean(uid, sid int64) error { - query := dao.NewQuery() - query.WithEq("uid", uid) - query.WithEq("sid", sid) - rbs, _, err := rb.dRecycleBin.FindAll(query) - if err != nil { - return err - } - - var size int64 - objects := make([]string, 0) - for _, recycle := range rbs { - if recycle.Size > 0 { - size += recycle.Size - objects = append(objects, recycle.Object) - continue - } else if recycle.DirType > model.DirTypeSys { - children, err := rb.dMatter.UnscopedChildren(recycle.Uid, recycle.Alias) - if err != nil { - return err - } - - for _, child := range children { - if child.IsDir() { - continue - } - - objects = append(objects, child.Object) - size += child.Size - } - } - } - - if len(objects) == 0 { - return fmt.Errorf("empty objects") - } - - provider, err := rb.sStorage.GetProvider(sid) - if err != nil { - return err - } - - //delete the remote object - if err := provider.ObjectsDelete(objects); err != nil { - return err - } - - return rb.dRecycleBin.Release(uid, size, "uid=?", uid) -} diff --git a/internal/app/service/storage.go b/internal/app/service/storage.go deleted file mode 100644 index 90d7e0d..0000000 --- a/internal/app/service/storage.go +++ /dev/null @@ -1,74 +0,0 @@ -package service - -import ( - "github.com/saltbo/zpan/internal/app/dao" - "github.com/saltbo/zpan/internal/app/model" - "github.com/saltbo/zpan/internal/pkg/provider" -) - -type Storage struct { - dStorage *dao.Storage -} - -func NewStorage() *Storage { - return &Storage{ - dStorage: dao.NewStorage(), - } -} - -func (s *Storage) Create(storage *model.Storage) error { - p, err := provider.New(s.buildConfig(storage)) - if err != nil { - return err - } - - if err := p.SetupCORS(); err != nil { - return err - } - - return s.dStorage.Create(storage) -} - -func (s *Storage) Get(id interface{}) (*model.Storage, error) { - // fixme: 单元测试mock侵入了业务代码,有没有更好的办法? - if sid, ok := id.(int64); ok && sid == 0 { - return &model.Storage{}, nil - } - - return s.dStorage.Find(id) -} - -func (s *Storage) GetProvider(id interface{}) (provider.Provider, error) { - // fixme: 单元测试mock侵入了业务代码,有没有更好的办法? - if sid, ok := id.(int64); ok && sid == 0 { - return &provider.MockProvider{}, nil - } - - storage, err := s.Get(id) - if err != nil { - return nil, err - } - - return s.GetProviderByStorage(storage) -} - -func (s *Storage) GetProviderByStorage(storage *model.Storage) (provider.Provider, error) { - // fixme: 单元测试mock侵入了业务代码,有没有更好的办法? - if storage.Id == 0 { - return &provider.MockProvider{}, nil - } - - return provider.New(s.buildConfig(storage)) -} - -func (s *Storage) buildConfig(storage *model.Storage) *provider.Config { - return &provider.Config{ - Provider: storage.Provider, - Bucket: storage.Bucket, - Endpoint: storage.Endpoint, - Region: storage.Region, - CustomHost: storage.CustomHost, - AccessKey: storage.AccessKey, - AccessSecret: storage.SecretKey, - } -} diff --git a/internal/app/usecase/storage/cloud_storage.go b/internal/app/usecase/storage/cloud_storage.go new file mode 100644 index 0000000..5f72739 --- /dev/null +++ b/internal/app/usecase/storage/cloud_storage.go @@ -0,0 +1,67 @@ +package storage + +import ( + "context" + + "github.com/saltbo/zpan/internal/app/entity" + "github.com/saltbo/zpan/internal/app/repo" + "github.com/saltbo/zpan/internal/pkg/provider" +) + +var _ Storage = (*CloudStorage)(nil) + +type CloudStorage struct { + storageRepo repo.Storage + + providerConstructor provider.Constructor +} + +func NewCloudStorage(storageRepo repo.Storage) *CloudStorage { + return &CloudStorage{storageRepo: storageRepo, providerConstructor: provider.New} +} + +func NewCloudStorageWithProviderConstructor(storageRepo repo.Storage, providerConstructor provider.Constructor) *CloudStorage { + return &CloudStorage{storageRepo: storageRepo, providerConstructor: providerConstructor} +} + +func (s *CloudStorage) Create(ctx context.Context, storage *entity.Storage) error { + p, err := s.providerConstructor(s.buildConfig(storage)) + if err != nil { + return err + } + + if err := p.SetupCORS(); err != nil { + return err + } + + return s.storageRepo.Create(ctx, storage) +} + +func (s *CloudStorage) Get(ctx context.Context, sid int64) (*entity.Storage, error) { + return s.storageRepo.Find(ctx, sid) +} + +func (s *CloudStorage) GetProvider(ctx context.Context, sid int64) (provider.Provider, error) { + storage, err := s.storageRepo.Find(ctx, sid) + if err != nil { + return nil, err + } + + return s.GetProviderByStorage(storage) +} + +func (s *CloudStorage) GetProviderByStorage(storage *entity.Storage) (provider.Provider, error) { + return s.providerConstructor(s.buildConfig(storage)) +} + +func (s *CloudStorage) buildConfig(storage *entity.Storage) *provider.Config { + return &provider.Config{ + Provider: storage.Provider, + Bucket: storage.Bucket, + Endpoint: storage.Endpoint, + Region: storage.Region, + CustomHost: storage.CustomHost, + AccessKey: storage.AccessKey, + AccessSecret: storage.SecretKey, + } +} diff --git a/internal/app/usecase/storage/cloud_storage_test.go b/internal/app/usecase/storage/cloud_storage_test.go new file mode 100644 index 0000000..2fba73d --- /dev/null +++ b/internal/app/usecase/storage/cloud_storage_test.go @@ -0,0 +1,40 @@ +package storage + +import ( + "context" + "testing" + + "github.com/saltbo/zpan/internal/app/entity" + "github.com/saltbo/zpan/internal/mock" + "github.com/saltbo/zpan/internal/pkg/provider" + "github.com/stretchr/testify/assert" +) + +var ( + testStorage = &entity.Storage{ + Id: 9527, + Name: "test", + Title: "TEST", + } +) + +func TestCloudStorage_Create(t *testing.T) { + ctx := context.Background() + s := NewCloudStorageWithProviderConstructor(mock.NewStorage(), provider.NewMockProvider) + assert.NoError(t, s.Create(context.Background(), testStorage)) + ss, err := s.Get(ctx, testStorage.Id) + assert.NoError(t, err) + assert.Equal(t, testStorage, ss) +} + +func TestCloudStorage_GetProvider(t *testing.T) { + ctx := context.Background() + s := NewCloudStorageWithProviderConstructor(mock.NewStorage(), provider.NewMockProvider) + assert.NoError(t, s.Create(context.Background(), testStorage)) + + pp, err := s.GetProvider(ctx, testStorage.Id) + assert.NoError(t, err) + mpp, err := provider.NewMockProvider(s.buildConfig(testStorage)) + assert.NoError(t, err) + assert.Equal(t, mpp, pp) +} diff --git a/internal/app/usecase/storage/storage.go b/internal/app/usecase/storage/storage.go new file mode 100644 index 0000000..15bf6f1 --- /dev/null +++ b/internal/app/usecase/storage/storage.go @@ -0,0 +1,14 @@ +package storage + +import ( + "context" + + "github.com/saltbo/zpan/internal/app/entity" + "github.com/saltbo/zpan/internal/pkg/provider" +) + +type Storage interface { + Create(ctx context.Context, storage *entity.Storage) error + Get(ctx context.Context, sid int64) (*entity.Storage, error) + GetProvider(ctx context.Context, id int64) (provider.Provider, error) +} diff --git a/internal/app/usecase/uploader/cloud_uploader.go b/internal/app/usecase/uploader/cloud_uploader.go new file mode 100644 index 0000000..b3c9455 --- /dev/null +++ b/internal/app/usecase/uploader/cloud_uploader.go @@ -0,0 +1,78 @@ +package uploader + +import ( + "context" + "time" + + "github.com/saltbo/zpan/internal/app/entity" + "github.com/saltbo/zpan/internal/app/repo" + "github.com/saltbo/zpan/internal/app/usecase/storage" +) + +var _ Uploader = (*CloudUploader)(nil) + +type CloudUploader struct { + storage storage.Storage + matterRepo repo.Matter +} + +func NewCloudUploader(storage storage.Storage, matterRepo repo.Matter) *CloudUploader { + return &CloudUploader{storage: storage, matterRepo: matterRepo} +} + +func (u *CloudUploader) CreateUploadURL(ctx context.Context, m *entity.Matter) error { + provider, err := u.storage.GetProvider(ctx, m.Sid) + if err != nil { + return err + } + + s, err := u.storage.Get(ctx, m.Sid) + if err != nil { + return err + } + + m.BuildObject(s.RootPath, s.FilePath) + urlStr, header, err := provider.SignedPutURL(m.Object, m.Type, m.Size, s.PublicRead()) + if err != nil { + return err + } + + m.Uploader["upURL"] = urlStr + m.Uploader["upHeaders"] = header + return nil +} + +func (u *CloudUploader) CreateVisitURL(ctx context.Context, m *entity.Matter) error { + provider, err := u.storage.GetProvider(ctx, m.Sid) + if err != nil { + return err + } + + s, err := u.storage.Get(ctx, m.Sid) + if err != nil { + return err + } + + if s.PublicRead() { + m.URL = provider.PublicURL(m.Object) + return nil + } + + link, err := provider.SignedGetURL(m.Object, m.Name) + m.URL = link + return err +} + +func (u *CloudUploader) UploadDone(ctx context.Context, m *entity.Matter) error { + provider, err := u.storage.GetProvider(ctx, m.Sid) + if err != nil { + return err + } + + if _, err := provider.Head(m.Object); err != nil { + return err + } + + m.UploadedAt = time.Now() + return u.matterRepo.Update(ctx, m.Id, m) +} diff --git a/internal/app/usecase/uploader/cloud_uploader_test.go b/internal/app/usecase/uploader/cloud_uploader_test.go new file mode 100644 index 0000000..01aafa6 --- /dev/null +++ b/internal/app/usecase/uploader/cloud_uploader_test.go @@ -0,0 +1 @@ +package uploader diff --git a/internal/app/usecase/uploader/fake_uploader.go b/internal/app/usecase/uploader/fake_uploader.go new file mode 100644 index 0000000..ef85901 --- /dev/null +++ b/internal/app/usecase/uploader/fake_uploader.go @@ -0,0 +1,23 @@ +package uploader + +import ( + "context" + + "github.com/saltbo/zpan/internal/app/entity" +) + +type FakeUploader struct { + CreateUploadURLFn func(ctx context.Context, m *entity.Matter) error +} + +func (f *FakeUploader) CreateUploadURL(ctx context.Context, m *entity.Matter) error { + return f.CreateUploadURLFn(ctx, m) +} + +func (f *FakeUploader) CreateVisitURL(ctx context.Context, m *entity.Matter) error { + return nil +} + +func (f *FakeUploader) UploadDone(ctx context.Context, m *entity.Matter) error { + return nil +} diff --git a/internal/app/usecase/uploader/uploader.go b/internal/app/usecase/uploader/uploader.go new file mode 100644 index 0000000..280e223 --- /dev/null +++ b/internal/app/usecase/uploader/uploader.go @@ -0,0 +1,13 @@ +package uploader + +import ( + "context" + + "github.com/saltbo/zpan/internal/app/entity" +) + +type Uploader interface { + CreateUploadURL(ctx context.Context, m *entity.Matter) error + CreateVisitURL(ctx context.Context, m *entity.Matter) error + UploadDone(ctx context.Context, m *entity.Matter) error +} diff --git a/internal/app/usecase/vfs/interfaces.go b/internal/app/usecase/vfs/interfaces.go new file mode 100644 index 0000000..16ff2d3 --- /dev/null +++ b/internal/app/usecase/vfs/interfaces.go @@ -0,0 +1,24 @@ +package vfs + +import ( + "context" + + "github.com/saltbo/zpan/internal/app/entity" + "github.com/saltbo/zpan/internal/app/repo" +) + +type VirtualFs interface { + Create(ctx context.Context, m *entity.Matter) error + List(ctx context.Context, option *repo.MatterListOption) ([]*entity.Matter, int64, error) + Get(ctx context.Context, alias string) (*entity.Matter, error) + Rename(ctx context.Context, alias string, newName string) error + Move(ctx context.Context, alias string, to string) error + Copy(ctx context.Context, alias string, to string) (*entity.Matter, error) + Delete(ctx context.Context, alias string) error +} + +type RecycleBinFs interface { + Recovery(ctx context.Context, alias string) error + Delete(ctx context.Context, alias string) error + Clean(ctx context.Context, sid int64) error +} diff --git a/internal/app/usecase/vfs/recyclebin.go b/internal/app/usecase/vfs/recyclebin.go new file mode 100644 index 0000000..3ccde60 --- /dev/null +++ b/internal/app/usecase/vfs/recyclebin.go @@ -0,0 +1,74 @@ +package vfs + +import ( + "context" + + "github.com/saltbo/zpan/internal/app/repo" + "github.com/saltbo/zpan/internal/app/usecase/storage" +) + +var _ RecycleBinFs = (*RecycleBin)(nil) + +type RecycleBin struct { + recycleRepo repo.RecycleBin + matterRepo repo.Matter + storage storage.Storage +} + +func NewRecycleBin(recycleRepo repo.RecycleBin, matterRepo repo.Matter, storage storage.Storage) *RecycleBin { + return &RecycleBin{recycleRepo: recycleRepo, matterRepo: matterRepo, storage: storage} +} + +func (rb *RecycleBin) Recovery(ctx context.Context, alias string) error { + rbv, err := rb.recycleRepo.Find(ctx, alias) + if err != nil { + return err + } + + if err := rb.matterRepo.Recovery(ctx, rbv.Mid); err != nil { + return err + } + + return rb.recycleRepo.Delete(ctx, alias) +} + +func (rb *RecycleBin) Delete(ctx context.Context, alias string) error { + m, err := rb.recycleRepo.Find(ctx, alias) + if err != nil { + return err + } + + matter, err := rb.matterRepo.FindWith(ctx, &repo.MatterFindWithOption{Id: m.Mid, Deleted: true}) + if err != nil { + return err + } + + provider, err := rb.storage.GetProvider(ctx, matter.Sid) + if err != nil { + return err + } + + objects, _ := rb.matterRepo.GetObjects(ctx, matter.Id) + if len(objects) != 0 { + if err := provider.ObjectsDelete(objects); err != nil { + return err + } + } + + return rb.recycleRepo.Delete(ctx, alias) +} + +func (rb *RecycleBin) Clean(ctx context.Context, sid int64) error { + rbs, _, err := rb.recycleRepo.FindAll(ctx, &repo.RecycleBinFindOptions{Sid: sid}) + if err != nil { + return err + } + + for _, rbMatter := range rbs { + if err := rb.Delete(ctx, rbMatter.Alias); err != nil { + return err + } + } + + return nil +} diff --git a/internal/app/usecase/vfs/vfs.go b/internal/app/usecase/vfs/vfs.go new file mode 100644 index 0000000..76aa69d --- /dev/null +++ b/internal/app/usecase/vfs/vfs.go @@ -0,0 +1,101 @@ +package vfs + +import ( + "context" + "fmt" + "path" + + "github.com/saltbo/zpan/internal/app/entity" + "github.com/saltbo/zpan/internal/app/repo" + "github.com/saltbo/zpan/internal/app/usecase/uploader" +) + +var _ VirtualFs = (*Vfs)(nil) + +type Vfs struct { + matterRepo repo.Matter + recycleBinRepo repo.RecycleBin + uploader uploader.Uploader +} + +func NewVfs(matterRepo repo.Matter, recycleBinRepo repo.RecycleBin, uploader uploader.Uploader) *Vfs { + return &Vfs{matterRepo: matterRepo, recycleBinRepo: recycleBinRepo, uploader: uploader} +} + +func (v *Vfs) Create(ctx context.Context, m *entity.Matter) error { + if !m.IsDir() { + if err := v.uploader.CreateUploadURL(ctx, m); err != nil { + return err + } + } + + return v.matterRepo.Create(ctx, m) +} + +func (v *Vfs) List(ctx context.Context, option *repo.MatterListOption) ([]*entity.Matter, int64, error) { + return v.matterRepo.FindAll(ctx, option) +} + +func (v *Vfs) Get(ctx context.Context, alias string) (*entity.Matter, error) { + matter, err := v.matterRepo.FindByAlias(ctx, alias) + if err != nil { + return nil, err + } + + if matter.IsDir() { + return matter, nil + } + + return matter, v.uploader.CreateVisitURL(ctx, matter) +} + +func (v *Vfs) Rename(ctx context.Context, alias string, newName string) error { + m, err := v.matterRepo.FindByAlias(ctx, alias) + if err != nil { + return err + } + + if exist := v.matterRepo.PathExist(ctx, path.Join(m.Parent, newName)); exist { + return fmt.Errorf("dir already has the same name file") + } + + m.Name = newName + return v.matterRepo.Update(ctx, m.Id, m) +} + +func (v *Vfs) Move(ctx context.Context, alias string, to string) error { + m, err := v.matterRepo.FindByAlias(ctx, alias) + if err != nil { + return err + } + + if exist := v.matterRepo.PathExist(ctx, path.Join(to, m.Name)); exist { + return fmt.Errorf("dir already has the same name file") + } + + m.Parent = to + return v.matterRepo.Update(ctx, m.Id, m) +} + +func (v *Vfs) Copy(ctx context.Context, alias string, to string) (*entity.Matter, error) { + m, err := v.matterRepo.FindByAlias(ctx, alias) + if err != nil { + return nil, err + } + + return v.matterRepo.Copy(ctx, m.Id, to) +} + +func (v *Vfs) Delete(ctx context.Context, alias string) error { + m, err := v.matterRepo.FindByAlias(ctx, alias) + if err != nil { + return err + } + + if err := v.matterRepo.Delete(ctx, m.Id); err != nil { + return err + } + + rb := m.BuildRecycleBinItem() + return v.recycleBinRepo.Create(ctx, rb) +} diff --git a/internal/app/usecase/vfs/vfs_test.go b/internal/app/usecase/vfs/vfs_test.go new file mode 100644 index 0000000..238d005 --- /dev/null +++ b/internal/app/usecase/vfs/vfs_test.go @@ -0,0 +1,116 @@ +package vfs + +import ( + "context" + "testing" + + "github.com/saltbo/zpan/internal/app/entity" + "github.com/saltbo/zpan/internal/app/repo" + "github.com/saltbo/zpan/internal/app/usecase/uploader" + "github.com/saltbo/zpan/internal/mock" + "github.com/stretchr/testify/assert" +) + +var ( + mockUploader = map[string]any{ + "url": "https://example.com/upload", + } + mockMatters = []*entity.Matter{ + {}, + } +) + +func TestVfs_Create_File(t *testing.T) { + matter := &entity.Matter{ + Parent: "/", + Name: "abc.txt", + } + ctx := context.Background() + mockMatter := mock.NewMatter() + assert.NoError(t, mockMatter.Create(ctx, matter)) + vfs := NewVfs(mockMatter, nil, &uploader.FakeUploader{CreateUploadURLFn: func(ctx context.Context, m *entity.Matter) error { + m.Uploader = mockUploader + return nil + }}) + + assert.NoError(t, vfs.Create(context.Background(), matter)) + assert.Equal(t, "/abc.txt", matter.FullPath()) + assert.Equal(t, mockUploader, matter.Uploader) +} + +func TestVfs_Create_Folder(t *testing.T) { + matter := &entity.Matter{ + DirType: entity.DirTypeUser, + Parent: "/", + Name: "abc", + } + vfs := NewVfs(&mock.Matter{}, nil, nil) + assert.NoError(t, vfs.Create(context.Background(), matter)) + assert.True(t, matter.IsDir()) + assert.Equal(t, "/abc/", matter.FullPath()) + assert.Empty(t, matter.Uploader) +} + +func TestVfs_Rename(t *testing.T) { + matter := &entity.Matter{ + Alias: "test", + Parent: "/", + Name: "abc.txt", + } + ctx := context.Background() + mockMatter := mock.NewMatter() + assert.NoError(t, mockMatter.Create(ctx, matter)) + vfs := NewVfs(mockMatter, nil, nil) + assert.NoError(t, vfs.Rename(ctx, "test", "new.txt")) + assert.Equal(t, "new.txt", matter.Name) +} + +func TestVfs_Move(t *testing.T) { + matter := &entity.Matter{ + Alias: "test", + Parent: "/", + Name: "abc.txt", + } + ctx := context.Background() + mockMatter := mock.NewMatter() + assert.NoError(t, mockMatter.Create(ctx, matter)) + vfs := NewVfs(mockMatter, nil, nil) + assert.NoError(t, vfs.Move(context.Background(), "test", "newDir")) + assert.Equal(t, "newDir/abc.txt", matter.FullPath()) +} + +func TestVfs_Copy(t *testing.T) { + matter := &entity.Matter{ + Alias: "test", + Parent: "/", + Name: "abc.txt", + } + ctx := context.Background() + mockMatter := mock.NewMatter() + assert.NoError(t, mockMatter.Create(ctx, matter)) + vfs := NewVfs(mockMatter, nil, nil) + newMatter, err := vfs.Copy(context.Background(), "test", "newDir") + assert.NoError(t, err) + assert.Equal(t, "newDir/abc.txt", newMatter.FullPath()) +} + +func TestVfs_Delete(t *testing.T) { + matter := &entity.Matter{ + Alias: "test", + Parent: "/", + Name: "abc.txt", + } + + ctx := context.Background() + mockMatter := mock.NewMatter() + assert.NoError(t, mockMatter.Create(ctx, matter)) + vfs := NewVfs(mockMatter, mock.NewRecycleBin(), nil) + assert.NoError(t, vfs.Delete(ctx, "test")) + _, err := vfs.Get(ctx, "test") + assert.Error(t, err) + + rbs, total, err := vfs.recycleBinRepo.FindAll(ctx, &repo.RecycleBinFindOptions{}) + assert.NoError(t, err) + assert.Equal(t, int64(1), total) + assert.Equal(t, rbs[0].Name, matter.Name) +} diff --git a/internal/app/usecase/vfs/worker.go b/internal/app/usecase/vfs/worker.go new file mode 100644 index 0000000..160ce10 --- /dev/null +++ b/internal/app/usecase/vfs/worker.go @@ -0,0 +1,26 @@ +package vfs + +import ( + "github.com/saltbo/zpan/internal/app/repo" +) + +type Worker struct { + matterRepo repo.Matter +} + +func NewWorker() *Worker { + return &Worker{} +} + +func (w *Worker) Start() { + +} + +func (w *Worker) cleanExpireMatters() { + // matters, total, err := w.matterRepo.FindAll(context.Background(), &repo.MatterListOption{}) + // if err != nil { + // return + // } + // + // w.matterRepo.Delete() +} diff --git a/internal/app/usecase/wire.go b/internal/app/usecase/wire.go new file mode 100644 index 0000000..757e778 --- /dev/null +++ b/internal/app/usecase/wire.go @@ -0,0 +1,31 @@ +package usecase + +import ( + "github.com/google/wire" + "github.com/saltbo/zpan/internal/app/usecase/storage" + "github.com/saltbo/zpan/internal/app/usecase/uploader" + "github.com/saltbo/zpan/internal/app/usecase/vfs" +) + +type Repository struct { + Storage storage.Storage + Uploader uploader.Uploader + VFS vfs.VirtualFs +} + +func NewRepository(storage storage.Storage, uploader uploader.Uploader, VFS vfs.VirtualFs) *Repository { + return &Repository{Storage: storage, Uploader: uploader, VFS: VFS} +} + +var ProviderSet = wire.NewSet( + storage.NewCloudStorage, + uploader.NewCloudUploader, + vfs.NewVfs, + vfs.NewRecycleBin, + + wire.Bind(new(storage.Storage), new(*storage.CloudStorage)), + wire.Bind(new(uploader.Uploader), new(*uploader.CloudUploader)), + wire.Bind(new(vfs.VirtualFs), new(*vfs.Vfs)), + wire.Bind(new(vfs.RecycleBinFs), new(*vfs.RecycleBin)), + NewRepository, +) diff --git a/internal/app/wire_gen.go b/internal/app/wire_gen.go new file mode 100644 index 0000000..620731d --- /dev/null +++ b/internal/app/wire_gen.go @@ -0,0 +1,69 @@ +// Code generated by Wire. DO NOT EDIT. + +//go:generate go run github.com/google/wire/cmd/wire +//go:build !wireinject +// +build !wireinject + +package app + +import ( + "fmt" + "github.com/gin-gonic/gin" + "github.com/saltbo/gopkg/ginutil" + "github.com/saltbo/zpan/internal/app/api" + "github.com/saltbo/zpan/internal/app/dao" + "github.com/saltbo/zpan/internal/app/repo" + "github.com/saltbo/zpan/internal/app/usecase" + "github.com/saltbo/zpan/internal/app/usecase/storage" + "github.com/saltbo/zpan/internal/app/usecase/uploader" + "github.com/saltbo/zpan/internal/app/usecase/vfs" + "github.com/saltbo/zpan/web" + "github.com/spf13/viper" +) + +// Injectors from server.go: + +func NewServer() *Server { + query := dao.GetDBQuery() + storageDBQuery := repo.NewStorageDBQuery(query) + matterDBQuery := repo.NewMatterDBQuery(query) + recycleBinDBQuery := repo.NewRecycleBinDBQuery(query) + repository := repo.NewRepository(storageDBQuery, matterDBQuery, recycleBinDBQuery) + cloudStorage := storage.NewCloudStorage(storageDBQuery) + cloudUploader := uploader.NewCloudUploader(cloudStorage, matterDBQuery) + vfsVfs := vfs.NewVfs(matterDBQuery, recycleBinDBQuery, cloudUploader) + usecaseRepository := usecase.NewRepository(cloudStorage, cloudUploader, vfsVfs) + fileResource := api.NewFileResource(vfsVfs, cloudUploader) + recycleBin := vfs.NewRecycleBin(recycleBinDBQuery, matterDBQuery, cloudStorage) + recycleBinResource := api.NewRecycleBinResource(recycleBinDBQuery, recycleBin) + shareResource := api.NewShareResource(matterDBQuery) + storageResource := api.NewStorageResource(storageDBQuery, cloudStorage) + option := api.NewOptionResource() + tokenResource := api.NewTokenResource() + userResource := api.NewUserResource() + userKeyResource := api.NewUserKeyResource() + apiRepository := api.NewRepository(fileResource, recycleBinResource, shareResource, storageResource, option, tokenResource, userResource, userKeyResource) + server := newServer(repository, usecaseRepository, apiRepository) + return server +} + +// server.go: + +type Server struct { + uc *usecase.Repository + rp *repo.Repository + ap *api.Repository +} + +func newServer(rp *repo.Repository, uc *usecase.Repository, ap *api.Repository) *Server { + return &Server{rp: rp, uc: uc, ap: ap} +} + +func (s *Server) Run() error { + + ge := gin.Default() + api.SetupRoutes(ge, s.ap) + web.SetupRoutes(ge) + ginutil.Startup(ge, fmt.Sprintf(":%d", viper.GetInt("port"))) + return nil +} diff --git a/internal/mock/matter.go b/internal/mock/matter.go new file mode 100644 index 0000000..601233f --- /dev/null +++ b/internal/mock/matter.go @@ -0,0 +1,80 @@ +package mock + +import ( + "context" + "fmt" + + "github.com/saltbo/zpan/internal/app/entity" + "github.com/saltbo/zpan/internal/app/repo" + "github.com/samber/lo" +) + +var _ repo.Matter = (*Matter)(nil) + +type Matter struct { + mockStore[*entity.Matter, *repo.MatterListOption, int64] +} + +func NewMatter() *Matter { + return &Matter{} +} + +func (mk *Matter) FindWith(ctx context.Context, opt *repo.MatterFindWithOption) (*entity.Matter, error) { + matter, ok := lo.Find(mk.store, func(item *entity.Matter) bool { + var conds []bool + if opt.Id != 0 { + conds = append(conds, opt.Id == item.Id) + } + if opt.Alias != "" { + conds = append(conds, opt.Alias == item.Alias) + } + + for _, cond := range conds { + if !cond { + return false + } + } + return true + }) + if !ok { + return nil, fmt.Errorf("not found with: %v", opt) + } + + return matter, nil +} + +func (mk *Matter) FindByAlias(ctx context.Context, alias string) (*entity.Matter, error) { + matter, ok := lo.Find(mk.store, func(item *entity.Matter) bool { + return item.Alias == alias + }) + if !ok { + return nil, fmt.Errorf("not found: %v", alias) + } + + return matter, nil +} + +func (mk *Matter) PathExist(ctx context.Context, filepath string) bool { + _, ok := lo.Find(mk.store, func(item *entity.Matter) bool { return item.FullPath() == filepath }) + return ok +} + +func (mk *Matter) Copy(ctx context.Context, id int64, to string) (*entity.Matter, error) { + matter, err := mk.Find(ctx, id) + if err != nil { + return nil, err + } + + newMatter := matter.Clone() + newMatter.Parent = to + mk.store = append(mk.store, newMatter) + return newMatter, nil +} + +func (mk *Matter) Recovery(ctx context.Context, id int64) error { + return nil +} + +func (mk *Matter) GetObjects(ctx context.Context, id int64) ([]string, error) { + return []string{}, nil +} diff --git a/internal/mock/mock.go b/internal/mock/mock.go new file mode 100644 index 0000000..ffd08c0 --- /dev/null +++ b/internal/mock/mock.go @@ -0,0 +1,62 @@ +package mock + +import ( + "context" + "fmt" + + "github.com/saltbo/zpan/internal/app/repo" + "github.com/samber/lo" +) + +type Entity[ID repo.IDType] interface { + comparable + GetID() ID +} + +type mockStore[T Entity[ID], O any, ID repo.IDType] struct { + store []T +} + +func (ms *mockStore[T, O, ID]) Create(ctx context.Context, t T) error { + ms.store = append(ms.store, t) + return nil +} + +func (ms *mockStore[T, O, ID]) Find(ctx context.Context, id ID) (T, error) { + v, ok := lo.Find(ms.store, func(item T) bool { + return item.GetID() == id + }) + + if !ok { + var result T + return result, fmt.Errorf("not found: %v", id) + } + + return v, nil +} + +func (ms *mockStore[T, O, ID]) FindAll(ctx context.Context, opts O) ([]T, int64, error) { + return ms.store, int64(len(ms.store)), nil +} + +func (ms *mockStore[T, O, ID]) Update(ctx context.Context, id ID, t T) error { + matter, err := ms.Find(ctx, id) + if err != nil { + return err + } + + idx := lo.IndexOf(ms.store, matter) + ms.store[idx] = t + return nil +} + +func (ms *mockStore[T, O, ID]) Delete(ctx context.Context, id ID) error { + matter, err := ms.Find(ctx, id) + if err != nil { + return err + } + + idx := lo.IndexOf(ms.store, matter) + ms.store = append(ms.store[:idx], ms.store[idx+1:]...) + return nil +} diff --git a/internal/mock/recyclebin.go b/internal/mock/recyclebin.go new file mode 100644 index 0000000..dbe3ab2 --- /dev/null +++ b/internal/mock/recyclebin.go @@ -0,0 +1,16 @@ +package mock + +import ( + "github.com/saltbo/zpan/internal/app/entity" + "github.com/saltbo/zpan/internal/app/repo" +) + +var _ repo.RecycleBin = (*RecycleBin)(nil) + +type RecycleBin struct { + mockStore[*entity.RecycleBin, *repo.RecycleBinFindOptions, string] +} + +func NewRecycleBin() *RecycleBin { + return &RecycleBin{} +} diff --git a/internal/mock/storage.go b/internal/mock/storage.go new file mode 100644 index 0000000..c4f42e6 --- /dev/null +++ b/internal/mock/storage.go @@ -0,0 +1,16 @@ +package mock + +import ( + "github.com/saltbo/zpan/internal/app/entity" + "github.com/saltbo/zpan/internal/app/repo" +) + +var _ repo.Storage = (*Storage)(nil) + +type Storage struct { + mockStore[*entity.Storage, *repo.StorageFindOptions, int64] +} + +func NewStorage() *Storage { + return &Storage{} +} diff --git a/internal/pkg/bind/folder.go b/internal/pkg/bind/folder.go index afe8da7..6810a1a 100644 --- a/internal/pkg/bind/folder.go +++ b/internal/pkg/bind/folder.go @@ -1,7 +1,7 @@ package bind import ( - "github.com/saltbo/zpan/internal/app/model" + "github.com/saltbo/zpan/internal/app/entity" ) type QueryFolder struct { @@ -17,9 +17,9 @@ type BodyFolder struct { Dir string `json:"dir"` } -func (p *BodyFolder) ToMatter(uid int64) *model.Matter { - m := model.NewMatter(uid, p.Sid, p.Name) +func (p *BodyFolder) ToMatter(uid int64) *entity.Matter { + m := entity.NewMatter(uid, p.Sid, p.Name) m.Parent = p.Dir - m.DirType = model.DirTypeUser + m.DirType = entity.DirTypeUser return m } diff --git a/internal/pkg/bind/matter.go b/internal/pkg/bind/matter.go index 614ac37..476b2b2 100644 --- a/internal/pkg/bind/matter.go +++ b/internal/pkg/bind/matter.go @@ -4,7 +4,7 @@ import ( "mime" "path/filepath" - "github.com/saltbo/zpan/internal/app/model" + "github.com/saltbo/zpan/internal/app/entity" ) type QueryFiles struct { @@ -24,7 +24,7 @@ type BodyMatter struct { Size int64 `json:"size"` } -func (p *BodyMatter) ToMatter(uid int64) *model.Matter { +func (p *BodyMatter) ToMatter(uid int64) *entity.Matter { detectType := func(name string) string { cType := mime.TypeByExtension(filepath.Ext(p.Name)) if cType != "" { @@ -34,16 +34,15 @@ func (p *BodyMatter) ToMatter(uid int64) *model.Matter { return "application/octet-stream" } - m := model.NewMatter(uid, p.Sid, p.Name) + m := entity.NewMatter(uid, p.Sid, p.Name) m.Type = p.Type m.Size = p.Size m.Parent = p.Dir if p.IsDir { - m.DirType = model.DirTypeUser + m.DirType = entity.DirTypeUser } else if p.Type == "" { m.Type = detectType(p.Name) } - return m } diff --git a/internal/pkg/bind/storage.go b/internal/pkg/bind/storage.go index 95959cc..809f414 100644 --- a/internal/pkg/bind/storage.go +++ b/internal/pkg/bind/storage.go @@ -3,7 +3,7 @@ package bind import ( "strings" - "github.com/saltbo/zpan/internal/app/model" + "github.com/saltbo/zpan/internal/app/entity" ) var ts = strings.TrimSpace @@ -26,13 +26,13 @@ type StorageBody struct { PublicRead bool `json:"public_read"` } -func (b *StorageBody) Model() *model.Storage { +func (b *StorageBody) Model() *entity.Storage { title := b.Title if title == "" { title = b.Name } - return &model.Storage{ + return &entity.Storage{ Mode: b.Mode, Name: ts(b.Name), Title: ts(title), diff --git a/internal/pkg/fakefs/ffs.go b/internal/pkg/fakefs/ffs.go deleted file mode 100644 index e615ef9..0000000 --- a/internal/pkg/fakefs/ffs.go +++ /dev/null @@ -1,156 +0,0 @@ -package fakefs - -import ( - "fmt" - "strings" - - "github.com/gin-gonic/gin" - "github.com/saltbo/zpan/internal/app/dao" - "github.com/saltbo/zpan/internal/app/model" - "github.com/saltbo/zpan/internal/pkg/bind" -) - -type FakeFS struct { - dMatter *dao.Matter - - sFile *File - sFolder *Folder -} - -func New() *FakeFS { - return &FakeFS{ - dMatter: dao.NewMatter(), - - sFile: NewFile(), - sFolder: NewFolder(), - } -} - -func (fs *FakeFS) StartFileAutoDoneWorker() { - go fs.sFile.RunFileAutoDoneWorker() -} - -func (fs *FakeFS) List(uid int64, qp *bind.QueryFiles) (list []model.Matter, total int64, err error) { - query := dao.NewQuery() - query.WithEq("sid", qp.Sid) - query.WithEq("uid", uid) - if qp.Type == "doc" { - docTypes := "'" + strings.Join(model.DocTypes, "','") + "'" - query.WithIn("type", docTypes) - } else if qp.Type != "" { - query.WithLike("type", qp.Type) - } else if qp.Keyword != "" { - query.WithLike("name", qp.Keyword) - } else { - query.WithEq("parent", qp.Dir) - } - query.Limit = qp.Limit - query.Offset = qp.Offset - return fs.dMatter.FindAll(query) -} - -func (fs *FakeFS) Copy(uid int64, alias, newPath string) error { - m, err := fs.dMatter.FindUserMatter(uid, alias) - if err != nil { - return err - } - - if _, ok := fs.dMatter.Exist(uid, m.Name, newPath); ok { - return fmt.Errorf("dir already has the same name file") - } - - if m.IsDir() { - return fmt.Errorf("not support to copy a folder") - } - - return fs.sFile.Copy(uid, alias, newPath) -} - -func (fs *FakeFS) Move(uid int64, alias, newPath string) error { - m, err := fs.dMatter.FindUserMatter(uid, alias) - if err != nil { - return err - } - - if _, ok := fs.dMatter.Exist(uid, m.Name, newPath); ok { - return fmt.Errorf("dir already has the same name file") - } - - if m.IsDir() { - return fs.sFolder.Move(uid, alias, newPath) - } - - return fs.sFile.Move(uid, alias, newPath) -} - -func (fs *FakeFS) Rename(uid int64, alias, name string) error { - m, err := fs.dMatter.FindUserMatter(uid, alias) - if err != nil { - return err - } - - if _, ok := fs.dMatter.Exist(uid, name, m.Parent); ok { - return fmt.Errorf("dir already has the same name file") - } - - if m.IsDir() { - return fs.sFolder.Rename(uid, alias, name) - } - - return fs.sFile.Rename(uid, alias, name) -} - -func (fs *FakeFS) Delete(uid int64, alias string) error { - m, err := fs.dMatter.FindUserMatter(uid, alias) - if err != nil { - return err - } - - if m.IsDir() { - return fs.sFolder.Remove(uid, alias) - } - - return fs.sFile.Delete(uid, alias) -} - -func (fs *FakeFS) CreateFile(m *model.Matter) (interface{}, error) { - user, err := dao.NewUser().Find(m.Uid) - if err != nil { - return nil, err - } else if user.Storage.Overflowed(m.Size) { - return nil, fmt.Errorf("service not enough space") - } - - link, headers, err := fs.sFile.PreSignPutURL(m) - if err != nil { - return nil, err - } - - return gin.H{ - "matter": m, - "uplink": link, - "headers": headers, - }, nil -} - -func (fs *FakeFS) CreateFolder(m *model.Matter) (interface{}, error) { - err := fs.sFolder.Create(m) - return m, err -} - -func (fs *FakeFS) GetFileInfo(uid int64, alias string) (*model.Matter, error) { - return fs.sFile.GetMatter(uid, alias) -} - -func (fs *FakeFS) GetSaveRequest(uid int64, alias string) (interface{}, error) { - m, err := fs.dMatter.FindUserMatter(uid, alias) - if err != nil { - return nil, err - } - - return fs.sFile.BuildPutURL(m) -} - -func (fs *FakeFS) TagUploadDone(uid int64, alias string) (*model.Matter, error) { - return fs.sFile.UploadDone(uid, alias) -} diff --git a/internal/pkg/fakefs/file.go b/internal/pkg/fakefs/file.go deleted file mode 100644 index 079c30c..0000000 --- a/internal/pkg/fakefs/file.go +++ /dev/null @@ -1,223 +0,0 @@ -package fakefs - -import ( - "fmt" - "net/http" - "path/filepath" - "strings" - "time" - - "github.com/gin-gonic/gin" - "github.com/saltbo/gopkg/timeutil" - - "github.com/saltbo/zpan/internal/app/dao" - "github.com/saltbo/zpan/internal/app/model" - "github.com/saltbo/zpan/internal/app/service" -) - -type File struct { - dMatter *dao.Matter - - sStorage *service.Storage - fileWaiter *FileWaiter -} - -func NewFile() *File { - return &File{ - dMatter: dao.NewMatter(), - - sStorage: service.NewStorage(), - fileWaiter: NewFileWaiter(), - } -} - -func (f *File) RunFileAutoDoneWorker() error { - return f.fileWaiter.Run() -} - -func (f *File) PreSignPutURL(matter *model.Matter) (url string, headers http.Header, err error) { - if !f.dMatter.ParentExist(matter.Uid, matter.Parent) { - return "", nil, fmt.Errorf("dir does not exists") - } - - // auto append a suffix if matter exist - if _, ok := f.dMatter.Exist(matter.Uid, matter.Name, matter.Parent); ok { - ext := filepath.Ext(matter.Name) - name := strings.TrimSuffix(matter.Name, ext) - suffix := fmt.Sprintf("_%s", timeutil.Format(time.Now(), "YYYYMMDD_HHmmss")) - matter.Name = name + suffix + ext - } - - storage, err := f.sStorage.Get(matter.Sid) - if err != nil { - return "", nil, err - } - - matter.BuildObject(storage.RootPath, storage.FilePath) - provider, err := f.sStorage.GetProviderByStorage(storage) - if err != nil { - return "", nil, err - } - - // 只有外链盘才有自动标记上传完成的逻辑 - if storage.Mode == model.StorageModeOutline { - f.fileWaiter.Wait(provider, matter, f.UploadDone) - } - - url, headers, err = provider.SignedPutURL(matter.Object, matter.Type, matter.Size, storage.PublicRead()) - if err != nil { - return - } - - err = f.dMatter.Create(matter) - return -} - -func (f *File) UploadDone(uid int64, alias string) (*model.Matter, error) { - m, err := f.dMatter.FindUserMatter(uid, alias) - if err != nil { - return nil, err - } - - s, err := f.sStorage.Get(m.Sid) - if err != nil { - return nil, err - } - - if err := f.dMatter.Uploaded(m, s.Mode == model.StorageModeNetDisk); err != nil { - return nil, err - } - - return m, f.BuildGetURL(m) -} - -func (f File) GetMatter(uid int64, alias string) (*model.Matter, error) { - m, err := f.dMatter.FindUserMatter(uid, alias) - if err != nil { - return nil, err - } - - return m, f.BuildGetURL(m) -} - -func (f *File) BuildGetURL(m *model.Matter) error { - storage, err := f.sStorage.Get(m.Sid) - if err != nil { - return err - } - - provider, err := f.sStorage.GetProviderByStorage(storage) - if err != nil { - return err - } - - if storage.PublicRead() { - m.URL = provider.PublicURL(m.Object) - return nil - } - - link, err := provider.SignedGetURL(m.Object, m.Name) - m.URL = link - return err -} - -func (f *File) BuildPutURL(m *model.Matter) (interface{}, error) { - storage, err := f.sStorage.Get(m.Sid) - if err != nil { - return nil, err - } - - provider, err := f.sStorage.GetProviderByStorage(storage) - if err != nil { - return nil, err - } - - link, headers, err := provider.SignedPutURL(m.Object, m.Type, m.Size, storage.PublicRead()) - if err != nil { - return nil, err - } - - return gin.H{"link": link, "headers": headers}, nil -} - -func (f *File) Rename(uid int64, alias, name string) error { - m, err := f.dMatter.FindUserMatter(uid, alias) - if err != nil { - return err - } - - if _, ok := f.dMatter.Exist(uid, name, m.Parent); ok { - return fmt.Errorf("dir already has the same name file") - } - - return f.dMatter.Rename(alias, name) -} - -func (f *File) Copy(uid int64, alias, parent string) error { - m, err := f.dMatter.FindUserMatter(uid, alias) - if err != nil { - return err - } else if err := f.copyOrMoveValidation(m, uid, parent); err != nil { - return err - } - - return f.dMatter.Copy(alias, parent) -} - -func (f *File) Move(uid int64, alias, parent string) error { - m, err := f.dMatter.FindUserMatter(uid, alias) - if err != nil { - return err - } else if err := f.copyOrMoveValidation(m, uid, parent); err != nil { - return err - } - - return f.dMatter.Move(alias, parent) -} - -func (f *File) Delete(uid int64, alias string) error { - matter, err := f.dMatter.FindUserMatter(uid, alias) - if err != nil { - return err - } - - storage, err := f.sStorage.Get(matter.Sid) - if err != nil { - return err - } - - if storage.Mode == model.StorageModeNetDisk { - return f.dMatter.RemoveToRecycle(matter) - } - - return f.removeFromStorage(matter, storage) -} - -func (f *File) removeFromStorage(m *model.Matter, s *model.Storage) error { - provider, err := f.sStorage.GetProviderByStorage(s) - if err != nil { - return err - } - - if err := provider.ObjectDelete(m.Object); err != nil { - return err - } - - return f.dMatter.Remove(m.Id, m.Alias) -} - -func (f *File) copyOrMoveValidation(m *model.Matter, uid int64, parent string) error { - if m.IsDir() { - return fmt.Errorf("only support file") - } else if parent == m.Parent { - return fmt.Errorf("file already in the dir") - } else if !f.dMatter.ParentExist(uid, parent) { - return fmt.Errorf("dir does not exists") - } - - if _, ok := f.dMatter.Exist(m.Uid, m.Name, parent); ok { - return fmt.Errorf("dir already has the same name file") - } - - return nil -} diff --git a/internal/pkg/fakefs/file_test.go b/internal/pkg/fakefs/file_test.go deleted file mode 100644 index 4f1287e..0000000 --- a/internal/pkg/fakefs/file_test.go +++ /dev/null @@ -1,117 +0,0 @@ -package fakefs - -import ( - "os" - "testing" - - "github.com/saltbo/gopkg/strutil" - "github.com/stretchr/testify/assert" - - "github.com/saltbo/zpan/internal/app/dao" - "github.com/saltbo/zpan/internal/app/model" - "github.com/saltbo/zpan/internal/pkg/bind" -) - -func init() { - os.Remove("zpan.db") - dao.Init("sqlite3", "zpan.db") - user := &model.User{ - Email: "admin@zpan.space", - Username: "admin", - Password: strutil.Md5Hex("123"), - Roles: "admin", - Ticket: strutil.RandomText(6), - Status: model.StatusActivated, - } - dao.NewUser().Create(user, model.UserStorageDefaultSize) - //clean before all - //clean() -} - -//func clean() { -// gormutil.DB().Exec("delete from zp_matter where 1=1;") -//} - -var fs = New() - -func init() { - fs.StartFileAutoDoneWorker() -} - -func TestPreSignPutURL(t *testing.T) { - bf := &bind.BodyMatter{ - Name: "test.txt", - Size: 0, - Type: "text/plain", - Dir: "", - } - nm := bf.ToMatter(1) - _, err := fs.CreateFile(nm) - assert.NoError(t, err) - - m, err := fs.TagUploadDone(1, nm.Alias) - assert.NoError(t, err) - assert.Equal(t, nm.Name, m.Name) - assert.Equal(t, nm.Size, m.Size) - assert.Equal(t, nm.Type, m.Type) - assert.Equal(t, nm.Parent, m.Parent) -} - -func TestFileRename(t *testing.T) { - m := model.NewMatter(1, 0, "test1.txt") - assert.NoError(t, fs.dMatter.Create(m)) - - newName := "test-new.txt" - assert.NoError(t, fs.Rename(m.Uid, m.Alias, newName)) - nm, err := fs.dMatter.FindUserMatter(m.Uid, m.Alias) - assert.NoError(t, err) - assert.Equal(t, newName, nm.Name) -} - -func TestFileCopy(t *testing.T) { - fm := model.NewMatter(1, 0, "test-copy-dir") - fm.DirType = model.DirTypeUser - assert.NoError(t, NewFolder().Create(fm)) - - m := model.NewMatter(1, 0, "test2.txt") - assert.NoError(t, fs.dMatter.Create(m)) - assert.NoError(t, fs.Copy(m.Uid, m.Alias, fm.Name+"/")) -} - -func TestFileMove(t *testing.T) { - fm := model.NewMatter(1, 0, "test-move-dir") - fm.DirType = model.DirTypeUser - assert.NoError(t, NewFolder().Create(fm)) - - m := model.NewMatter(1, 0, "test3.txt") - assert.NoError(t, fs.dMatter.Create(m)) - assert.NoError(t, fs.Move(m.Uid, m.Alias, fm.Name+"/")) -} - -func TestFileMoveFails(t *testing.T) { - ems := []*model.Matter{ - {Uid: 1, Parent: "", Name: "move", DirType: model.DirTypeUser}, - {Uid: 1, Parent: "move/", Name: "move", DirType: model.DirTypeUser}, - {Uid: 1, Parent: "", Name: "move.txt"}, - {Uid: 1, Parent: "move/", Name: "move.txt"}, - } - - for _, m := range ems { - m.Alias = strutil.RandomText(8) - assert.NoError(t, fs.dMatter.Create(m)) - } - - assert.Error(t, fs.Move(1, "ne.txt", "abc/")) // Disable move a not exist file - assert.Error(t, fs.Move(1, ems[1].Alias, ems[2].Name+"/")) // Disable move to non-folder directory - assert.Error(t, fs.Move(1, ems[2].Alias, "abc/")) // Disable move to not exist directory - assert.Error(t, fs.Move(1, ems[3].Alias, ems[3].Parent)) // Disable move to the current directory - assert.Error(t, fs.Move(1, ems[2].Alias, "move/")) // Disable move to a directory with a file with the same name -} - -func TestFileDelete(t *testing.T) { - m := model.NewMatter(1, 0, "test4.txt") - assert.NoError(t, fs.dMatter.Create(m)) - assert.NoError(t, fs.Delete(m.Uid, m.Alias)) - - assert.Error(t, fs.Delete(1, "123")) -} diff --git a/internal/pkg/fakefs/filewaiter.go b/internal/pkg/fakefs/filewaiter.go deleted file mode 100644 index fe4d66b..0000000 --- a/internal/pkg/fakefs/filewaiter.go +++ /dev/null @@ -1,65 +0,0 @@ -package fakefs - -import ( - "fmt" - "math/rand" - "time" - - "github.com/saltbo/zpan/internal/app/model" - "github.com/saltbo/zpan/internal/pkg/provider" -) - -const maxHeadIntervalSec = 5 - -type AutoDoneMsg struct { - Provider provider.Provider - Matter *model.Matter - Handler func(uid int64, alias string) (*model.Matter, error) -} - -type FileWaiter struct { - ch chan *AutoDoneMsg -} - -func NewFileWaiter() *FileWaiter { - return &FileWaiter{ - ch: make(chan *AutoDoneMsg), - } -} - -func (w *FileWaiter) Run() error { - for m := range w.ch { - go w.runWait(m) - } - - return nil -} - -// fixme: 如果在外链上传期间服务重启了,将永远无法标记上传完成 - -func (w *FileWaiter) Wait(p provider.Provider, m *model.Matter, f func(uid int64, alias string) (*model.Matter, error)) { - w.ch <- &AutoDoneMsg{Provider: p, Matter: m, Handler: f} -} - -func (w *FileWaiter) runWait(adm *AutoDoneMsg) { - startAt := time.Now() - for { - // 如果超过上传有效期仍然没有上传完成则判定为失败,不再等待 - if startAt.Sub(time.Now()) > time.Hour { - break - } - - s := time.Now() - if _, err := adm.Provider.Head(adm.Matter.Object); err != nil { - // 加一个时间限制,控制请求频率 - if time.Now().Sub(s).Seconds() < maxHeadIntervalSec { - time.Sleep(time.Second * time.Duration(rand.Intn(maxHeadIntervalSec))) - } - continue - } - - adm.Handler(adm.Matter.Uid, adm.Matter.Alias) - fmt.Printf("object %s uploaed\n", adm.Matter.Object) - return - } -} diff --git a/internal/pkg/fakefs/folder.go b/internal/pkg/fakefs/folder.go deleted file mode 100644 index b920a73..0000000 --- a/internal/pkg/fakefs/folder.go +++ /dev/null @@ -1,129 +0,0 @@ -package fakefs - -import ( - "fmt" - "strings" - "time" - - "gorm.io/gorm" - - "github.com/saltbo/zpan/internal/app/dao" - "github.com/saltbo/zpan/internal/app/model" -) - -type Folder struct { - dMatter *dao.Matter -} - -func NewFolder() *Folder { - return &Folder{ - dMatter: dao.NewMatter(), - } -} - -func (f *Folder) Create(matter *model.Matter) error { - uploaded := time.Now() - matter.UploadedAt = &uploaded - return f.dMatter.Create(matter) -} - -func (f *Folder) Rename(uid int64, alias, name string) error { - m, err := f.dMatter.FindUserMatter(uid, alias) - if err != nil { - return err - } - - if _, ok := f.dMatter.Exist(uid, name, m.Parent); ok { - return fmt.Errorf("dir already exist a same name file") - } - - children, err := f.dMatter.FindChildren(m.Uid, m.FullPath()) - if err != nil { - return err - } - - oldParent := fmt.Sprintf("%s%s/", m.Parent, m.Name) - newParent := fmt.Sprintf("%s%s/", m.Parent, name) - fc := func(tx *gorm.DB) error { - for _, v := range children { - parent := strings.Replace(v.Parent, oldParent, newParent, 1) - if err := tx.Model(v).Update("parent", parent).Error; err != nil { - return err - } - } - - if err := tx.Model(m).Update("name", name).Error; err != nil { - return err - } - - return nil - } - - return dao.Transaction(fc) -} - -func (f *Folder) Move(uid int64, alias, parent string) error { - m, err := f.dMatter.FindUserMatter(uid, alias) - if err != nil { - return err - } - - if err := f.copyOrMoveValidation(m, uid, parent); err != nil { - return err - } - - children, err := f.dMatter.FindChildren(m.Uid, m.FullPath()) - if err != nil { - return err - } - - fc := func(tx *gorm.DB) error { - for _, v := range children { - err := tx.Model(v).Update("parent", parent+m.Name+"/").Error - if err != nil { - return err - } - } - - return tx.Model(m).Update("parent", parent).Error - } - return dao.Transaction(fc) -} - -func (f *Folder) Remove(uid int64, alias string) error { - m, err := f.dMatter.FindUserMatter(uid, alias) - if err != nil { - return err - } - - children, err := f.dMatter.FindChildren(m.Uid, m.FullPath()) - if err != nil { - return err - } - - for _, v := range children { - if err := f.dMatter.Remove(v.Id, m.Alias); err != nil { - return err - } - } - - return f.dMatter.RemoveToRecycle(m) -} - -func (f *Folder) copyOrMoveValidation(m *model.Matter, uid int64, parent string) error { - if !m.IsDir() { - return fmt.Errorf("only support direction") - } else if parent == m.Parent { - return fmt.Errorf("dir already in the dir") - } else if parent != "" && strings.HasPrefix(parent, m.Parent+m.Name+"/") { - return fmt.Errorf("can not move to itself") - } else if !f.dMatter.ParentExist(uid, parent) { - return fmt.Errorf("dir does not exists") - } - - if _, ok := f.dMatter.Exist(m.Uid, m.Name, parent); ok { - return fmt.Errorf("dir already has the same name file") - } - - return nil -} diff --git a/internal/pkg/fakefs/folder_test.go b/internal/pkg/fakefs/folder_test.go deleted file mode 100644 index ca303a3..0000000 --- a/internal/pkg/fakefs/folder_test.go +++ /dev/null @@ -1,114 +0,0 @@ -package fakefs - -import ( - "testing" - - "github.com/saltbo/gopkg/strutil" - "github.com/stretchr/testify/assert" - - "github.com/saltbo/zpan/internal/app/model" -) - -var folder = NewFolder() - -func TestFolder_Rename(t *testing.T) { - m := model.NewMatter(1, 0, "folder-test1") - m.DirType = model.DirTypeUser - assert.NoError(t, folder.Create(m)) - - newName := "folder-test-new" - assert.NoError(t, folder.Rename(m.Uid, m.Alias, newName)) - assert.Error(t, folder.Rename(m.Uid, m.Alias, newName)) - - nm, err := folder.dMatter.FindUserMatter(m.Uid, m.Alias) - assert.NoError(t, err) - assert.Equal(t, newName, nm.Name) -} - -func TestFolder_RenameNotEmpty(t *testing.T) { - ems := []*model.Matter{ - {Uid: 1,Parent: "", Name: "rename", DirType: model.DirTypeUser}, - {Uid: 1,Parent: "rename/", Name: "rename", DirType: model.DirTypeUser}, - {Uid: 1,Parent: "rename/rename/", Name: "rename1.txt"}, - {Uid: 1,Parent: "rename/rename/", Name: "rename2.txt"}, - } - - for _, m := range ems { - m.Alias = strutil.RandomText(8) - assert.NoError(t, fs.dMatter.Create(m)) - } - - newName := "rename-new" - assert.NoError(t, folder.Rename(1, ems[0].Alias, newName)) - - ems[0].Name = newName - children, err := folder.dMatter.FindChildren(ems[0].Uid, ems[0].FullPath()) - assert.NoError(t, err) - assert.Len(t, children, 3) -} - -func TestFolder_Move(t *testing.T) { - fm := model.NewMatter(1, 0, "test-move-dir2") - fm.DirType = model.DirTypeUser - assert.NoError(t, NewFolder().Create(fm)) - - m := model.NewMatter(1, 0, "test-move-dir3") - m.DirType = model.DirTypeUser - assert.NoError(t, folder.Create(m)) - assert.NoError(t, folder.Move(m.Uid, m.Alias, fm.Name+"/")) -} - -func TestFolder_MoveWithNotEmpty(t *testing.T) { - ems := []*model.Matter{ - {Uid: 1,Parent: "", Name: "f-move", DirType: model.DirTypeUser}, - {Uid: 1,Parent: "", Name: "f-move2", DirType: model.DirTypeUser}, - {Uid: 1,Parent: "f-move/", Name: "move", DirType: model.DirTypeUser}, - {Uid: 1,Parent: "f-move/move/", Name: "move1.txt"}, - {Uid: 1,Parent: "f-move/move/", Name: "move2.txt"}, - } - for _, m := range ems { - m.Alias = strutil.RandomText(8) - assert.NoError(t, fs.dMatter.Create(m)) - } - - assert.NoError(t, folder.Move(1, ems[0].Alias, ems[1].Name+"/")) - - children, err := folder.dMatter.FindChildren(ems[1].Uid, ems[1].FullPath()) - assert.NoError(t, err) - assert.Len(t, children, 4) -} - -func TestFolder_MoveFails(t *testing.T) { - ems := []*model.Matter{ - {Uid: 1, Parent: "", Name: "ff-move", DirType: model.DirTypeUser}, - {Uid: 1, Parent: "", Name: "move2", DirType: model.DirTypeUser}, - {Uid: 1, Parent: "ff-move/", Name: "move2", DirType: model.DirTypeUser}, - {Uid: 1, Parent: "ff-move/move2/", Name: "move1.txt"}, - {Uid: 1, Parent: "ff-move/move2/", Name: "move2.txt"}, - } - for _, m := range ems { - m.Alias = strutil.RandomText(8) - assert.NoError(t, fs.dMatter.Create(m)) - } - - assert.Error(t, folder.Move(1, ems[3].Alias, "")) // Only support move the direction - assert.Error(t, folder.Move(1, ems[0].Alias, ems[0].Parent)) // Disable move to the same direction - assert.Error(t, folder.Move(1, ems[0].Alias, "ff-move/move")) // Disable move to own subdirectories - assert.Error(t, folder.Move(1, ems[0].Alias, "abc/")) // Disable move to the not exist direction - assert.Error(t, folder.Move(1, ems[1].Alias, ems[2].Parent)) // Disable move to a directory with a file with the same name -} - -func TestFolder_Remove(t *testing.T) { - ems := []*model.Matter{ - {Uid: 1, Parent: "", Name: "remove", DirType: model.DirTypeUser}, - {Uid: 1, Parent: "remove/", Name: "remove", DirType: model.DirTypeUser}, - {Uid: 1, Parent: "remove/remove/", Name: "remove-1.txt"}, - {Uid: 1, Parent: "remove/remove/", Name: "remove-2.txt"}, - } - for _, m := range ems { - m.Alias = strutil.RandomText(8) - assert.NoError(t, fs.dMatter.Create(m)) - } - - assert.NoError(t, folder.Remove(1, ems[0].Alias)) -} diff --git a/internal/pkg/provider/provider_mock.go b/internal/pkg/provider/provider_mock.go index c56925d..c8e85a5 100644 --- a/internal/pkg/provider/provider_mock.go +++ b/internal/pkg/provider/provider_mock.go @@ -8,14 +8,18 @@ import ( type MockProvider struct { } +func NewMockProvider(provider *Config) (Provider, error) { + return &MockProvider{}, nil +} + func (m *MockProvider) SetupCORS() error { return nil } func (m *MockProvider) Head(object string) (*Object, error) { return &Object{ - Key: "20210709/86JzAOLIlGZ5Z2Fk.zip", - Type: "application/zip", + Key: "20210709/86JzAOLIlGZ5Z2Fk.zip", + Type: "application/zip", }, nil }