From d8cb33a7004ea9741589262ed2769bbc2306cf07 Mon Sep 17 00:00:00 2001 From: Jefferson Baldion Date: Sat, 4 May 2024 13:12:16 -0500 Subject: [PATCH 01/27] Invest data by PromoUrl - Add Post method to set data in DB - Add Get method to get all data or data by code --- internal/api/v1/invest_get.go | 48 +++++++++++++++++++++++++++ internal/api/v1/invest_post.go | 55 +++++++++++++++++++++++++++++++ internal/entity/invest_account.go | 31 +++++++++++++++++ internal/entity/invest_code.go | 25 ++++++++++++++ internal/server/routes.go | 10 +++++- 5 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 internal/api/v1/invest_get.go create mode 100644 internal/api/v1/invest_post.go create mode 100644 internal/entity/invest_account.go create mode 100644 internal/entity/invest_code.go diff --git a/internal/api/v1/invest_get.go b/internal/api/v1/invest_get.go new file mode 100644 index 0000000..794788e --- /dev/null +++ b/internal/api/v1/invest_get.go @@ -0,0 +1,48 @@ +package v1 + +import ( + "net/http" + + "github.com/Hello-Storage/hello-back/internal/db" + "github.com/Hello-Storage/hello-back/internal/entity" + "github.com/gin-gonic/gin" +) + +func InvestGetDataByCode(router *gin.RouterGroup) { + + router.GET("/invest/:code", func(ctx *gin.Context) { + + code := ctx.Param("code") + + var investCode entity.InvestCode + result := db.Db().Preload("InvestAccounts").Where("code = ?", code).First(&investCode) + + if result.RowsAffected > 0 { + + ctx.JSON(http.StatusOK, gin.H{ + "isSuccess": "true", + "message": investCode, + }) + } else { + + ctx.JSON(http.StatusNotFound, gin.H{ + "isSuccess": "false", + "message": "code was not found", + }) + } + + }) + + router.GET("/invest", func(ctx *gin.Context) { + + var investCodes []entity.InvestCode + db.Db().Preload("InvestAccounts").Find(&investCodes) + + ctx.JSON(http.StatusOK, gin.H{ + "isSuccess": "true", + "message": investCodes, + }) + + }) + +} diff --git a/internal/api/v1/invest_post.go b/internal/api/v1/invest_post.go new file mode 100644 index 0000000..c0b2f6a --- /dev/null +++ b/internal/api/v1/invest_post.go @@ -0,0 +1,55 @@ +package v1 + +import ( + "net/http" + + "github.com/Hello-Storage/hello-back/internal/db" + "github.com/Hello-Storage/hello-back/internal/entity" + "github.com/gin-gonic/gin" +) + +type InvestCodeRequest struct { + IP string `json:"ip"` + Email string `json:"email"` + SocialNetwork string `json:"social_network"` +} + +func InvestPostData(router *gin.RouterGroup) { + + router.POST("/invest", func(ctx *gin.Context) { + + code := ctx.Query("code") + + var request InvestCodeRequest + if err := ctx.ShouldBindJSON(&request); err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"error": "body request not found or incomplete"}) + return + } + + var investCode entity.InvestCode + result := db.Db().Preload("InvestAccounts").Where("code = ?", code).First(&investCode) + + if result.RowsAffected > 0 { + newInvestAccount := entity.InvestAccount{IP: request.IP, Code: code} + db.Db().Create(&newInvestAccount) + + ctx.JSON(http.StatusOK, gin.H{ + "status": "Ya existe", + "message": investCode, + }) + } else { + newInvestCode := entity.InvestCode{Code: code, Email: request.Email, SocialNetwork: request.SocialNetwork} + db.Db().Create(&newInvestCode) + + newInvestAccount := entity.InvestAccount{IP: request.IP, Code: code} + db.Db().Create(&newInvestAccount) + + ctx.JSON(http.StatusOK, gin.H{ + "status": "Se ha creado", + "message": investCode, + }) + } + + }) + +} diff --git a/internal/entity/invest_account.go b/internal/entity/invest_account.go new file mode 100644 index 0000000..f5b9973 --- /dev/null +++ b/internal/entity/invest_account.go @@ -0,0 +1,31 @@ +package entity + +import ( + "time" + + "github.com/Hello-Storage/hello-back/internal/db" + "gorm.io/gorm" +) + +type InvestAccount struct { + ID uint `gorm:"primarykey" json:"id"` + IP string `gorm:"type:varchar(16);unique" json:"ip"` + CreatedAt time.Time ` json:"created_at"` + UpdatedAt time.Time ` json:"updated_at"` + DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at"` + Code string `gorm:"type:varchar(64);index" json:"code"` + InvestCode InvestCode `gorm:"foreignKey:Code;references:Code" json:"-"` +} + +// TableName returns the entity table name. +func (InvestAccount) TableName() string { + return "invest_accounts" +} + +func (m *InvestAccount) Create() error { + return db.Db().Create(m).Error +} + +func (m *InvestAccount) Save() error { + return db.Db().Save(m).Error +} diff --git a/internal/entity/invest_code.go b/internal/entity/invest_code.go new file mode 100644 index 0000000..e2e2fdf --- /dev/null +++ b/internal/entity/invest_code.go @@ -0,0 +1,25 @@ +package entity + +import ( + "github.com/Hello-Storage/hello-back/internal/db" +) + +type InvestCode struct { + Code string `gorm:"primarykey" json:"code"` + Email string `gorm:"type:varchar(64)" json:"email"` + SocialNetwork string `gorm:"type:varchar(64)" json:"social_network"` + InvestAccounts []InvestAccount `gorm:"foreignKey:Code;references:Code"` +} + +// TableName returns the entity table name. +func (InvestCode) TableName() string { + return "invest_codes" +} + +func (m *InvestCode) Create() error { + return db.Db().Create(m).Error +} + +func (m *InvestCode) Save() error { + return db.Db().Save(m).Error +} diff --git a/internal/server/routes.go b/internal/server/routes.go index ca0ce1c..de62894 100644 --- a/internal/server/routes.go +++ b/internal/server/routes.go @@ -67,7 +67,6 @@ func registerRoutes(router *gin.Engine) { api.EncryptFile(FileRoutes) api.UploadFileMultipart(FileRoutes) - api.GetPublishedFileName(router.Group("/api/file")) // folder routes @@ -93,6 +92,14 @@ func RegisterApiRoutes(router *gin.Engine) { } // Create router groups. + + //Public route without apiKey + ApiPublic := router.Group("/public-api/v1") + //Public api route + v1.InvestPostData(ApiPublic) + v1.InvestGetDataByCode(ApiPublic) + + //Public route with apiKey ApiKeyAPIv1 = router.Group("/public-api/v1") ApiKeyAPIv1.Use(middlewares.APIKeyAuthMiddleware(tokenMaker)) @@ -103,4 +110,5 @@ func RegisterApiRoutes(router *gin.Engine) { v1.FileUpdate(ApiKeyAPIv1) v1.DeleteFile(ApiKeyAPIv1) v1.DownloadFile(ApiKeyAPIv1) + } From 459586127918eb6fd7df6a27b15dff5691fecae8 Mon Sep 17 00:00:00 2001 From: Jefferson Baldion Date: Tue, 7 May 2024 15:28:14 -0500 Subject: [PATCH 02/27] Fix routes to /api --- internal/api/v1/invest_get.go | 12 +++++------- internal/api/v1/invest_post.go | 20 ++++++++++++-------- internal/entity/invest_code.go | 1 - internal/server/routes.go | 10 ++++------ 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/internal/api/v1/invest_get.go b/internal/api/v1/invest_get.go index 794788e..8be56c2 100644 --- a/internal/api/v1/invest_get.go +++ b/internal/api/v1/invest_get.go @@ -10,24 +10,22 @@ import ( func InvestGetDataByCode(router *gin.RouterGroup) { - router.GET("/invest/:code", func(ctx *gin.Context) { + router.GET("/invest/all", func(ctx *gin.Context) { - code := ctx.Param("code") - - var investCode entity.InvestCode - result := db.Db().Preload("InvestAccounts").Where("code = ?", code).First(&investCode) + var investAccount []entity.InvestAccount + result := db.Db().Find(&investAccount) if result.RowsAffected > 0 { ctx.JSON(http.StatusOK, gin.H{ "isSuccess": "true", - "message": investCode, + "message": investAccount, }) } else { ctx.JSON(http.StatusNotFound, gin.H{ "isSuccess": "false", - "message": "code was not found", + "message": "No data found", }) } diff --git a/internal/api/v1/invest_post.go b/internal/api/v1/invest_post.go index c0b2f6a..59218f1 100644 --- a/internal/api/v1/invest_post.go +++ b/internal/api/v1/invest_post.go @@ -34,19 +34,23 @@ func InvestPostData(router *gin.RouterGroup) { db.Db().Create(&newInvestAccount) ctx.JSON(http.StatusOK, gin.H{ - "status": "Ya existe", - "message": investCode, + "isSuccess": true, + "message": investCode, }) } else { - newInvestCode := entity.InvestCode{Code: code, Email: request.Email, SocialNetwork: request.SocialNetwork} - db.Db().Create(&newInvestCode) + //Creacion de Invest_codes - newInvestAccount := entity.InvestAccount{IP: request.IP, Code: code} - db.Db().Create(&newInvestAccount) + // newInvestCode := entity.InvestCode{Code: code, Email: request.Email, SocialNetwork: request.SocialNetwork} + // db.Db().Create(&newInvestCode) + + //Creacion de Invest_account + + // newInvestAccount := entity.InvestAccount{IP: request.IP, Code: code} + // db.Db().Create(&newInvestAccount) ctx.JSON(http.StatusOK, gin.H{ - "status": "Se ha creado", - "message": investCode, + "isSuccess": false, + "message": "The code is not found", }) } diff --git a/internal/entity/invest_code.go b/internal/entity/invest_code.go index e2e2fdf..d7a9151 100644 --- a/internal/entity/invest_code.go +++ b/internal/entity/invest_code.go @@ -6,7 +6,6 @@ import ( type InvestCode struct { Code string `gorm:"primarykey" json:"code"` - Email string `gorm:"type:varchar(64)" json:"email"` SocialNetwork string `gorm:"type:varchar(64)" json:"social_network"` InvestAccounts []InvestAccount `gorm:"foreignKey:Code;references:Code"` } diff --git a/internal/server/routes.go b/internal/server/routes.go index de62894..db83221 100644 --- a/internal/server/routes.go +++ b/internal/server/routes.go @@ -32,6 +32,10 @@ func registerRoutes(router *gin.Engine) { //api keys routes api.ApiKey(AuthAPIv1, tokenMaker) + //api invest data + v1.InvestPostData(APIv1) + v1.InvestGetDataByCode(APIv1) + //statistics routes api.GetStatistics(APIv1) api.GetWeeklyPublicStats(APIv1) @@ -93,12 +97,6 @@ func RegisterApiRoutes(router *gin.Engine) { // Create router groups. - //Public route without apiKey - ApiPublic := router.Group("/public-api/v1") - //Public api route - v1.InvestPostData(ApiPublic) - v1.InvestGetDataByCode(ApiPublic) - //Public route with apiKey ApiKeyAPIv1 = router.Group("/public-api/v1") ApiKeyAPIv1.Use(middlewares.APIKeyAuthMiddleware(tokenMaker)) From 48ebc17fbf1a9bcc1b04c14e131adcc5c679e104 Mon Sep 17 00:00:00 2001 From: Jefferson Baldion Date: Tue, 7 May 2024 15:57:38 -0500 Subject: [PATCH 03/27] Update entity_tables --- internal/entity/entity_tables.go | 50 +++++++++++++++++--------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/internal/entity/entity_tables.go b/internal/entity/entity_tables.go index 5905013..fcf7f5b 100644 --- a/internal/entity/entity_tables.go +++ b/internal/entity/entity_tables.go @@ -12,30 +12,32 @@ type Tables map[string]interface{} // Entities contains database entities and their table names. var Entities = Tables{ - Error{}.TableName(): &Error{}, - User{}.TableName(): &User{}, - UserDetail{}.TableName(): &UserDetail{}, - UserLogin{}.TableName(): &UserLogin{}, - ReferredUser{}.TableName(): &ReferredUser{}, - Plan{}.TableName(): &Plan{}, - Subscription{}.TableName(): &Subscription{}, - Email{}.TableName(): &Email{}, - Wallet{}.TableName(): &Wallet{}, - Github{}.TableName(): &Github{}, - File{}.TableName(): &File{}, - FileShareState{}.TableName(): &FileShareState{}, - PublicFile{}.TableName(): &PublicFile{}, - Folder{}.TableName(): &Folder{}, - FileUser{}.TableName(): &FileUser{}, - FolderUser{}.TableName(): &FolderUser{}, - Referral{}.TableName(): &Referral{}, - PublicFileShareGroup{}.TableName(): &PublicFileShareGroup{}, - ShareGroup{}.TableName(): &ShareGroup{}, - ApiKey{}.TableName(): &ApiKey{}, - ApiKeyFile{}.TableName(): &ApiKeyFile{}, + Error{}.TableName(): &Error{}, + User{}.TableName(): &User{}, + UserDetail{}.TableName(): &UserDetail{}, + UserLogin{}.TableName(): &UserLogin{}, + ReferredUser{}.TableName(): &ReferredUser{}, + Plan{}.TableName(): &Plan{}, + Subscription{}.TableName(): &Subscription{}, + Email{}.TableName(): &Email{}, + Wallet{}.TableName(): &Wallet{}, + Github{}.TableName(): &Github{}, + File{}.TableName(): &File{}, + FileShareState{}.TableName(): &FileShareState{}, + PublicFile{}.TableName(): &PublicFile{}, + Folder{}.TableName(): &Folder{}, + FileUser{}.TableName(): &FileUser{}, + FolderUser{}.TableName(): &FolderUser{}, + Referral{}.TableName(): &Referral{}, + PublicFileShareGroup{}.TableName(): &PublicFileShareGroup{}, + ShareGroup{}.TableName(): &ShareGroup{}, + ApiKey{}.TableName(): &ApiKey{}, + ApiKeyFile{}.TableName(): &ApiKeyFile{}, FileShareStatesUserShared{}.TableName(): &FileShareStatesUserShared{}, - PublicFileUserShared{}.TableName(): &PublicFileUserShared{}, - ArweaveTransaction{}.TableName(): &ArweaveTransaction{}, + PublicFileUserShared{}.TableName(): &PublicFileUserShared{}, + ArweaveTransaction{}.TableName(): &ArweaveTransaction{}, + InvestCode{}.TableName(): &InvestCode{}, + InvestAccount{}.TableName(): &InvestAccount{}, } // WaitForMigration waits for the database migration to be successful. @@ -106,7 +108,7 @@ func (list Tables) Migrate(db *gorm.DB, opt migrate.Options) { for name, entity = range list { if name == "users" || name == "wallets" || name == "githubs" { // if db.Migrator().HasTable(name) { - continue + continue // } } if err := db.AutoMigrate(entity); err != nil { From 7c87c3b7f664baf59b2475b017df22df11750cda Mon Sep 17 00:00:00 2001 From: Jefferson Baldion Date: Tue, 7 May 2024 15:58:31 -0500 Subject: [PATCH 04/27] Update entity_tables.go --- internal/entity/entity_tables.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/entity/entity_tables.go b/internal/entity/entity_tables.go index fcf7f5b..50c011e 100644 --- a/internal/entity/entity_tables.go +++ b/internal/entity/entity_tables.go @@ -108,7 +108,7 @@ func (list Tables) Migrate(db *gorm.DB, opt migrate.Options) { for name, entity = range list { if name == "users" || name == "wallets" || name == "githubs" { // if db.Migrator().HasTable(name) { - continue + continue // } } if err := db.AutoMigrate(entity); err != nil { From 327c9c63925a69c455db397b389ce76b424f2a9f Mon Sep 17 00:00:00 2001 From: Jefferson Baldion Date: Tue, 7 May 2024 16:03:00 -0500 Subject: [PATCH 05/27] Create invest tables --- internal/entity/invest_account.go | 14 +++++++------- internal/entity/invest_code.go | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/internal/entity/invest_account.go b/internal/entity/invest_account.go index f5b9973..fbe7709 100644 --- a/internal/entity/invest_account.go +++ b/internal/entity/invest_account.go @@ -8,13 +8,13 @@ import ( ) type InvestAccount struct { - ID uint `gorm:"primarykey" json:"id"` - IP string `gorm:"type:varchar(16);unique" json:"ip"` - CreatedAt time.Time ` json:"created_at"` - UpdatedAt time.Time ` json:"updated_at"` - DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at"` - Code string `gorm:"type:varchar(64);index" json:"code"` - InvestCode InvestCode `gorm:"foreignKey:Code;references:Code" json:"-"` + ID uint `gorm:"primarykey" json:"id"` + IP string `gorm:"type:varchar(16);unique" json:"ip"` + CreatedAt time.Time ` json:"created_at"` + UpdatedAt time.Time ` json:"updated_at"` + DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at"` + Code string `gorm:"type:varchar(64);index" json:"code"` + // InvestCode InvestCode `gorm:"foreignKey:Code;references:Code" json:"-"` } // TableName returns the entity table name. diff --git a/internal/entity/invest_code.go b/internal/entity/invest_code.go index d7a9151..91284d9 100644 --- a/internal/entity/invest_code.go +++ b/internal/entity/invest_code.go @@ -5,9 +5,9 @@ import ( ) type InvestCode struct { - Code string `gorm:"primarykey" json:"code"` - SocialNetwork string `gorm:"type:varchar(64)" json:"social_network"` - InvestAccounts []InvestAccount `gorm:"foreignKey:Code;references:Code"` + Code string `gorm:"primarykey" json:"code"` + SocialNetwork string `gorm:"type:varchar(64)" json:"social_network"` + // InvestAccounts []InvestAccount `gorm:"foreignKey:Code;references:Code"` } // TableName returns the entity table name. From e6560d723351c44f86004e3d1871b739a45653e1 Mon Sep 17 00:00:00 2001 From: Jefferson Baldion Date: Tue, 7 May 2024 16:07:40 -0500 Subject: [PATCH 06/27] Create tables relation --- internal/entity/invest_account.go | 14 +++++++------- internal/entity/invest_code.go | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/internal/entity/invest_account.go b/internal/entity/invest_account.go index fbe7709..f5b9973 100644 --- a/internal/entity/invest_account.go +++ b/internal/entity/invest_account.go @@ -8,13 +8,13 @@ import ( ) type InvestAccount struct { - ID uint `gorm:"primarykey" json:"id"` - IP string `gorm:"type:varchar(16);unique" json:"ip"` - CreatedAt time.Time ` json:"created_at"` - UpdatedAt time.Time ` json:"updated_at"` - DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at"` - Code string `gorm:"type:varchar(64);index" json:"code"` - // InvestCode InvestCode `gorm:"foreignKey:Code;references:Code" json:"-"` + ID uint `gorm:"primarykey" json:"id"` + IP string `gorm:"type:varchar(16);unique" json:"ip"` + CreatedAt time.Time ` json:"created_at"` + UpdatedAt time.Time ` json:"updated_at"` + DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at"` + Code string `gorm:"type:varchar(64);index" json:"code"` + InvestCode InvestCode `gorm:"foreignKey:Code;references:Code" json:"-"` } // TableName returns the entity table name. diff --git a/internal/entity/invest_code.go b/internal/entity/invest_code.go index 91284d9..d7a9151 100644 --- a/internal/entity/invest_code.go +++ b/internal/entity/invest_code.go @@ -5,9 +5,9 @@ import ( ) type InvestCode struct { - Code string `gorm:"primarykey" json:"code"` - SocialNetwork string `gorm:"type:varchar(64)" json:"social_network"` - // InvestAccounts []InvestAccount `gorm:"foreignKey:Code;references:Code"` + Code string `gorm:"primarykey" json:"code"` + SocialNetwork string `gorm:"type:varchar(64)" json:"social_network"` + InvestAccounts []InvestAccount `gorm:"foreignKey:Code;references:Code"` } // TableName returns the entity table name. From a9813b67ca5f135d6ce95ac704fbe032621995f1 Mon Sep 17 00:00:00 2001 From: Keiner Alvarado Date: Thu, 9 May 2024 10:01:10 -0500 Subject: [PATCH 07/27] fix: gitignore fix, air config unnecesary privacy, filesharestate migration error fixed, column ipfs_hash created on files table --- .air.example.toml => .air.toml | 7 +------ .gitignore | 1 - internal/config/env.go | 4 ---- internal/entity/file.go | 1 + internal/entity/file_share_state_user_shared.go | 2 +- 5 files changed, 3 insertions(+), 12 deletions(-) rename .air.example.toml => .air.toml (96%) diff --git a/.air.example.toml b/.air.toml similarity index 96% rename from .air.example.toml rename to .air.toml index 97124f9..d68789b 100644 --- a/.air.example.toml +++ b/.air.toml @@ -1,7 +1,6 @@ root = "." testdata_dir = "testdata" tmp_dir = "tmp" - [build] args_bin = [] bin = "tmp/main" @@ -24,21 +23,17 @@ tmp_dir = "tmp" rerun_delay = 500 send_interrupt = false stop_on_error = false - [color] app = "" build = "yellow" main = "magenta" runner = "green" watcher = "cyan" - [log] main_only = false time = false - [misc] clean_on_exit = false - [screen] clear_on_rebuild = false - keep_scroll = true + keep_scroll = true \ No newline at end of file diff --git a/.gitignore b/.gitignore index 41cf1ca..54d31b6 100644 --- a/.gitignore +++ b/.gitignore @@ -41,7 +41,6 @@ arweave-wallet.json .env.production.local .drone.secrets -.air.toml # Go workspace file go.work diff --git a/internal/config/env.go b/internal/config/env.go index 062e585..0110b21 100644 --- a/internal/config/env.go +++ b/internal/config/env.go @@ -100,10 +100,6 @@ func LoadEnv() (err error) { } } - if err != nil { - return - } - return } diff --git a/internal/entity/file.go b/internal/entity/file.go index 06110ac..1037f55 100644 --- a/internal/entity/file.go +++ b/internal/entity/file.go @@ -39,6 +39,7 @@ type File struct { DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at"` Path string `gorm:"type:varchar(1024);" json:"path"` // full path IsInPool *bool `gorm:"type:boolean;default:false;" json:"is_in_pool"` + IPFSHash *string `gorm:"type:varchar(256);default:NULL" json:"ipfs_hash"` //sharestates are referenced by this file's UID at file share state FileShareState FileShareState `gorm:"foreignKey:FileUID;references:UID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"file_share_state"` EncryptionStatus EncryptionStatus `gorm:"type:encryption_status;default:'public'" json:"encryption_status"` diff --git a/internal/entity/file_share_state_user_shared.go b/internal/entity/file_share_state_user_shared.go index 482772a..0b55b98 100644 --- a/internal/entity/file_share_state_user_shared.go +++ b/internal/entity/file_share_state_user_shared.go @@ -9,7 +9,7 @@ type FileShareStatesUserShared struct { ID uint `gorm:"primarykey" json:"id"` FileUID string `gorm:"type:varchar(42);index;references:UID;referencedTable:files" json:"file_uid"` UserID uint `gorm:"type:int" json:"user_id"` - PublicFileUserShared PublicFileUserShared `gorm:"foreignKey:FileUID;references:FileUID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"public_file"` + PublicFileUserShared PublicFileUserShared `gorm:"foreignKey:FileUID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"public_file"` } func (FileShareStatesUserShared) TableName() string { From 041e875d6beda62fad430ba9a3cb65f826b0838b Mon Sep 17 00:00:00 2001 From: Keiner Alvarado Date: Thu, 9 May 2024 12:30:31 -0500 Subject: [PATCH 08/27] feat: update ipfshash --- internal/api/file_update.go | 50 ++++++++++++++++++++++++------------- internal/entity/file.go | 5 ++++ internal/form/file.go | 5 ++++ internal/server/routes.go | 1 + 4 files changed, 43 insertions(+), 18 deletions(-) diff --git a/internal/api/file_update.go b/internal/api/file_update.go index 798f4c0..c8a361b 100644 --- a/internal/api/file_update.go +++ b/internal/api/file_update.go @@ -1,15 +1,14 @@ package api import ( - "fmt" "net/http" "strconv" "sync" "github.com/Hello-Storage/hello-back/internal/constant" - "github.com/Hello-Storage/hello-back/internal/db" "github.com/Hello-Storage/hello-back/internal/entity" "github.com/Hello-Storage/hello-back/internal/form" + "github.com/Hello-Storage/hello-back/internal/query" "github.com/Hello-Storage/hello-back/pkg/token" "github.com/gin-gonic/gin" ) @@ -23,7 +22,6 @@ var fileMutex = sync.Mutex{} // @return 200 {string} string "ok" func UpdateFileRoot(router *gin.RouterGroup) { router.PUT("/update/root", func(ctx *gin.Context) { - fmt.Println("UpdateFileRoot") authPayload := ctx.MustGet(constant.AuthorizationPayloadKey).(*token.Payload) var form form.UpdateFileRoot @@ -54,14 +52,13 @@ func UpdateFileRoot(router *gin.RouterGroup) { return } - file := entity.File{} - - // Query the database to populate the 'File' entity with existing data. - if err := db.Db().Where("UID = ?", form.Uid).First(&file).Error; err != nil { - log.Errorf("db.Db().Where != nil: %s", err) + // get file + file, err := query.FindFileByUID(form.Uid) + if err != nil { AbortBadRequest(ctx) return } + file.ID = uintID file.UID = form.Uid file.Root = form.Root @@ -72,18 +69,35 @@ func UpdateFileRoot(router *gin.RouterGroup) { return } - // Add select db for return id of file + ctx.JSON(http.StatusOK, file) + }) +} + +func UpdateFileIpfs(router *gin.RouterGroup) { + router.PUT("/update/ipfshash", func(ctx *gin.Context) { + var form form.UpdateFileIpfsHash + if err := ctx.BindJSON(&form); err != nil { + log.Errorf("ctx.BindJSON: %s", err) + AbortBadRequest(ctx) + return + } + + // get file + file, err := query.FindFileByUID(form.Uid) + if err != nil { + AbortBadRequest(ctx) + return + } - //file_user := entity.FileUser{ - //FileID: file.ID, - //UserID: authPayload.UserID, - //Permission: entity.OwnerPermission, - //} + // update ipfshash + file.IPFSHash = &form.IpfsHash - //if err := file_user.Update(); err != nil { - //AbortBadRequest(ctx) - //return - //} + // save ipfshash + if err := file.UpdateIpfsHash(); err != nil { + log.Errorf("file.UpdateIpfsHash != nil: %s", err) + AbortBadRequest(ctx) + return + } ctx.JSON(http.StatusOK, file) }) diff --git a/internal/entity/file.go b/internal/entity/file.go index 1037f55..84558fe 100644 --- a/internal/entity/file.go +++ b/internal/entity/file.go @@ -100,6 +100,11 @@ func (m *File) UpdateRootOnly() error { return db.Db().Model(m).Where("UID = ?", m.UID).Update("Root", m.Root).Error } +// update ipfshash +func (m *File) UpdateIpfsHash() error { + return db.Db().Model(m).Where("UID = ?", m.UID).Update("ipfs_hash", m.IPFSHash).Error +} + // checks if a user is the owner of a file func IsFileOwner(fileID uint, userID uint) (bool, error) { var count int64 diff --git a/internal/form/file.go b/internal/form/file.go index be345ad..c310ea9 100644 --- a/internal/form/file.go +++ b/internal/form/file.go @@ -5,3 +5,8 @@ type UpdateFileRoot struct { Root string `json:"root"` Id string `json:"id"` } + +type UpdateFileIpfsHash struct { + IpfsHash string `json:"ipfs_hash"` + Uid string `json:"uid"` +} \ No newline at end of file diff --git a/internal/server/routes.go b/internal/server/routes.go index ca0ce1c..f493258 100644 --- a/internal/server/routes.go +++ b/internal/server/routes.go @@ -66,6 +66,7 @@ func registerRoutes(router *gin.Engine) { api.GetPublishedFile(FileRoutes) api.EncryptFile(FileRoutes) api.UploadFileMultipart(FileRoutes) + api.UpdateFileIpfs(FileRoutes) api.GetPublishedFileName(router.Group("/api/file")) From 6416d5ced2a9a9bca0f9c12baf210f24e1457df3 Mon Sep 17 00:00:00 2001 From: Keiner Alvarado Date: Thu, 9 May 2024 12:51:04 -0500 Subject: [PATCH 09/27] fix: get files optimization --- internal/api/folder_search.go | 73 +++++++++++------------------------ internal/query/file.go | 31 +-------------- internal/query/folder.go | 14 +------ 3 files changed, 25 insertions(+), 93 deletions(-) diff --git a/internal/api/folder_search.go b/internal/api/folder_search.go index 8810c1a..61caea5 100644 --- a/internal/api/folder_search.go +++ b/internal/api/folder_search.go @@ -1,7 +1,6 @@ package api import ( - "fmt" "net/http" "github.com/Hello-Storage/hello-back/internal/constant" @@ -31,60 +30,34 @@ func SearchFolderByRoot(router *gin.RouterGroup) { authPayload := ctx.MustGet(constant.AuthorizationPayloadKey).(*token.Payload) resp := FolderResponse{Root: root} - if root == "/" { - if folders, err := query.FindRootFoldersByUser(authPayload.UserID); err != nil { - log.Errorf("folder find root by user: %s", err) - - AbortInternalServerError(ctx) - return - } else { - resp.Folders = folders - } - - // files - if files, err := query.FindRootFilesByUser(authPayload.UserID); err != nil { - AbortInternalServerError(ctx) - return - } else { - filesMaped := []entity.File{} - for _, file := range files { - sharestatefound, err := query.GetFileShareStateByFileUIDAndUserID(file.UID, authPayload.UserID) - if err == nil { - file.FileShareState = query.ConvertToDomainEntities(sharestatefound) - }else{ - fmt.Println(err) - } - filesMaped = append(filesMaped, file) - } - resp.Files = filesMaped - } + if root == "" { + root = "/" + } + + if folders, err := query.FoldersByRoot(root); err != nil { + log.Errorf("folders by root: %s", err) + AbortInternalServerError(ctx) + return } else { - if folders, err := query.FoldersByRoot(root); err != nil { - log.Errorf("folders by root: %s", err) - - AbortInternalServerError(ctx) - return - } else { - resp.Folders = folders - } + resp.Folders = folders + } - // files - if files, err := query.FindFilesByRoot(root); err != nil { - log.Errorf("file: %s", err) - AbortInternalServerError(ctx) - return - } else { - filesMaped := []entity.File{} - for _, file := range files { - sharestatefound, err := query.GetFileShareStateByFileUIDAndUserID(file.UID, authPayload.UserID) - if err == nil { - file.FileShareState = query.ConvertToDomainEntities(sharestatefound) - } - filesMaped = append(filesMaped, file) + // files + if files, err := query.FindFilesByRoot(root); err != nil { + log.Errorf("file: %s", err) + AbortInternalServerError(ctx) + return + } else { + filesMaped := []entity.File{} + for _, file := range files { + sharestatefound, err := query.GetFileShareStateByFileUIDAndUserID(file.UID, authPayload.UserID) + if err == nil { + file.FileShareState = query.ConvertToDomainEntities(sharestatefound) } - resp.Files = filesMaped + filesMaped = append(filesMaped, file) } + resp.Files = filesMaped } // add path diff --git a/internal/query/file.go b/internal/query/file.go index f1f9e74..7ac4707 100644 --- a/internal/query/file.go +++ b/internal/query/file.go @@ -76,7 +76,7 @@ func FindFileByCID(cid string) (*entity.File, error) { // FilesByRoot return files in a given folder root. func FindFilesByRoot(root string) (files entity.Files, err error) { - if err := db.Db().Where("root = ?", root).Find(&files).Error; err != nil { + if err := db.Db().Where("root = ? AND deleted_at IS NULL", root).Find(&files).Error; err != nil { return files, err } @@ -198,35 +198,6 @@ func CreateShareState(tx *gorm.DB, file *entity.File) (file_share_state *entity. return file_share_state, nil } -// Query daily storage used by all users in the last 24 hours -// func CountDailyStorage(daystring string) (dailystorage int64, err error) { -// log.Infof("daystring: %s", daystring) - -// query := db.Db().Table("files").Select("SUM(size)") - -// // Apply the date range filter -// query = query.Where("created_at >= DATE_TRUNC('DAY', TIMESTAMP ?) AND created_at < DATE_TRUNC('DAY', TIMESTAMP ?) + INTERVAL '1 DAY'", daystring, "2023-09-14 17:52:29") - -// // Execute and scan the result -// if err := query.Scan(&dailystorage).Error; err != nil { -// return dailystorage, err -// } - -// return dailystorage, nil -// } - -func FindRootFilesByUser(user_id uint) (files entity.Files, err error) { - if err := db.Db(). - Table("files"). - Joins("LEFT JOIN files_users on files_users.file_id = files.id"). - Where("files.root = '/' AND files_users.permission <> 'deleted' AND files_users.user_id = ? AND files.deleted_at IS NULL", user_id). - Find(&files).Error; err != nil { - return files, err - } - - return files, nil -} - func FindUsersByFileCID(cid string) ([]uint, error) { var fileUsers []entity.FileUser var usersWF []uint diff --git a/internal/query/folder.go b/internal/query/folder.go index 028821f..38e347e 100644 --- a/internal/query/folder.go +++ b/internal/query/folder.go @@ -35,19 +35,7 @@ func FindFolder(find entity.Folder) *entity.Folder { // FoldersByRoot returns folders in a given directory. func FoldersByRoot(root string) (folders entity.Folders, err error) { - if err := db.Db().Where("root = ?", root).Find(&folders).Error; err != nil { - return folders, err - } - - return folders, nil -} - -func FindRootFoldersByUser(user_id uint) (folders entity.Folders, err error) { - if err := db.Db(). - Table("folders"). - Joins("LEFT JOIN folders_users on folders_users.folder_id = folders.id"). - Where("((folders.root = '/' AND folders_users.permission = 'owner') OR (folders.root = '/' AND folders_users.permission = 'shared')) AND folders_users.user_id = ?", user_id). - Find(&folders).Error; err != nil { + if err := db.Db().Where("root = ? AND deleted_at IS NULL", root).Find(&folders).Error; err != nil { return folders, err } From d6107de3eaf1edffa1dca25dd4eb0f3f3438f601 Mon Sep 17 00:00:00 2001 From: Keiner Alvarado Date: Thu, 9 May 2024 14:30:28 -0500 Subject: [PATCH 10/27] fix: name fixes --- internal/api/file_update.go | 2 +- internal/entity/file.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/api/file_update.go b/internal/api/file_update.go index c8a361b..3875e71 100644 --- a/internal/api/file_update.go +++ b/internal/api/file_update.go @@ -90,7 +90,7 @@ func UpdateFileIpfs(router *gin.RouterGroup) { } // update ipfshash - file.IPFSHash = &form.IpfsHash + file.IPFSHash = form.IpfsHash // save ipfshash if err := file.UpdateIpfsHash(); err != nil { diff --git a/internal/entity/file.go b/internal/entity/file.go index 84558fe..c49b188 100644 --- a/internal/entity/file.go +++ b/internal/entity/file.go @@ -39,9 +39,9 @@ type File struct { DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at"` Path string `gorm:"type:varchar(1024);" json:"path"` // full path IsInPool *bool `gorm:"type:boolean;default:false;" json:"is_in_pool"` - IPFSHash *string `gorm:"type:varchar(256);default:NULL" json:"ipfs_hash"` + IPFSHash string `gorm:"type:varchar(256);default:NULL" json:"ipfs_hash"` //sharestates are referenced by this file's UID at file share state - FileShareState FileShareState `gorm:"foreignKey:FileUID;references:UID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"file_share_state"` + FileShareState FileShareState `gorm:"foreignKey:FileUID;references:UID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"file_share_state"` EncryptionStatus EncryptionStatus `gorm:"type:encryption_status;default:'public'" json:"encryption_status"` } @@ -102,7 +102,7 @@ func (m *File) UpdateRootOnly() error { // update ipfshash func (m *File) UpdateIpfsHash() error { - return db.Db().Model(m).Where("UID = ?", m.UID).Update("ipfs_hash", m.IPFSHash).Error + return db.Db().Model(m).Where("UID = ?", m.UID).Update("IPFSHash", m.IPFSHash).Error } // checks if a user is the owner of a file From e7236654fa00098a8ec6b23f7d565dbc077f0945 Mon Sep 17 00:00:00 2001 From: Keiner Alvarado Date: Sat, 11 May 2024 09:25:21 -0500 Subject: [PATCH 11/27] fix file & folder permision search --- internal/api/folder_search.go | 5 ++--- internal/query/file.go | 10 +++++++++- internal/query/folder.go | 8 ++++++++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/internal/api/folder_search.go b/internal/api/folder_search.go index 61caea5..10d540a 100644 --- a/internal/api/folder_search.go +++ b/internal/api/folder_search.go @@ -34,9 +34,8 @@ func SearchFolderByRoot(router *gin.RouterGroup) { root = "/" } - if folders, err := query.FoldersByRoot(root); err != nil { + if folders, err := query.FoldersByRootWithPermision(root, authPayload.UserID); err != nil { log.Errorf("folders by root: %s", err) - AbortInternalServerError(ctx) return } else { @@ -44,7 +43,7 @@ func SearchFolderByRoot(router *gin.RouterGroup) { } // files - if files, err := query.FindFilesByRoot(root); err != nil { + if files, err := query.FindFilesByRootWithPermision(root, authPayload.UserID); err != nil { log.Errorf("file: %s", err) AbortInternalServerError(ctx) return diff --git a/internal/query/file.go b/internal/query/file.go index 7ac4707..41bc25e 100644 --- a/internal/query/file.go +++ b/internal/query/file.go @@ -80,8 +80,16 @@ func FindFilesByRoot(root string) (files entity.Files, err error) { return files, err } - return files, err + return files, nil } +func FindFilesByRootWithPermision(root string, userId uint) (files entity.Files, err error) { + if err := db.Db().Table("files").Joins("INNER JOIN files_users ON files_users.file_id = files.id").Where("files.root = ? AND files_users.user_id = ? AND files.deleted_at IS NULL", root, userId).Find(&files).Error; err != nil { + return files, err + } + + return files, nil +} + // FindSharedFilesByRoot returns shared files in a given folder root. func FindPublicFilesByRoot(root string) (publicFiles []entity.PublicFile, err error) { diff --git a/internal/query/folder.go b/internal/query/folder.go index 38e347e..9862a58 100644 --- a/internal/query/folder.go +++ b/internal/query/folder.go @@ -42,6 +42,14 @@ func FoldersByRoot(root string) (folders entity.Folders, err error) { return folders, nil } +func FoldersByRootWithPermision(root string,userId uint) (folders entity.Folders, err error) { + if err := db.Db().Table("folders").Joins("INNER JOIN folders_users ON folders_users.folder_id = folders.id").Where("folders.root = ? AND folders_users.user_id = ? AND folders.deleted_at IS NULL", root,userId).Find(&folders).Error; err != nil { + return folders, err + } + + return folders, nil +} + func FindFolderByTitleAndRoot(title, root string) *entity.Folder { m := &entity.Folder{} From 2acb223f4bc514ec57297515d6f7b105a15b8c2c Mon Sep 17 00:00:00 2001 From: Keiner Alvarado Date: Sat, 11 May 2024 09:53:25 -0500 Subject: [PATCH 12/27] fix: migration errors --- internal/entity/invest_account.go | 2 +- internal/entity/invest_code.go | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/entity/invest_account.go b/internal/entity/invest_account.go index f5b9973..4059ee4 100644 --- a/internal/entity/invest_account.go +++ b/internal/entity/invest_account.go @@ -14,7 +14,7 @@ type InvestAccount struct { UpdatedAt time.Time ` json:"updated_at"` DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at"` Code string `gorm:"type:varchar(64);index" json:"code"` - InvestCode InvestCode `gorm:"foreignKey:Code;references:Code" json:"-"` + InvestCode InvestCode `gorm:"foreignKey:Code" json:"-"` } // TableName returns the entity table name. diff --git a/internal/entity/invest_code.go b/internal/entity/invest_code.go index d7a9151..ebd37d0 100644 --- a/internal/entity/invest_code.go +++ b/internal/entity/invest_code.go @@ -7,7 +7,6 @@ import ( type InvestCode struct { Code string `gorm:"primarykey" json:"code"` SocialNetwork string `gorm:"type:varchar(64)" json:"social_network"` - InvestAccounts []InvestAccount `gorm:"foreignKey:Code;references:Code"` } // TableName returns the entity table name. From d16033b69ba87f381dff4d0af08bd73c46f133a1 Mon Sep 17 00:00:00 2001 From: Keiner Alvarado Date: Sat, 11 May 2024 09:59:46 -0500 Subject: [PATCH 13/27] fix: migration errors --- internal/entity/invest_account.go | 1 - internal/entity/invest_code.go | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/entity/invest_account.go b/internal/entity/invest_account.go index 4059ee4..f591ef1 100644 --- a/internal/entity/invest_account.go +++ b/internal/entity/invest_account.go @@ -14,7 +14,6 @@ type InvestAccount struct { UpdatedAt time.Time ` json:"updated_at"` DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at"` Code string `gorm:"type:varchar(64);index" json:"code"` - InvestCode InvestCode `gorm:"foreignKey:Code" json:"-"` } // TableName returns the entity table name. diff --git a/internal/entity/invest_code.go b/internal/entity/invest_code.go index ebd37d0..d7a9151 100644 --- a/internal/entity/invest_code.go +++ b/internal/entity/invest_code.go @@ -7,6 +7,7 @@ import ( type InvestCode struct { Code string `gorm:"primarykey" json:"code"` SocialNetwork string `gorm:"type:varchar(64)" json:"social_network"` + InvestAccounts []InvestAccount `gorm:"foreignKey:Code;references:Code"` } // TableName returns the entity table name. From 27c952ffe0a61702a7afb931d16d5fbb8ccca36e Mon Sep 17 00:00:00 2001 From: Jefferson Baldion Date: Sun, 26 May 2024 11:13:07 -0500 Subject: [PATCH 14/27] Update file_share_state_user_shared.go --- internal/entity/file_share_state_user_shared.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/entity/file_share_state_user_shared.go b/internal/entity/file_share_state_user_shared.go index 0b55b98..cccf231 100644 --- a/internal/entity/file_share_state_user_shared.go +++ b/internal/entity/file_share_state_user_shared.go @@ -9,7 +9,7 @@ type FileShareStatesUserShared struct { ID uint `gorm:"primarykey" json:"id"` FileUID string `gorm:"type:varchar(42);index;references:UID;referencedTable:files" json:"file_uid"` UserID uint `gorm:"type:int" json:"user_id"` - PublicFileUserShared PublicFileUserShared `gorm:"foreignKey:FileUID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"public_file"` + PublicFileUserShared PublicFileUserShared `gorm:"foreignKey:FileUID;reference:FileUID"` } func (FileShareStatesUserShared) TableName() string { From a22606aa2ec08b1b94d0b0689d14dc596cf59e87 Mon Sep 17 00:00:00 2001 From: Onetti01 Date: Fri, 23 Aug 2024 20:13:15 +0200 Subject: [PATCH 15/27] test: creating folder testing --- internal/api/folder.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/api/folder.go b/internal/api/folder.go index 4cade06..f71f699 100644 --- a/internal/api/folder.go +++ b/internal/api/folder.go @@ -184,6 +184,7 @@ func ShareWithUserHandler(formget form.SharedFolder, parentRoot string, authPayl return true } + // ShareFolderHandler handles the sharing of a folder. // // It takes a form.SharedFolder and a shareType string as parameters and returns a boolean. @@ -306,6 +307,7 @@ func CreateFolder(router *gin.RouterGroup) { var form form.CreateFolder if err := ctx.BindJSON(&form); err != nil { + log.Errorf("error when creating folder_user: %v", err) AbortBadRequest(ctx) return } @@ -320,6 +322,7 @@ func CreateFolder(router *gin.RouterGroup) { } if err := folder.Create(); err != nil { + log.Errorf("error when creating folder_user: %v", err) AbortBadRequest(ctx) return } @@ -331,6 +334,7 @@ func CreateFolder(router *gin.RouterGroup) { } if err := folder_user.Create(); err != nil { + log.Errorf("error when creating folder_user: %v", err) AbortBadRequest(ctx) return } From c951006738502c22d560efe97e70f9bc92fbc97b Mon Sep 17 00:00:00 2001 From: alexanderbkl Date: Wed, 28 Aug 2024 18:55:42 +0200 Subject: [PATCH 16/27] remove redundant logs and redundant migration checker, refactor database orm to prevent migration failure --- internal/api/auth.go | 2 - internal/api/file_upload.go | 6 +- internal/entity/entity_init.go | 1 - internal/entity/entity_tables.go | 74 ++++++++----------- internal/entity/file.go | 5 +- .../entity/file_share_state_user_shared.go | 4 +- 6 files changed, 38 insertions(+), 54 deletions(-) diff --git a/internal/api/auth.go b/internal/api/auth.go index ac893c4..552ddf2 100644 --- a/internal/api/auth.go +++ b/internal/api/auth.go @@ -91,8 +91,6 @@ func LoginUser(router *gin.RouterGroup, tokenMaker token.Maker) { return } - log.Infof("nonce: %s", nonce) - // validate signature result := web3.ValidateMessageSignature( f.WalletAddress, diff --git a/internal/api/file_upload.go b/internal/api/file_upload.go index 27b1521..c3c9607 100644 --- a/internal/api/file_upload.go +++ b/internal/api/file_upload.go @@ -66,9 +66,6 @@ func CheckFilesExistInPool(router *gin.RouterGroup) { headObject, err := s3.HeadObject(s3Config, config.Env().WasabiBucket, customFileMeta.CID) if err != nil { //this means that the object doesn't exist at S3, so we can return CID to frontend for later upload of binary and metadata - log.Info("CID not found:") - log.Info(customFileMeta.CID) - } else { //this means that the object exists at S3, so we can create a file entry on database for the file @@ -155,7 +152,8 @@ func CheckFilesExistInPool(router *gin.RouterGroup) { } if headObject == nil { - log.Print("headObject is nil") + //file doesn't exist on pool + //log.Print("headObject is nil") } } diff --git a/internal/entity/entity_init.go b/internal/entity/entity_init.go index a65f18f..1841c65 100644 --- a/internal/entity/entity_init.go +++ b/internal/entity/entity_init.go @@ -16,7 +16,6 @@ func InitDb(opt migrate.Options) { start := time.Now() Entities.Migrate(db.Db(), opt) - Entities.WaitForMigration(db.Db()) log.Debugf("migrate: completed in %s", time.Since(start)) } diff --git a/internal/entity/entity_tables.go b/internal/entity/entity_tables.go index 50c011e..5a91d85 100644 --- a/internal/entity/entity_tables.go +++ b/internal/entity/entity_tables.go @@ -4,6 +4,8 @@ import ( "fmt" "time" + "runtime/debug" + "github.com/Hello-Storage/hello-back/internal/migrate" "gorm.io/gorm" ) @@ -12,19 +14,24 @@ type Tables map[string]interface{} // Entities contains database entities and their table names. var Entities = Tables{ - Error{}.TableName(): &Error{}, - User{}.TableName(): &User{}, - UserDetail{}.TableName(): &UserDetail{}, - UserLogin{}.TableName(): &UserLogin{}, - ReferredUser{}.TableName(): &ReferredUser{}, - Plan{}.TableName(): &Plan{}, - Subscription{}.TableName(): &Subscription{}, - Email{}.TableName(): &Email{}, - Wallet{}.TableName(): &Wallet{}, - Github{}.TableName(): &Github{}, - File{}.TableName(): &File{}, - FileShareState{}.TableName(): &FileShareState{}, - PublicFile{}.TableName(): &PublicFile{}, + + Error{}.TableName(): &Error{}, + + User{}.TableName(): &User{}, + UserDetail{}.TableName(): &UserDetail{}, + UserLogin{}.TableName(): &UserLogin{}, + + ReferredUser{}.TableName(): &ReferredUser{}, + Plan{}.TableName(): &Plan{}, + Subscription{}.TableName(): &Subscription{}, + Email{}.TableName(): &Email{}, + Wallet{}.TableName(): &Wallet{}, + Github{}.TableName(): &Github{}, + + File{}.TableName(): &File{}, + FileShareState{}.TableName(): &FileShareState{}, + PublicFile{}.TableName(): &PublicFile{}, + Folder{}.TableName(): &Folder{}, FileUser{}.TableName(): &FileUser{}, FolderUser{}.TableName(): &FolderUser{}, @@ -40,31 +47,6 @@ var Entities = Tables{ InvestAccount{}.TableName(): &InvestAccount{}, } -// WaitForMigration waits for the database migration to be successful. -func (list Tables) WaitForMigration(db *gorm.DB) { - type RowCount struct { - Count int - } - - attempts := 100 - for name := range list { - for i := 0; i <= attempts; i++ { - count := RowCount{} - if err := db.Raw(fmt.Sprintf("SELECT COUNT(*) AS count FROM %s", name)).Scan(&count).Error; err == nil { - log.Tracef("migrate: %s migrated", name) - break - } else { - log.Tracef("migrate: waiting for %s migration (%s)", name, err.Error()) - time.Sleep(100 * time.Millisecond) - } - - if i == attempts { - panic("migration failed") - } - } - } -} - // Truncate removes all data from tables without dropping them. func (list Tables) Truncate(db *gorm.DB) { var name string @@ -93,6 +75,8 @@ func (list Tables) Migrate(db *gorm.DB, opt migrate.Options) { defer func() { if r := recover(); r != nil { log.Errorf("migrate: %s in %s (panic)", r, name) + log.Error("stack trace:\n", string(debug.Stack())) // Print the stack trace + } }() @@ -100,18 +84,21 @@ func (list Tables) Migrate(db *gorm.DB, opt migrate.Options) { // Run pre migrations, if any. if err := migrate.Run(db, opt.Pre()); err != nil { - log.Error(err) + log.Errorf("migrate: pre-migration error: %v", err) } // Run ORM auto migrations. if opt.AutoMigrate { for name, entity = range list { + if name == "users" || name == "wallets" || name == "githubs" { - // if db.Migrator().HasTable(name) { - continue - // } + if db.Migrator().HasTable(name) { + continue + } } if err := db.AutoMigrate(entity); err != nil { + log.Errorf("migrate: initial error migrating %s: %v", name, err) + log.Debugf("migrate: %s (waiting 1s)", err) time.Sleep(time.Second) @@ -126,7 +113,8 @@ func (list Tables) Migrate(db *gorm.DB, opt migrate.Options) { // Run main migrations, if any. if err := migrate.Run(db, opt); err != nil { - log.Error(err) + log.Errorf("migrate: main migration error: %v", err) + } } diff --git a/internal/entity/file.go b/internal/entity/file.go index c49b188..32b35f7 100644 --- a/internal/entity/file.go +++ b/internal/entity/file.go @@ -41,8 +41,9 @@ type File struct { IsInPool *bool `gorm:"type:boolean;default:false;" json:"is_in_pool"` IPFSHash string `gorm:"type:varchar(256);default:NULL" json:"ipfs_hash"` //sharestates are referenced by this file's UID at file share state - FileShareState FileShareState `gorm:"foreignKey:FileUID;references:UID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"file_share_state"` - EncryptionStatus EncryptionStatus `gorm:"type:encryption_status;default:'public'" json:"encryption_status"` + FileShareStatesUserShared FileShareStatesUserShared `gorm:"foreignKey:FileUID;references:UID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"file_share_states_user_shared"` + FileShareState FileShareState `gorm:"foreignKey:FileUID;references:UID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"file_share_state"` + EncryptionStatus EncryptionStatus `gorm:"type:encryption_status;default:'public'" json:"encryption_status"` } // TableName returns the entity table name. diff --git a/internal/entity/file_share_state_user_shared.go b/internal/entity/file_share_state_user_shared.go index cccf231..c5c0396 100644 --- a/internal/entity/file_share_state_user_shared.go +++ b/internal/entity/file_share_state_user_shared.go @@ -7,9 +7,9 @@ import ( type FileShareStatesUserShared struct { ID uint `gorm:"primarykey" json:"id"` - FileUID string `gorm:"type:varchar(42);index;references:UID;referencedTable:files" json:"file_uid"` + FileUID string `gorm:"type:varchar(42);uniqueIndex;references:UID;referencedTable:files" json:"file_uid"` UserID uint `gorm:"type:int" json:"user_id"` - PublicFileUserShared PublicFileUserShared `gorm:"foreignKey:FileUID;reference:FileUID"` + PublicFileUserShared PublicFileUserShared `gorm:"foreignKey:FileUID;references:FileUID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"public_files_user_shared"` } func (FileShareStatesUserShared) TableName() string { From b4e61c6cf3151601a91dc8b635a5eadb58f6372a Mon Sep 17 00:00:00 2001 From: alexanderbkl Date: Wed, 28 Aug 2024 18:57:06 +0200 Subject: [PATCH 17/27] remove obsolete github oauth env parameters --- internal/config/env.go | 8 ++++---- pkg/oauth/github.go | 6 ++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/internal/config/env.go b/internal/config/env.go index 0110b21..4fe3df6 100644 --- a/internal/config/env.go +++ b/internal/config/env.go @@ -24,8 +24,8 @@ type EnvVar struct { DBPassword string DBPort string // Github OAuth credential - GithubClientID string - GithubClientSecret string + //GithubClientID string + //GithubClientSecret string // Wasabi keys WasabiAccessKey string WasabiSecretKey string @@ -76,8 +76,8 @@ func LoadEnv() (err error) { DBPassword: os.Getenv("POSTGRES_PASSWORD"), DBPort: os.Getenv("POSTGRES_PORT"), // Github OAuth credentail - GithubClientID: os.Getenv("GITHUB_CLIENT_ID"), - GithubClientSecret: os.Getenv("GITHUB_CLIENT_SECRET"), + //GithubClientID: os.Getenv("GITHUB_CLIENT_ID"), + //GithubClientSecret: os.Getenv("GITHUB_CLIENT_SECRET"), //Wasabi keys WasabiAccessKey: os.Getenv("WASABI_ACCESS_KEY"), WasabiSecretKey: os.Getenv("WASABI_SECRET_KEY"), diff --git a/pkg/oauth/github.go b/pkg/oauth/github.go index dea1e58..190c39e 100644 --- a/pkg/oauth/github.go +++ b/pkg/oauth/github.go @@ -9,8 +9,6 @@ import ( "net/http" "net/url" "time" - - "github.com/Hello-Storage/hello-back/internal/config" ) type GithubUser struct { @@ -24,8 +22,8 @@ func GetGithubOAuthToken(code string) (string, error) { values := url.Values{} values.Add("code", code) - values.Add("client_id", config.Env().GithubClientID) - values.Add("client_secret", config.Env().GithubClientSecret) + //values.Add("client_id", config.Env().GithubClientID) + //values.Add("client_secret", config.Env().GithubClientSecret) query := values.Encode() From e01291761c6c2b5cefd317f1433eddf19ae18c33 Mon Sep 17 00:00:00 2001 From: alexanderbkl Date: Tue, 10 Sep 2024 03:57:49 +0200 Subject: [PATCH 18/27] updated from deprecated cosmtrek/air to air-verse maker dependency --- docker/Dockerfile.dev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile.dev b/docker/Dockerfile.dev index c859698..cb694f1 100644 --- a/docker/Dockerfile.dev +++ b/docker/Dockerfile.dev @@ -7,7 +7,7 @@ ENV CGO_ENABLED 0 ENV GOPATH /go ENV GOCACHE /go-build -RUN go install github.com/cosmtrek/air@latest +RUN go install github.com/air-verse/air@latest COPY go.mod go.sum ./ From 590cf476fa2c4d5c5fb90ee78931e28314e15ea7 Mon Sep 17 00:00:00 2001 From: alexanderbkl Date: Tue, 10 Sep 2024 07:34:11 +0200 Subject: [PATCH 19/27] fix and improve sharedByMe obtention by checking if filesharestate exists, refactor for scalability && remove unnecessary logs --- internal/api/file.go | 8 ++-- internal/api/user_detail.go | 88 +++++++++++++++++++++++-------------- internal/query/file.go | 7 ++- 3 files changed, 61 insertions(+), 42 deletions(-) diff --git a/internal/api/file.go b/internal/api/file.go index 8d47c4a..1c4cd28 100644 --- a/internal/api/file.go +++ b/internal/api/file.go @@ -143,7 +143,7 @@ func GetShareState(router *gin.RouterGroup) { //get share state, if doesn't exist, create it share_state, _, err := query.FindShareStateByFileUID(file_uid) if err != nil { - log.Errorf("Error finding share state: %s", err) + //log.Errorf("Error finding share state: %s", err) share_state, err = query.CreateShareState(tx, f) if err != nil { log.Errorf("cannot create share state: %s", err) @@ -188,7 +188,7 @@ func GetShareState(router *gin.RouterGroup) { // get share state, if doesn't exist, create it shareState, _, err := query.FindShareStateByFileUID(fileUID) if err != nil { - log.Errorf("Error finding share state: %s", err) + //log.Errorf("Error finding share state: %s", err) shareState, err = query.CreateShareState(tx, f) if err != nil { log.Errorf("cannot create share state: %s", err) @@ -411,7 +411,7 @@ func PublishFile(router *gin.RouterGroup) { ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid share type"}) return } - + //cancel if user not found receiverNil := shareWithUser == nil || shareWithUser.ID == 0 if receiverNil { @@ -458,7 +458,7 @@ func PublishFile(router *gin.RouterGroup) { } // delete the file share state user shared in case it exists - query.DeleteFileShareStatesUserShared(db.Db(),f.UID, shareWithUser.ID) + query.DeleteFileShareStatesUserShared(db.Db(), f.UID, shareWithUser.ID) // create a new share state user shared shareState, err := query.CreateShareStateUserShared(tx, newFile, shareWithUser.ID) if err != nil { diff --git a/internal/api/user_detail.go b/internal/api/user_detail.go index 4bfb8ce..4db57b2 100644 --- a/internal/api/user_detail.go +++ b/internal/api/user_detail.go @@ -72,72 +72,92 @@ func GetUserDetail(router *gin.RouterGroup) { return } - // get user files from the table "file_user" (where permission != deleted) + // get filesUser from the table "file_user" (where permission != deleted) filesUser, err := query.GetFilesUserFromUser(user.ID) if err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": "error fetching user files"}) return } - // start variables for shared files var sharedWithUser entity.Files var sharedByUser entity.Files + sharedByUserMap := make(map[uint]struct{}) + sharedWithUserMap := make(map[string]struct{}) - // iterate over files + // Create a channel to fetch files concurrently + type fileResult struct { + file *entity.File + err error + } + fileChan := make(chan fileResult, len(filesUser)) + + // Fetch files concurrently using goroutines for _, fileUser := range filesUser { - // try to get file by its id - file, err := query.FindFileByID(fileUser.FileID) - if err != nil { - log.Errorf("error fetching file: %v", err) - if err != gorm.ErrRecordNotFound { - // if it's not a "not found" error it means it's probably an internal error, so stop here + go func(fileUser entity.FileUser) { + file, err := query.FindFileByID(fileUser.FileID) + fileChan <- fileResult{file: file, err: err} + }(fileUser) + } + + for _, fileUser := range filesUser { + fileResult := <-fileChan + if fileResult.err != nil { + log.Errorf("error fetching file: %v", fileResult.err) + if fileResult.err != gorm.ErrRecordNotFound { ctx.JSON(http.StatusInternalServerError, gin.H{"error": "error fetching file"}) return } - // if it's a "not found" error, continue with the next file continue } - // get users with file CID + file := fileResult.file + + // Filter files shared by the user + if file.FileShareState.ID != 0 && fileUser.Permission == entity.OwnerPermission { + if _, exists := sharedByUserMap[file.ID]; exists { + continue + } + sharedByUser = append(sharedByUser, *file) + sharedByUserMap[file.ID] = struct{}{} + } + + // Check if the file CID has already been processed + if _, exists := sharedWithUserMap[file.CID]; exists { + continue // Skip processing the file if this CID has already been processed + } + + // Concurrently fetch users with the file CID usersWithFile, err := query.FindUsersByFileCID(file.CID) if err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": "error fetching users with file"}) return } - // filter out usersID that belong to others than the current user - usersWithFileFiltered := []uint{} + // Filter out usersID that belong to others than the current user + usersWithFileFiltered := make([]uint, 0, len(usersWithFile)) for _, usrID := range usersWithFile { if usrID != user.ID { usersWithFileFiltered = append(usersWithFileFiltered, usrID) } } - if file.ID != 0 { - if fileUser.Permission == entity.SharedPermission && len(usersWithFileFiltered) > 0 { - // if the file is shared to current user and its more than one user with the file - // then it's a shared (with the user) file - if file.Root == "/" /*|| !query.IsInSharedFolder(file.Root, authPayload.UserID) */{ - // if the file was shared by email or wallet, we need to get - // the public file and its share state - sharestatefound, err := query.GetFileShareStateByFileUIDAndUserID(file.UID, authPayload.UserID) - if err == nil { - file.FileShareState = query.ConvertToDomainEntities(sharestatefound) - } - sharedWithUser = append(sharedWithUser, *file) - } - } else if fileUser.Permission == entity.OwnerPermission && len(usersWithFileFiltered) > 0 { - // if the file owned by current user and its more than one user with the file - // then it's a shared (by the user) file - if file.Root == "/" /*|| !query.IsInSharedFolder(file.Root, authPayload.UserID) */{ - // TODO: check if the file/forder is in a shared folder or not - // (because if we only show the files in Root, the elements in a non-shared folder will not be shown) - sharedByUser = append(sharedByUser, *file) + if file.ID != 0 && fileUser.Permission == entity.SharedPermission && len(usersWithFileFiltered) > 0 { + if file.Root == "/" { + sharestatefound, err := query.GetFileShareStateByFileUIDAndUserID(file.UID, authPayload.UserID) + if err == nil { + file.FileShareState = query.ConvertToDomainEntities(sharestatefound) } + + sharedWithUser = append(sharedWithUser, *file) + // Mark this CID as processed to avoid duplicate entries + sharedWithUserMap[file.CID] = struct{}{} } } } + // Close the channel after processing + close(fileChan) + // at this point we have all the shared files, now we need to get the folders // get user folders from the table "folder_user" @@ -185,7 +205,7 @@ func GetUserDetail(router *gin.RouterGroup) { if folder.ID != 0 { if folderUser.Permission == entity.SharedPermission && len(usersWithFolderFiltered) > 0 { if folder.Root == "/" /*|| !query.IsInSharedFolder(folder.Root, authPayload.UserID)*/ { - // TODO: check if the file/forder is in a shared folder or not + // TODO: check if the file/forder is in a shared folder or not // (because if we only show the files in Root, the elements in a non-shared folder will not be shown) FoldersharedwithUser = append(FoldersharedwithUser, *folder) } diff --git a/internal/query/file.go b/internal/query/file.go index 41bc25e..2c5f1f5 100644 --- a/internal/query/file.go +++ b/internal/query/file.go @@ -90,7 +90,6 @@ func FindFilesByRootWithPermision(root string, userId uint) (files entity.Files, return files, nil } - // FindSharedFilesByRoot returns shared files in a given folder root. func FindPublicFilesByRoot(root string) (publicFiles []entity.PublicFile, err error) { files, err := FindFilesByRoot(root) @@ -626,7 +625,7 @@ func FindFilesNotInPool() (files entity.Files, err error) { } // get if file is in a shared folder or not -func IsInSharedFolder(fileRoot string, userID uint) (bool) { +func IsInSharedFolder(fileRoot string, userID uint) bool { // if file root is empty or user id is 0, return false if fileRoot == "" || userID == 0 || fileRoot == "/" { @@ -647,11 +646,11 @@ func IsInSharedFolder(fileRoot string, userID uint) (bool) { // get folder user by folder id and user id query = db.Db().Table("folder_users").Select("*"). - Where("user_id = ? AND folder_id = ?", userID, folderID) + Where("user_id = ? AND folder_id = ?", userID, folderID) var folderUser entity.FolderUser - if err := query.Scan(&folderUser) .Error; err != nil { + if err := query.Scan(&folderUser).Error; err != nil { return false } From ceb00634c1c983ff7dd300c3e4bc89c3bdc512db Mon Sep 17 00:00:00 2001 From: alexanderbkl Date: Tue, 10 Sep 2024 07:39:10 +0200 Subject: [PATCH 20/27] readded TODO comments --- internal/api/user_detail.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/internal/api/user_detail.go b/internal/api/user_detail.go index 4db57b2..0bd299d 100644 --- a/internal/api/user_detail.go +++ b/internal/api/user_detail.go @@ -117,6 +117,9 @@ func GetUserDetail(router *gin.RouterGroup) { if _, exists := sharedByUserMap[file.ID]; exists { continue } + /*|| !query.IsInSharedFolder(file.Root, authPayload.UserID) */ + // TODO: check if the file/forder is in a shared folder or not + // (because if we only show the files in Root, the elements in a non-shared folder will not be shown) sharedByUser = append(sharedByUser, *file) sharedByUserMap[file.ID] = struct{}{} } @@ -143,6 +146,8 @@ func GetUserDetail(router *gin.RouterGroup) { if file.ID != 0 && fileUser.Permission == entity.SharedPermission && len(usersWithFileFiltered) > 0 { if file.Root == "/" { + // TODO: check if the file/forder is in a shared folder or not + // (because if we only show the files in Root, the elements in a non-shared folder will not be shown) sharestatefound, err := query.GetFileShareStateByFileUIDAndUserID(file.UID, authPayload.UserID) if err == nil { file.FileShareState = query.ConvertToDomainEntities(sharestatefound) From 19335838dea29a8c3261faea3d0465c5bde46e71 Mon Sep 17 00:00:00 2001 From: alexanderbkl Date: Thu, 12 Sep 2024 08:28:45 +0200 Subject: [PATCH 21/27] remove redundant code --- internal/api/file.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/internal/api/file.go b/internal/api/file.go index 1c4cd28..478e849 100644 --- a/internal/api/file.go +++ b/internal/api/file.go @@ -484,7 +484,7 @@ func PublishFile(router *gin.RouterGroup) { // Send email with the file link to the user if the share type is email if shareType == "email" { // Send email with the file link to the user and pass also the sender user's email - sendEmailLinkToUser(authPayload.UserName, shareWithUser, accountIdentifier, newFile, publicFile) + sendEmailLinkToUser(authPayload.UserName, accountIdentifier, newFile, publicFile) } // Save the updated shareState.PublicFile @@ -518,7 +518,7 @@ func formatBytes(size int64) string { return fmt.Sprintf("%.1f %cB", float64(size)/float64(div), "KMGTPE"[exp]) } -func sendEmailLinkToUser(username string, user *entity.User, email string, file *entity.File, publicFile *entity.PublicFileUserShared) { +func sendEmailLinkToUser(username string, email string, file *entity.File, publicFile *entity.PublicFileUserShared) { mg := mg.Mailgun{ Domain: "hello.app", @@ -526,7 +526,8 @@ func sendEmailLinkToUser(username string, user *entity.User, email string, file } mg.Init() - id, err := mg.SendEmail( + //id, err := mg.SendEmail( + _, err := mg.SendEmail( "noreply@hello.app", email, "hello.app | Received file named "+file.Name+"", @@ -540,7 +541,7 @@ func sendEmailLinkToUser(username string, user *entity.User, email string, file }, ) - log.Infof("id: %s", id) + //log.Infof("id: %s", id) if err != nil { log.Errorf("failed to send email: %v", err) From c26f4a92f646d072492e16a496d4e4e31df8b323 Mon Sep 17 00:00:00 2001 From: alexanderbkl Date: Thu, 12 Sep 2024 08:52:23 +0200 Subject: [PATCH 22/27] remove deprecated circleci docker verioning --- .circleci/config.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 16fed6b..216ca2b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -52,7 +52,6 @@ jobs: steps: - checkout - setup_remote_docker: - version: 20.10.14 docker_layer_caching: true - build-docker-image - run: @@ -67,7 +66,6 @@ jobs: steps: - checkout - setup_remote_docker: - version: 20.10.14 docker_layer_caching: true - attach_workspace: at: /tmp/workspace From e2fcc0f5aa33bba20446859c8acbfe9c4bca074d Mon Sep 17 00:00:00 2001 From: alexanderbkl Date: Thu, 12 Sep 2024 11:02:47 +0200 Subject: [PATCH 23/27] prevent getting shared files on main files page --- internal/query/file.go | 2 +- internal/query/file_share.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/query/file.go b/internal/query/file.go index 2c5f1f5..abe0002 100644 --- a/internal/query/file.go +++ b/internal/query/file.go @@ -83,7 +83,7 @@ func FindFilesByRoot(root string) (files entity.Files, err error) { return files, nil } func FindFilesByRootWithPermision(root string, userId uint) (files entity.Files, err error) { - if err := db.Db().Table("files").Joins("INNER JOIN files_users ON files_users.file_id = files.id").Where("files.root = ? AND files_users.user_id = ? AND files.deleted_at IS NULL", root, userId).Find(&files).Error; err != nil { + if err := db.Db().Table("files").Joins("INNER JOIN files_users ON files_users.file_id = files.id").Where("files.root = ? AND files.c_id_original_encrypted NOT LIKE '' AND files_users.user_id = ? AND files.deleted_at IS NULL", root, userId).Find(&files).Error; err != nil { return files, err } diff --git a/internal/query/file_share.go b/internal/query/file_share.go index bf2cd93..613c5f9 100644 --- a/internal/query/file_share.go +++ b/internal/query/file_share.go @@ -157,7 +157,7 @@ func DeleteFileShareStatesUserShared(db *gorm.DB, fileUID string, userID uint) e // Check if the error is due to the record not being found, which isn't considered an error in this context. if errors.Is(result.Error, gorm.ErrRecordNotFound) { // Possibly log this as info or debug, as it's an expected situation that doesn't require an action. - log.Infof("No file share state found for UID: %s, UserID: %d. Nothing to delete.", fileUID, userID) + //log.Infof("No file share state found for UID: %s, UserID: %d. Nothing to delete.", fileUID, userID) // Return nil to continue the transaction without considering this as an error. return nil } else { @@ -168,9 +168,9 @@ func DeleteFileShareStatesUserShared(db *gorm.DB, fileUID string, userID uint) e } db.Unscoped().Delete(&fileShareState.PublicFileUserShared) - db.Unscoped().Delete(&fileShareState); // Perform the second delete operation only if the previous operations were successful. + db.Unscoped().Delete(&fileShareState) // Perform the second delete operation only if the previous operations were successful. db.Unscoped().Where("file_uid = ?", fileUID).Delete(&filepublicf) - + // If everything was successful, return nil indicating no error occurred. return nil } @@ -183,7 +183,7 @@ func DeleteFileShareState(tx *gorm.DB, fileUID string) { if result.Error == nil { tx.Unscoped().Delete(&fileShareState.PublicFile) tx.Unscoped().Delete(&fileShareState) - // if error is record not found, ignore it + // if error is record not found, ignore it } else if !errors.Is(result.Error, gorm.ErrRecordNotFound) { log.Errorf("Error while finding file share state: %v", result.Error) } From 6d04faca16da5e1407ad2ee282e620dcb899c639 Mon Sep 17 00:00:00 2001 From: alexanderbaikal Date: Sat, 19 Apr 2025 22:12:14 +0200 Subject: [PATCH 24/27] feat/bump modules --- go.mod | 55 ++++++++++----- go.sum | 215 ++++++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 205 insertions(+), 65 deletions(-) diff --git a/go.mod b/go.mod index b677264..39df2d6 100644 --- a/go.mod +++ b/go.mod @@ -1,14 +1,17 @@ module github.com/Hello-Storage/hello-back -go 1.18 +go 1.23 + +toolchain go1.24.1 require ( + github.com/davecgh/go-spew v1.1.1 github.com/ethereum/go-ethereum v1.12.0 github.com/gin-contrib/cors v1.4.0 github.com/gin-gonic/gin v1.9.1 - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.6.0 github.com/googollee/go-socket.io v1.7.0 - github.com/gorilla/websocket v1.5.0 + github.com/gorilla/websocket v1.5.3 github.com/joho/godotenv v1.5.1 github.com/leandro-lugaresi/hub v1.1.1 github.com/magiconair/properties v1.8.7 @@ -18,39 +21,52 @@ require ( github.com/pquerna/otp v1.4.0 github.com/redis/go-redis/v9 v9.1.0 github.com/sirupsen/logrus v1.9.3 - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 github.com/tidwall/gjson v1.14.4 - golang.org/x/time v0.0.0-20220922220347-f3bd1da661af + golang.org/x/time v0.6.0 ) require ( + dario.cat/mergo v1.0.1 // indirect github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect github.com/aead/chacha20poly1305 v0.0.0-20201124145622-1a5aba2a8b29 // indirect github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 // indirect + github.com/air-verse/air v1.61.7 // indirect + github.com/bep/godartsass v1.2.0 // indirect + github.com/bep/godartsass/v2 v2.1.0 // indirect + github.com/bep/golibsass v1.2.0 // indirect github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect github.com/bytedance/sonic v1.10.0-rc2 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect github.com/chenzhuoyu/iasm v0.9.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/cli/safeexec v1.0.1 // indirect + github.com/creack/pty v1.1.23 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/fatih/color v1.17.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-chi/chi/v5 v5.0.8 // 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.1 // indirect + github.com/gobwas/glob v0.2.3 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/gofrs/uuid v4.0.0+incompatible // indirect + github.com/gohugoio/hugo v0.134.3 // indirect + github.com/golang/protobuf v1.5.3 // indirect github.com/gomodule/redigo v1.8.4 // indirect - github.com/google/go-cmp v0.5.9 // indirect + github.com/google/go-cmp v0.6.0 // indirect github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/leodido/go-urn v1.2.4 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect github.com/minio/sha256-simd v1.0.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect @@ -60,32 +76,39 @@ require ( github.com/multiformats/go-base36 v0.1.0 // indirect github.com/multiformats/go-multibase v0.0.3 // indirect github.com/multiformats/go-varint v0.0.6 // indirect - github.com/pelletier/go-toml/v2 v2.0.9 // indirect + github.com/pelletier/go-toml v1.9.5 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.7.0 // indirect + github.com/tdewolff/parse/v2 v2.7.15 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect golang.org/x/arch v0.4.0 // indirect - golang.org/x/net v0.17.0 // indirect - google.golang.org/protobuf v1.31.0 // indirect + golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect + golang.org/x/net v0.28.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) require ( - github.com/aws/aws-sdk-go v1.44.332 + github.com/aws/aws-sdk-go v1.55.5 github.com/ipfs/go-cid v0.4.1 github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/pgx/v5 v5.3.1 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/multiformats/go-multicodec v0.9.0 - golang.org/x/crypto v0.17.0 - golang.org/x/sys v0.15.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/crypto v0.26.0 + golang.org/x/sys v0.25.0 // indirect + golang.org/x/text v0.18.0 // indirect gorm.io/driver/postgres v1.5.2 gorm.io/gorm v1.25.1 ) diff --git a/go.sum b/go.sum index 112df30..244108c 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,13 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= +github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8= +github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o= +github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA= github.com/aead/chacha20poly1305 v0.0.0-20170617001512-233f39982aeb/go.mod h1:UzH9IX1MMqOcwhoNOIjmTQeAxrFgzs50j4golQtXXxU= @@ -8,33 +15,56 @@ github.com/aead/chacha20poly1305 v0.0.0-20201124145622-1a5aba2a8b29 h1:1DcvRPZOd github.com/aead/chacha20poly1305 v0.0.0-20201124145622-1a5aba2a8b29/go.mod h1:UzH9IX1MMqOcwhoNOIjmTQeAxrFgzs50j4golQtXXxU= github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 h1:52m0LGchQBBVqJRyYYufQuIbVqRawmubW3OFGqK1ekw= github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635/go.mod h1:lmLxL+FV291OopO93Bwf9fQLQeLyt33VJRUg5VJ30us= -github.com/aws/aws-sdk-go v1.44.332 h1:Ze+98F41+LxoJUdsisAFThV+0yYYLYw17/Vt0++nFYM= -github.com/aws/aws-sdk-go v1.44.332/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/air-verse/air v1.61.7 h1:MtOZs6wYoYYXm+S4e+ORjkq9BjvyEamKJsHcvko8LrQ= +github.com/air-verse/air v1.61.7/go.mod h1:QW4HkIASdtSnwaYof1zgJCSxd41ebvix10t5ubtm9cg= +github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= +github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bep/godartsass v1.2.0 h1:E2VvQrxAHAFwbjyOIExAMmogTItSKodoKuijNrGm5yU= +github.com/bep/godartsass v1.2.0/go.mod h1:6LvK9RftsXMxGfsA0LDV12AGc4Jylnu6NgHL+Q5/pE8= +github.com/bep/godartsass/v2 v2.1.0 h1:fq5Y1xYf4diu4tXABiekZUCA+5l/dmNjGKCeQwdy+s0= +github.com/bep/godartsass/v2 v2.1.0/go.mod h1:AcP8QgC+OwOXEq6im0WgDRYK7scDsmZCEW62o1prQLo= +github.com/bep/golibsass v1.2.0 h1:nyZUkKP/0psr8nT6GR2cnmt99xS93Ji82ZD9AgOK6VI= +github.com/bep/golibsass v1.2.0/go.mod h1:DL87K8Un/+pWUS75ggYv41bliGiolxzDKWJAq3eJ1MA= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/bsm/ginkgo/v2 v2.9.5 h1:rtVBYPs3+TC5iLUVOis1B9tjLTup7Cj5IfzosKtvTJ0= +github.com/bsm/ginkgo/v2 v2.9.5/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y= +github.com/bsm/gomega v1.26.0/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= github.com/bytedance/sonic v1.10.0-rc2 h1:oDfRZ+4m6AYCOC0GFeOCeYqvBmucy1isvouS2K0cPzo= github.com/bytedance/sonic v1.10.0-rc2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo= github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= +github.com/cli/safeexec v1.0.0/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q= +github.com/cli/safeexec v1.0.1 h1:e/C79PbXF4yYTN/wauC4tviMxEV13BwljGj0N9j+N00= +github.com/cli/safeexec v1.0.1/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8= +github.com/cockroachdb/errors v1.9.1/go.mod h1:2sxOtL2WIc096WSZqZ5h8fa17rdDq9HZOZLBCor4mBk= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 h1:ytcWPaNPhNoGMWEhDvS3zToKcDpRsLuRolQJBVGdozk= +github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811/go.mod h1:Nb5lgvnQ2+oGlE/EyZy4+2/CxRh9KfvCXnag1vtpxVM= github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= +github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.23 h1:4M6+isWdcStXEf15G/RbrMPOQj1dZ7HPZCGwE4kOeP0= +github.com/creack/pty v1.1.23/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= 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= @@ -44,6 +74,8 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/ethereum/go-ethereum v1.12.0 h1:bdnhLPtqETd4m3mS8BGMNvBTf36bO5bx/hxE2zljOa0= github.com/ethereum/go-ethereum v1.12.0/go.mod h1:/oo2X/dZLJjf2mJ6YT9wcWxa4nNJDBKDBU6sFIpx1Gs= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ= @@ -52,9 +84,16 @@ github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojt github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQDg5gKsWoLBOB0n+ZW8s599zru8FJ2/Y= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= +github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o= +github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0= +github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ= github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g= github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= @@ -65,8 +104,10 @@ github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SU github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0= github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E= +github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= 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/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= @@ -77,29 +118,54 @@ github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXS github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k= github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= +github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= 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/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/gohugoio/hugo v0.134.3 h1:Pn2KECXAAQWCd2uryDcmtzVhNJWGF5Pt6CplQvLcWe0= +github.com/gohugoio/hugo v0.134.3/go.mod h1:/1gnGxlWfAzQarxcQ+tMvKw4e/IMBwy0DFbRxORwOtY= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= +github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v1.8.4 h1:Z5JUg94HMTR1XpwBaSH4vq3+PNSIykBLxMdglbw10gg= github.com/gomodule/redigo v1.8.4/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googollee/go-socket.io v1.7.0 h1:ODcQSAvVIPvKozXtUGuJDV3pLwdpBLDs1Uoq/QHIlY8= github.com/googollee/go-socket.io v1.7.0/go.mod h1:0vGP8/dXR9SZUMMD4+xxaGo/lohOw3YWMh2WRiWeKxg= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c h1:DZfsyhDK1hnSS5lH8l+JggqzEleHteTYfutAiVlSUM8= github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= @@ -124,6 +190,7 @@ github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= +github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= @@ -133,11 +200,13 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 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 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leandro-lugaresi/hub v1.1.1 h1:zqp0HzFvj4HtqjMBXM2QF17o6PNmR8MJOChgeKl/aw8= github.com/leandro-lugaresi/hub v1.1.1/go.mod h1:XEFWanhHv6Rt3XlteHMxuNDYi8dJcpJjodpqkU+BtIo= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= @@ -147,11 +216,16 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailgun/mailgun-go/v4 v4.11.0 h1:1cbHVxtf6SP6memOvQpZy7dgmo4Wz/urmpNv3z09rSg= github.com/mailgun/mailgun-go/v4 v4.11.0/go.mod h1:L9s941Lgk7iB3TgywTPz074pK2Ekkg4kgbnAaAyJ2z8= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -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-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= @@ -180,9 +254,12 @@ github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXS github.com/o1egl/paseto v1.0.0 h1:bwpvPu2au176w4IBlhbyUv/S5VPptERIA99Oap5qUd0= github.com/o1egl/paseto v1.0.0/go.mod h1:5HxsZPmw/3RI2pAwGo1HhOOwSdvBpcuVzO7uDkm+CLU= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= -github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0= -github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= 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= @@ -193,17 +270,31 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg= github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI= +github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/redis/go-redis/v9 v9.1.0 h1:137FnGdk+EQdCbye1FW+qOEcY5S+SpY9T0NiuqvtfMY= github.com/redis/go-redis/v9 v9.1.0/go.mod h1:urWj3He21Dj5k4TK1y59xH8Uj6ATueP8AH1cY3lZl4c= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= +github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= +github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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= @@ -217,9 +308,13 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= +github.com/tdewolff/parse/v2 v2.7.15 h1:hysDXtdGZIRF5UZXwpfn3ZWRbm+ru4l53/ajBRGpCTw= +github.com/tdewolff/parse/v2 v2.7.15/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA= +github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= @@ -227,14 +322,15 @@ github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JT github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4= +github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA= +github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= @@ -242,20 +338,27 @@ golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/exp v0.0.0-20230206171751-46f607a40771 h1:xP7rWLUr1e1n2xkK5YB4LI0hPEy3LJC6Wk+D4pGlOJg= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +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-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -264,36 +367,48 @@ golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/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-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/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.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y= -golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= +golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= 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-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= @@ -312,5 +427,7 @@ gorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0= gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8= gorm.io/gorm v1.25.1 h1:nsSALe5Pr+cM3V1qwwQ7rOkw+6UeLrX5O4v3llhHa64= gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= From 66f4bae866ed335759e058ccc7bcf7e7b8a183e0 Mon Sep 17 00:00:00 2001 From: alexanderbaikal Date: Tue, 22 Apr 2025 17:25:07 +0200 Subject: [PATCH 25/27] feat: integrate Ethermail API for email notifications and update environment variables --- .env.example | 5 +- internal/api/file.go | 73 ++++++++++++++++++---------- internal/api/otp_auth.go | 100 +++++++++++++++++++++++++++------------ internal/config/env.go | 8 ++-- 4 files changed, 127 insertions(+), 59 deletions(-) diff --git a/.env.example b/.env.example index e147a68..6eaae32 100644 --- a/.env.example +++ b/.env.example @@ -44,4 +44,7 @@ WASABI_REGION=us-east-1 ENCRYPTION_KEY=ThIS_Is_A_32ByTE_LoNG_STrING_123 -NODEJS_SERVER_ENDPOINT=http://nodejs-server:3000 \ No newline at end of file +NODEJS_SERVER_ENDPOINT=http://nodejs-server:3000 + +ETHERMAIL_API_KEY=ethermail_api_key +ETHERMAIL_API_SECRET=ethermail_api_secret \ No newline at end of file diff --git a/internal/api/file.go b/internal/api/file.go index 478e849..311bddf 100644 --- a/internal/api/file.go +++ b/internal/api/file.go @@ -1,20 +1,21 @@ package api import ( + "bytes" + "encoding/json" "fmt" + "io/ioutil" "math" "net/http" "strconv" "sync" "time" - "github.com/Hello-Storage/hello-back/internal/config" "github.com/Hello-Storage/hello-back/internal/constant" "github.com/Hello-Storage/hello-back/internal/db" "github.com/Hello-Storage/hello-back/internal/entity" "github.com/Hello-Storage/hello-back/internal/form" "github.com/Hello-Storage/hello-back/internal/query" - "github.com/Hello-Storage/hello-back/pkg/mg" "github.com/Hello-Storage/hello-back/pkg/token" "github.com/gin-gonic/gin" ) @@ -484,7 +485,7 @@ func PublishFile(router *gin.RouterGroup) { // Send email with the file link to the user if the share type is email if shareType == "email" { // Send email with the file link to the user and pass also the sender user's email - sendEmailLinkToUser(authPayload.UserName, accountIdentifier, newFile, publicFile) + sendEmailLinkToUser(authPayload.UserName, accountIdentifier, shareWithUser.Wallet.Address, newFile, publicFile) } // Save the updated shareState.PublicFile @@ -518,33 +519,57 @@ func formatBytes(size int64) string { return fmt.Sprintf("%.1f %cB", float64(size)/float64(div), "KMGTPE"[exp]) } -func sendEmailLinkToUser(username string, email string, file *entity.File, publicFile *entity.PublicFileUserShared) { +func sendEmailLinkToUser(username string, email string, recipientWallet string, file *entity.File, publicFile *entity.PublicFileUserShared) { + + emailReq := EmailRequest{ + SenderName: "hello.app", + SenderEmail: "noreply@hello.app", + ToName: username, + ToEmail: email, + Subject: "hello.app | Received file named " + file.Name + "", + ReplyTo: email, + TemplateID: "6807add19d805166a3d1c440", + MergeData: map[string]interface{}{ + "filename": file.Name, + "filesize": formatBytes(file.Size), + "filelink": "https://hello.app/space/shared/public/" + publicFile.ShareHash, + "sendername": username, + "username": email, + "walletAddress": recipientWallet, + }, + } + + //log.Infof("id: %s", id) - mg := mg.Mailgun{ - Domain: "hello.app", - ApiKey: config.Env().MailGunApiKey, + payloadBuf := new(bytes.Buffer) + if err := json.NewEncoder(payloadBuf).Encode(emailReq); err != nil { + log.Errorf("failed to encode payload: %v", err) + return } - mg.Init() - //id, err := mg.SendEmail( - _, err := mg.SendEmail( - "noreply@hello.app", - email, - "hello.app | Received file named "+file.Name+"", - "received-file", - map[string]interface{}{ - "filename": file.Name, - "filesize": formatBytes(file.Size), - "filelink": "https://hello.app/space/shared/public/" + publicFile.ShareHash, - "sendername": username, - "username": email, - }, - ) + req, err := http.NewRequest("POST", ETHERMAIL_API_URL, payloadBuf) + if err != nil { + log.Errorf("failed to create request: %v", err) + return + } - //log.Infof("id: %s", id) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("x-api-key", ETHERMAIL_API_KEY) + req.Header.Set("x-api-secret", ETHERMAIL_API_KEY_SECRET) + client := &http.Client{} + resp, err := client.Do(req) if err != nil { - log.Errorf("failed to send email: %v", err) + log.Errorf("failed to send request: %v", err) + return + } + defer resp.Body.Close() + + body, _ := ioutil.ReadAll(resp.Body) + + if resp.StatusCode != http.StatusCreated { + log.Errorf("unexpected status code: %d, body: %s", resp.StatusCode, string(body)) + return } } diff --git a/internal/api/otp_auth.go b/internal/api/otp_auth.go index cb40195..af8dfa9 100644 --- a/internal/api/otp_auth.go +++ b/internal/api/otp_auth.go @@ -1,7 +1,10 @@ package api import ( + "bytes" + "encoding/json" "errors" + "io/ioutil" "net/http" "strings" "time" @@ -12,12 +15,27 @@ import ( "github.com/Hello-Storage/hello-back/internal/form" "github.com/Hello-Storage/hello-back/internal/query" "github.com/Hello-Storage/hello-back/pkg/crypto" - "github.com/Hello-Storage/hello-back/pkg/mg" "github.com/Hello-Storage/hello-back/pkg/token" "github.com/gin-gonic/gin" "github.com/pquerna/otp/totp" ) +const ETHERMAIL_API_URL = "https://hub-gateway.ethermail.io/v1/transactional-emails" + +var ETHERMAIL_API_KEY = config.Env().EthermailApiKey +var ETHERMAIL_API_KEY_SECRET = config.Env().EthermailApiSecret + +type EmailRequest struct { + SenderName string `json:"sender_name"` + SenderEmail string `json:"sender_email"` + ToName string `json:"to_name"` + ToEmail string `json:"to_email"` + Subject string `json:"subject"` + ReplyTo string `json:"reply_to"` + TemplateID string `json:"template_id"` + MergeData any `json:"merge_data"` +} + // OTP Auth (one-time-passcode auth) // // POST /api/otp/start @@ -32,7 +50,7 @@ func StartOTP(router *gin.RouterGroup) { if err := ctx.ShouldBindJSON(&f); err != nil { log.Errorf("failed to bind json: %v", err) - ctx.JSON(http.StatusBadRequest, ErrorResponse(err,"/otp/start:00000001")) + ctx.JSON(http.StatusBadRequest, ErrorResponse(err, "/otp/start:00000001")) return } @@ -43,7 +61,7 @@ func StartOTP(router *gin.RouterGroup) { }) if err != nil { log.Errorf("failed to generate key: %v", err) - ctx.JSON(http.StatusInternalServerError, ErrorResponse(err,"/otp/start:00000002")) + ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "/otp/start:00000002")) return } @@ -57,8 +75,8 @@ func StartOTP(router *gin.RouterGroup) { isValidEthereumPrivateKey := crypto.IsValidEthereumPrivateKey(f.PrivateKey) if !isValidEthereumAddress || !isValidEthereumPrivateKey { log.Errorf("invalid wallet address or private key") - ctx.JSON(http.StatusBadRequest, - ErrorResponse(errors.New("invalid wallet address or private key") ,"/otp/start:00000003")) + ctx.JSON(http.StatusBadRequest, + ErrorResponse(errors.New("invalid wallet address or private key"), "/otp/start:00000003")) return } @@ -66,7 +84,7 @@ func StartOTP(router *gin.RouterGroup) { if err != nil { log.Errorf("failed to encrypt private key: %v", err) tx.Rollback() - ctx.JSON(http.StatusInternalServerError, ErrorResponse(err,"/otp/start:00000004")) + ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "/otp/start:00000004")) return } @@ -86,7 +104,7 @@ func StartOTP(router *gin.RouterGroup) { if err := u.Create(); err != nil { log.Errorf("failed to create user: %v", err) - ctx.JSON(http.StatusInternalServerError, ErrorResponse(err,"/otp/start:00000005")) + ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "/otp/start:00000005")) return } @@ -99,7 +117,7 @@ func StartOTP(router *gin.RouterGroup) { if err := referral.TxCreate(tx); err != nil { log.Errorf("failed to save referral: %v", err) tx.Rollback() - ctx.JSON(http.StatusInternalServerError, ErrorResponse(err,"/otp/start:00000006")) + ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "/otp/start:00000006")) return } } @@ -116,7 +134,7 @@ func StartOTP(router *gin.RouterGroup) { } if err := user_detail.Create(); err != nil { - ctx.JSON(http.StatusInternalServerError,ErrorResponse(err,"/otp/start:00000007")) + ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "/otp/start:00000007")) return } @@ -125,11 +143,11 @@ func StartOTP(router *gin.RouterGroup) { if err != nil { log.Errorf("failed to create referral: %v", err) - ctx.JSON(http.StatusInternalServerError,ErrorResponse(err,"/otp/start:00000008")) + ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "/otp/start:00000008")) return } } - uSearch = &u; + uSearch = &u } else { email := uSearch.Email @@ -138,12 +156,11 @@ func StartOTP(router *gin.RouterGroup) { if err := email.Save(); err != nil { log.Errorf("failed to save email: %v", err) tx.Rollback() - ctx.JSON(http.StatusInternalServerError, ErrorResponse(err,"/otp/start:00000009")) + ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "/otp/start:00000009")) return } } - userLogin := &entity.UserLogin{ LoginDate: time.Now(), WalletAddr: uSearch.Wallet.Address, @@ -154,38 +171,59 @@ func StartOTP(router *gin.RouterGroup) { tx.Rollback() ctx.JSON( http.StatusInternalServerError, - ErrorResponse(err,"/otp/start:00000010"), + ErrorResponse(err, "/otp/start:00000010"), ) return } code, err := totp.GenerateCode(key.Secret(), time.Now()) if err != nil { - ctx.JSON(http.StatusBadRequest, ErrorResponse(err,"/otp/start:00000011")) + ctx.JSON(http.StatusBadRequest, ErrorResponse(err, "/otp/start:00000011")) return } - mg := mg.Mailgun{ - Domain: "hello.app", - ApiKey: config.Env().MailGunApiKey, + email := EmailRequest{ + SenderName: "hello.app", + SenderEmail: "noreply@hello.app", + ToName: f.Email, + ToEmail: f.Email, + Subject: "Hello from hello.app!", + ReplyTo: f.Email, + TemplateID: "6807a4239d805166a3cebc12", + MergeData: map[string]interface{}{ + "code": code, + "walletAddress": f.WalletAddress, + }, } - mg.Init() - id, err := mg.SendEmail( - "noreply@hello.app", - f.Email, - "Login to hello.app", - "magic-code", - map[string]interface{}{ - "code": code, - }, - ) + payloadBuf := new(bytes.Buffer) + if err := json.NewEncoder(payloadBuf).Encode(email); err != nil { + log.Errorf("failed to encode payload: %v", err) + return + } + + req, err := http.NewRequest("POST", ETHERMAIL_API_URL, payloadBuf) + if err != nil { + log.Errorf("failed to create request: %v", err) + return + } - log.Infof("id: %s", id) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("x-api-key", ETHERMAIL_API_KEY) + req.Header.Set("x-api-secret", ETHERMAIL_API_KEY_SECRET) + client := &http.Client{} + resp, err := client.Do(req) if err != nil { - log.Errorf("failed to send email: %v", err) - ctx.JSON(http.StatusInternalServerError, ErrorResponse(err,"/otp/start:00000012")) + log.Errorf("failed to send request: %v", err) + return + } + defer resp.Body.Close() + + body, _ := ioutil.ReadAll(resp.Body) + + if resp.StatusCode != http.StatusCreated { + log.Errorf("unexpected status code: %d, body: %s", resp.StatusCode, string(body)) return } diff --git a/internal/config/env.go b/internal/config/env.go index 4fe3df6..c95e0b8 100644 --- a/internal/config/env.go +++ b/internal/config/env.go @@ -34,8 +34,9 @@ type EnvVar struct { WasabiRegion string // Encryption EncryptionKey string - // MailGun - MailGunApiKey string + // Mailing Service + EthermailApiKey string + EthermailApiSecret string // Arweave NodejsServerEndpoint string } @@ -87,7 +88,8 @@ func LoadEnv() (err error) { // Encryption EncryptionKey: os.Getenv("ENCRYPTION_KEY"), // MailGun - MailGunApiKey: os.Getenv("MAILGUN_API"), + EthermailApiKey: os.Getenv("ETHERMAIL_API_KEY"), + EthermailApiSecret: os.Getenv("ETHERMAIL_API_SECRET"), // Arweave NodejsServerEndpoint: os.Getenv("NODEJS_SERVER_ENDPOINT"), } From cccebe52b735304c503e9fda0156b44642d5f77e Mon Sep 17 00:00:00 2001 From: alexanderbaikal Date: Tue, 22 Apr 2025 18:02:50 +0200 Subject: [PATCH 26/27] fix: prevent panic during migration for specific entity --- internal/entity/entity_tables.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/internal/entity/entity_tables.go b/internal/entity/entity_tables.go index 5a91d85..f633ba3 100644 --- a/internal/entity/entity_tables.go +++ b/internal/entity/entity_tables.go @@ -105,7 +105,10 @@ func (list Tables) Migrate(db *gorm.DB, opt migrate.Options) { if err = db.AutoMigrate(entity); err != nil { log.Errorf("migrate: failed migrating %s", name) - panic(err) + if name != "public_files_user_shared" { + log.Errorf("migrate: failed migrating %s", name) + panic(err) + } } } } From 477573a7ab16f6d261769f1b84d2302a09726170 Mon Sep 17 00:00:00 2001 From: alexanderbaikal Date: Tue, 22 Apr 2025 18:40:34 +0200 Subject: [PATCH 27/27] refactor: replace hardcoded Ethermail API keys with config values --- internal/api/file.go | 5 +++-- internal/api/otp_auth.go | 16 +++++++--------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/internal/api/file.go b/internal/api/file.go index 311bddf..d6736b5 100644 --- a/internal/api/file.go +++ b/internal/api/file.go @@ -11,6 +11,7 @@ import ( "sync" "time" + "github.com/Hello-Storage/hello-back/internal/config" "github.com/Hello-Storage/hello-back/internal/constant" "github.com/Hello-Storage/hello-back/internal/db" "github.com/Hello-Storage/hello-back/internal/entity" @@ -554,8 +555,8 @@ func sendEmailLinkToUser(username string, email string, recipientWallet string, } req.Header.Set("Content-Type", "application/json") - req.Header.Set("x-api-key", ETHERMAIL_API_KEY) - req.Header.Set("x-api-secret", ETHERMAIL_API_KEY_SECRET) + req.Header.Set("x-api-key", config.Env().EthermailApiKey) + req.Header.Set("x-api-secret", config.Env().EthermailApiSecret) client := &http.Client{} resp, err := client.Do(req) diff --git a/internal/api/otp_auth.go b/internal/api/otp_auth.go index af8dfa9..6522587 100644 --- a/internal/api/otp_auth.go +++ b/internal/api/otp_auth.go @@ -22,9 +22,6 @@ import ( const ETHERMAIL_API_URL = "https://hub-gateway.ethermail.io/v1/transactional-emails" -var ETHERMAIL_API_KEY = config.Env().EthermailApiKey -var ETHERMAIL_API_KEY_SECRET = config.Env().EthermailApiSecret - type EmailRequest struct { SenderName string `json:"sender_name"` SenderEmail string `json:"sender_email"` @@ -196,21 +193,22 @@ func StartOTP(router *gin.RouterGroup) { }, } - payloadBuf := new(bytes.Buffer) - if err := json.NewEncoder(payloadBuf).Encode(email); err != nil { - log.Errorf("failed to encode payload: %v", err) + payloadBytes, err := json.Marshal(email) + if err != nil { + log.Errorf("failed to marshal payload: %v", err) return } - req, err := http.NewRequest("POST", ETHERMAIL_API_URL, payloadBuf) + req, err := http.NewRequest("POST", ETHERMAIL_API_URL, bytes.NewBuffer(payloadBytes)) + if err != nil { log.Errorf("failed to create request: %v", err) return } req.Header.Set("Content-Type", "application/json") - req.Header.Set("x-api-key", ETHERMAIL_API_KEY) - req.Header.Set("x-api-secret", ETHERMAIL_API_KEY_SECRET) + req.Header.Set("x-api-key", config.Env().EthermailApiKey) + req.Header.Set("x-api-secret", config.Env().EthermailApiSecret) client := &http.Client{} resp, err := client.Do(req)