This is an automated email from the ASF dual-hosted git repository. linkinstar pushed a commit to branch dev in repository https://gitbox.apache.org/repos/asf/answer.git
The following commit(s) were added to refs/heads/dev by this push: new def0559a Fix file record and delete files (branding and avatar) (#1335) def0559a is described below commit def0559a5513d711d31bbf066fe4442c7ed30c7d Author: DanielAuerX <72256996+danielau...@users.noreply.github.com> AuthorDate: Fri May 23 09:07:14 2025 +0200 Fix file record and delete files (branding and avatar) (#1335) - [x] create file_record table - [x] avatar and branding files are added to file_record - [x] branding files are being deleted - [x] avatar files are being deleted - [x] reload latest avatar (frontend) after backend state is being updated problems addressed in the pr: - clean up job fails, because it cannot access file_record table - avatar and branding files are not added to the file_record table - avatar and branding files are never deleted - after an avatar is being updated/deleted, the old file is still being requested due to browser caching. This is causing error logs ("no such file or directory") in the backend. cf. conversation in [pr 1326](https://github.com/apache/answer/pull/1326) --------- Co-authored-by: broccoli <lekker.brocc...@gmail.com> Co-authored-by: LinkinStars <linkins...@foxmail.com> --- cmd/wire_gen.go | 8 ++-- internal/base/middleware/avatar.go | 4 +- internal/controller_admin/siteinfo_controller.go | 14 ++++++- internal/migrations/init_data.go | 1 + internal/repo/file_record/file_record_repo.go | 15 +++++++ internal/repo/site_info/siteinfo_repo.go | 15 +++++++ internal/repo/user/user_repo.go | 15 +++++++ internal/service/content/user_service.go | 45 +++++++++++++++++++- .../service/file_record/file_record_service.go | 38 ++++++++++++++++- internal/service/siteinfo/siteinfo_service.go | 49 ++++++++++++++++++++++ .../service/siteinfo_common/siteinfo_service.go | 12 ++++++ internal/service/uploader/upload.go | 18 ++++++-- internal/service/user_common/user.go | 11 +++++ 13 files changed, 232 insertions(+), 13 deletions(-) diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index 702f60df..f98deb42 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -181,7 +181,9 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, metaCommonService := metacommon.NewMetaCommonService(metaRepo) questionCommon := questioncommon.NewQuestionCommon(questionRepo, answerRepo, voteRepo, followRepo, tagCommonService, userCommon, collectionCommon, answerCommon, metaCommonService, configService, activityQueueService, revisionRepo, siteInfoCommonService, dataData) eventQueueService := event_queue.NewEventQueueService() - userService := content.NewUserService(userRepo, userActiveActivityRepo, activityRepo, emailService, authService, siteInfoCommonService, userRoleRelService, userCommon, userExternalLoginService, userNotificationConfigRepo, userNotificationConfigService, questionCommon, eventQueueService) + fileRecordRepo := file_record.NewFileRecordRepo(dataData) + fileRecordService := file_record2.NewFileRecordService(fileRecordRepo, revisionRepo, serviceConf, siteInfoCommonService, userCommon) + userService := content.NewUserService(userRepo, userActiveActivityRepo, activityRepo, emailService, authService, siteInfoCommonService, userRoleRelService, userCommon, userExternalLoginService, userNotificationConfigRepo, userNotificationConfigService, questionCommon, eventQueueService, fileRecordService) captchaRepo := captcha.NewCaptchaRepo(dataData) captchaService := action.NewCaptchaService(captchaRepo) userController := controller.NewUserController(authService, userService, captchaService, emailService, siteInfoCommonService, userNotificationConfigService) @@ -239,7 +241,7 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, reasonService := reason2.NewReasonService(reasonRepo) reasonController := controller.NewReasonController(reasonService) themeController := controller_admin.NewThemeController() - siteInfoService := siteinfo.NewSiteInfoService(siteInfoRepo, siteInfoCommonService, emailService, tagCommonService, configService, questionCommon) + siteInfoService := siteinfo.NewSiteInfoService(siteInfoRepo, siteInfoCommonService, emailService, tagCommonService, configService, questionCommon, fileRecordService) siteInfoController := controller_admin.NewSiteInfoController(siteInfoService) controllerSiteInfoController := controller.NewSiteInfoController(siteInfoCommonService) notificationCommon := notificationcommon.NewNotificationCommon(dataData, notificationRepo, userCommon, activityRepo, followRepo, objService, notificationQueueService, userExternalLoginRepo, siteInfoCommonService) @@ -248,8 +250,6 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, notificationController := controller.NewNotificationController(notificationService, rankService) dashboardService := dashboard.NewDashboardService(questionRepo, answerRepo, commentCommonRepo, voteRepo, userRepo, reportRepo, configService, siteInfoCommonService, serviceConf, reviewService, revisionRepo, dataData) dashboardController := controller.NewDashboardController(dashboardService) - fileRecordRepo := file_record.NewFileRecordRepo(dataData) - fileRecordService := file_record2.NewFileRecordService(fileRecordRepo, revisionRepo, serviceConf, siteInfoCommonService) uploaderService := uploader.NewUploaderService(serviceConf, siteInfoCommonService, fileRecordService) uploadController := controller.NewUploadController(uploaderService) activityActivityRepo := activity.NewActivityRepo(dataData, configService) diff --git a/internal/base/middleware/avatar.go b/internal/base/middleware/avatar.go index 1d246417..98430638 100644 --- a/internal/base/middleware/avatar.go +++ b/internal/base/middleware/avatar.go @@ -21,6 +21,7 @@ package middleware import ( "fmt" + "net/http" "net/url" "os" "path" @@ -62,7 +63,8 @@ func (am *AvatarMiddleware) AvatarThumb() gin.HandlerFunc { filePath, err = am.uploaderService.AvatarThumbFile(ctx, filename, size) if err != nil { log.Error(err) - ctx.Abort() + ctx.AbortWithStatus(http.StatusNotFound) + return } } avatarFile, err := os.ReadFile(filePath) diff --git a/internal/controller_admin/siteinfo_controller.go b/internal/controller_admin/siteinfo_controller.go index cd1b2ab6..8a92daba 100644 --- a/internal/controller_admin/siteinfo_controller.go +++ b/internal/controller_admin/siteinfo_controller.go @@ -28,6 +28,7 @@ import ( "github.com/apache/answer/internal/schema" "github.com/apache/answer/internal/service/siteinfo" "github.com/gin-gonic/gin" + "github.com/segmentfault/pacman/log" ) // SiteInfoController site info controller @@ -274,8 +275,17 @@ func (sc *SiteInfoController) UpdateBranding(ctx *gin.Context) { if handler.BindAndCheck(ctx, req) { return } - err := sc.siteInfoService.SaveSiteBranding(ctx, req) - handler.HandleResponse(ctx, err, nil) + currentBranding, getBrandingErr := sc.siteInfoService.GetSiteBranding(ctx) + if getBrandingErr == nil { + cleanUpErr := sc.siteInfoService.CleanUpRemovedBrandingFiles(ctx, req, currentBranding) + if cleanUpErr != nil { + log.Errorf("failed to clean up removed branding file(s): %v", cleanUpErr) + } + } else { + log.Errorf("failed to get current site branding: %v", getBrandingErr) + } + saveErr := sc.siteInfoService.SaveSiteBranding(ctx, req) + handler.HandleResponse(ctx, saveErr, nil) } // UpdateSiteWrite update site write info diff --git a/internal/migrations/init_data.go b/internal/migrations/init_data.go index 8b853c4d..96151625 100644 --- a/internal/migrations/init_data.go +++ b/internal/migrations/init_data.go @@ -74,6 +74,7 @@ var ( &entity.Badge{}, &entity.BadgeGroup{}, &entity.BadgeAward{}, + &entity.FileRecord{}, &entity.PluginKVStorage{}, } diff --git a/internal/repo/file_record/file_record_repo.go b/internal/repo/file_record/file_record_repo.go index ed081be4..ce486c7a 100644 --- a/internal/repo/file_record/file_record_repo.go +++ b/internal/repo/file_record/file_record_repo.go @@ -82,3 +82,18 @@ func (fr *fileRecordRepo) UpdateFileRecord(ctx context.Context, fileRecord *enti } return } + +// GetFileRecordByURL gets a file record by its url +func (fr *fileRecordRepo) GetFileRecordByURL(ctx context.Context, fileURL string) (record *entity.FileRecord, err error) { + record = &entity.FileRecord{} + session := fr.data.DB.Context(ctx) + exists, err := session.Where("file_url = ? AND status = ?", fileURL, entity.FileRecordStatusAvailable).Get(record) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + return + } + if !exists { + return + } + return record, nil +} diff --git a/internal/repo/site_info/siteinfo_repo.go b/internal/repo/site_info/siteinfo_repo.go index 420e483f..5f95b748 100644 --- a/internal/repo/site_info/siteinfo_repo.go +++ b/internal/repo/site_info/siteinfo_repo.go @@ -101,3 +101,18 @@ func (sr *siteInfoRepo) setCache(ctx context.Context, siteType string, siteInfo log.Error(err) } } + +func (sr *siteInfoRepo) IsBrandingFileUsed(ctx context.Context, filePath string) (bool, error) { + siteInfo := &entity.SiteInfo{} + count, err := sr.data.DB.Context(ctx). + Table("site_info"). + Where(builder.Eq{"type": "branding"}). + And(builder.Like{"content", "%" + filePath + "%"}). + Count(&siteInfo) + + if err != nil { + return false, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + + return count > 0, nil +} diff --git a/internal/repo/user/user_repo.go b/internal/repo/user/user_repo.go index f56e00b8..a85cd79a 100644 --- a/internal/repo/user/user_repo.go +++ b/internal/repo/user/user_repo.go @@ -33,6 +33,7 @@ import ( "github.com/apache/answer/plugin" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" + "xorm.io/builder" "xorm.io/xorm" ) @@ -380,3 +381,17 @@ func decorateByUserCenterUser(original *entity.User, ucUser *plugin.UserCenterBa original.Status = int(ucUser.Status) } } + +func (ur *userRepo) IsAvatarFileUsed(ctx context.Context, filePath string) (bool, error) { + user := &entity.User{} + count, err := ur.data.DB.Context(ctx). + Table("user"). + Where(builder.Like{"avatar", "%" + filePath + "%"}). + Count(&user) + + if err != nil { + return false, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + + return count > 0, nil +} diff --git a/internal/service/content/user_service.go b/internal/service/content/user_service.go index b59790c1..ece3a86d 100644 --- a/internal/service/content/user_service.go +++ b/internal/service/content/user_service.go @@ -23,9 +23,10 @@ import ( "context" "encoding/json" "fmt" + "time" + "github.com/apache/answer/internal/service/event_queue" "github.com/apache/answer/pkg/token" - "time" "github.com/apache/answer/internal/base/constant" questioncommon "github.com/apache/answer/internal/service/question_common" @@ -41,6 +42,7 @@ import ( "github.com/apache/answer/internal/service/activity_common" "github.com/apache/answer/internal/service/auth" "github.com/apache/answer/internal/service/export" + "github.com/apache/answer/internal/service/file_record" "github.com/apache/answer/internal/service/role" "github.com/apache/answer/internal/service/siteinfo_common" usercommon "github.com/apache/answer/internal/service/user_common" @@ -67,6 +69,7 @@ type UserService struct { userNotificationConfigService *user_notification_config.UserNotificationConfigService questionService *questioncommon.QuestionCommon eventQueueService event_queue.EventQueueService + fileRecordService *file_record.FileRecordService } func NewUserService(userRepo usercommon.UserRepo, @@ -82,6 +85,7 @@ func NewUserService(userRepo usercommon.UserRepo, userNotificationConfigService *user_notification_config.UserNotificationConfigService, questionService *questioncommon.QuestionCommon, eventQueueService event_queue.EventQueueService, + fileRecordService *file_record.FileRecordService, ) *UserService { return &UserService{ userCommonService: userCommonService, @@ -97,6 +101,7 @@ func NewUserService(userRepo usercommon.UserRepo, userNotificationConfigService: userNotificationConfigService, questionService: questionService, eventQueueService: eventQueueService, + fileRecordService: fileRecordService, } } @@ -355,6 +360,9 @@ func (us *UserService) UpdateInfo(ctx context.Context, req *schema.UpdateInfoReq } cond := us.formatUserInfoForUpdateInfo(oldUserInfo, req, siteUsers) + + us.cleanUpRemovedAvatar(ctx, oldUserInfo.Avatar, cond.Avatar) + err = us.userRepo.UpdateInfo(ctx, cond) if err != nil { return nil, err @@ -363,6 +371,41 @@ func (us *UserService) UpdateInfo(ctx context.Context, req *schema.UpdateInfoReq return nil, err } +func (us *UserService) cleanUpRemovedAvatar( + ctx context.Context, + oldAvatarJSON string, + newAvatarJSON string, +) { + if oldAvatarJSON == newAvatarJSON { + return + } + + var oldAvatar, newAvatar schema.AvatarInfo + + _ = json.Unmarshal([]byte(oldAvatarJSON), &oldAvatar) + _ = json.Unmarshal([]byte(newAvatarJSON), &newAvatar) + + if len(oldAvatar.Custom) == 0 { + return + } + + // clean up if old is custom and it's either removed or replaced + if oldAvatar.Custom != newAvatar.Custom { + fileRecord, err := us.fileRecordService.GetFileRecordByURL(ctx, oldAvatar.Custom) + if err != nil { + log.Error(err) + return + } + if fileRecord == nil { + log.Warn("no file record found for old avatar url:", oldAvatar.Custom) + return + } + if err := us.fileRecordService.DeleteAndMoveFileRecord(ctx, fileRecord); err != nil { + log.Error(err) + } + } +} + func (us *UserService) formatUserInfoForUpdateInfo( oldUserInfo *entity.User, req *schema.UpdateInfoRequest, siteUsersConf *schema.SiteUsersResp) *entity.User { avatar, _ := json.Marshal(req.Avatar) diff --git a/internal/service/file_record/file_record_service.go b/internal/service/file_record/file_record_service.go index abb98376..29097ba8 100644 --- a/internal/service/file_record/file_record_service.go +++ b/internal/service/file_record/file_record_service.go @@ -24,6 +24,7 @@ import ( "fmt" "os" "path/filepath" + "strings" "time" "github.com/apache/answer/internal/base/constant" @@ -31,6 +32,7 @@ import ( "github.com/apache/answer/internal/service/revision" "github.com/apache/answer/internal/service/service_config" "github.com/apache/answer/internal/service/siteinfo_common" + usercommon "github.com/apache/answer/internal/service/user_common" "github.com/apache/answer/pkg/checker" "github.com/apache/answer/pkg/dir" "github.com/apache/answer/pkg/writer" @@ -44,6 +46,7 @@ type FileRecordRepo interface { GetFileRecordPage(ctx context.Context, page, pageSize int, cond *entity.FileRecord) ( fileRecordList []*entity.FileRecord, total int64, err error) DeleteFileRecord(ctx context.Context, id int) (err error) + GetFileRecordByURL(ctx context.Context, fileURL string) (record *entity.FileRecord, err error) } // FileRecordService file record service @@ -52,6 +55,7 @@ type FileRecordService struct { revisionRepo revision.RevisionRepo serviceConfig *service_config.ServiceConfig siteInfoService siteinfo_common.SiteInfoCommonService + userService *usercommon.UserCommon } // NewFileRecordService new file record service @@ -60,12 +64,14 @@ func NewFileRecordService( revisionRepo revision.RevisionRepo, serviceConfig *service_config.ServiceConfig, siteInfoService siteinfo_common.SiteInfoCommonService, + userService *usercommon.UserCommon, ) *FileRecordService { return &FileRecordService{ fileRecordRepo: fileRecordRepo, revisionRepo: revisionRepo, serviceConfig: serviceConfig, siteInfoService: siteInfoService, + userService: userService, } } @@ -104,6 +110,21 @@ func (fs *FileRecordService) CleanOrphanUploadFiles(ctx context.Context) { if fileRecord.CreatedAt.AddDate(0, 0, 2).After(time.Now()) { continue } + if isBrandingOrAvatarFile(fileRecord.FilePath) { + if strings.Contains(fileRecord.FilePath, constant.BrandingSubPath+"/") { + if fs.siteInfoService.IsBrandingFileUsed(ctx, fileRecord.FilePath) { + continue + } + } else if strings.Contains(fileRecord.FilePath, constant.AvatarSubPath+"/") { + if fs.userService.IsAvatarFileUsed(ctx, fileRecord.FilePath) { + continue + } + } + if err := fs.DeleteAndMoveFileRecord(ctx, fileRecord); err != nil { + log.Error(err) + } + continue + } if checker.IsNotZeroString(fileRecord.ObjectID) { _, exist, err := fs.revisionRepo.GetLastRevisionByObjectID(ctx, fileRecord.ObjectID) if err != nil { @@ -129,7 +150,7 @@ func (fs *FileRecordService) CleanOrphanUploadFiles(ctx context.Context) { } } // Delete and move the file record - if err := fs.deleteAndMoveFileRecord(ctx, fileRecord); err != nil { + if err := fs.DeleteAndMoveFileRecord(ctx, fileRecord); err != nil { log.Error(err) } } @@ -137,6 +158,10 @@ func (fs *FileRecordService) CleanOrphanUploadFiles(ctx context.Context) { } } +func isBrandingOrAvatarFile(filePath string) bool { + return strings.Contains(filePath, constant.BrandingSubPath+"/") || strings.Contains(filePath, constant.AvatarSubPath+"/") +} + func (fs *FileRecordService) PurgeDeletedFiles(ctx context.Context) { deletedPath := filepath.Join(fs.serviceConfig.UploadPath, constant.DeletedSubPath) log.Infof("purge deleted files: %s", deletedPath) @@ -152,7 +177,7 @@ func (fs *FileRecordService) PurgeDeletedFiles(ctx context.Context) { return } -func (fs *FileRecordService) deleteAndMoveFileRecord(ctx context.Context, fileRecord *entity.FileRecord) error { +func (fs *FileRecordService) DeleteAndMoveFileRecord(ctx context.Context, fileRecord *entity.FileRecord) error { // Delete the file record if err := fs.fileRecordRepo.DeleteFileRecord(ctx, fileRecord.ID); err != nil { return fmt.Errorf("delete file record error: %v", err) @@ -170,3 +195,12 @@ func (fs *FileRecordService) deleteAndMoveFileRecord(ctx context.Context, fileRe log.Debugf("delete and move file: %s", fileRecord.FileURL) return nil } + +func (fs *FileRecordService) GetFileRecordByURL(ctx context.Context, fileURL string) (record *entity.FileRecord, err error) { + record, err = fs.fileRecordRepo.GetFileRecordByURL(ctx, fileURL) + if err != nil { + log.Errorf("error retrieving file record by URL: %v", err) + return + } + return +} diff --git a/internal/service/siteinfo/siteinfo_service.go b/internal/service/siteinfo/siteinfo_service.go index 5141faee..a0f4891c 100644 --- a/internal/service/siteinfo/siteinfo_service.go +++ b/internal/service/siteinfo/siteinfo_service.go @@ -22,6 +22,7 @@ package siteinfo import ( "context" "encoding/json" + errpkg "errors" "fmt" "strings" @@ -33,6 +34,7 @@ import ( "github.com/apache/answer/internal/schema" "github.com/apache/answer/internal/service/config" "github.com/apache/answer/internal/service/export" + "github.com/apache/answer/internal/service/file_record" questioncommon "github.com/apache/answer/internal/service/question_common" "github.com/apache/answer/internal/service/siteinfo_common" tagcommon "github.com/apache/answer/internal/service/tag_common" @@ -49,6 +51,7 @@ type SiteInfoService struct { tagCommonService *tagcommon.TagCommonService configService *config.ConfigService questioncommon *questioncommon.QuestionCommon + fileRecordService *file_record.FileRecordService } func NewSiteInfoService( @@ -58,6 +61,7 @@ func NewSiteInfoService( tagCommonService *tagcommon.TagCommonService, configService *config.ConfigService, questioncommon *questioncommon.QuestionCommon, + fileRecordService *file_record.FileRecordService, ) *SiteInfoService { plugin.RegisterGetSiteURLFunc(func() string { @@ -76,6 +80,7 @@ func NewSiteInfoService( tagCommonService: tagCommonService, configService: configService, questioncommon: questioncommon, + fileRecordService: fileRecordService, } } @@ -438,3 +443,47 @@ func (s *SiteInfoService) UpdatePrivilegesConfig(ctx context.Context, req *schem } return } + +func (s *SiteInfoService) CleanUpRemovedBrandingFiles( + ctx context.Context, + newBranding *schema.SiteBrandingReq, + currentBranding *schema.SiteBrandingResp, +) error { + var allErrors []error + currentFiles := map[string]string{ + "logo": currentBranding.Logo, + "mobile_logo": currentBranding.MobileLogo, + "square_icon": currentBranding.SquareIcon, + "favicon": currentBranding.Favicon, + } + + newFiles := map[string]string{ + "logo": newBranding.Logo, + "mobile_logo": newBranding.MobileLogo, + "square_icon": newBranding.SquareIcon, + "favicon": newBranding.Favicon, + } + + for key, currentFile := range currentFiles { + newFile := newFiles[key] + if currentFile != "" && currentFile != newFile { + fileRecord, err := s.fileRecordService.GetFileRecordByURL(ctx, currentFile) + if err != nil { + allErrors = append(allErrors, err) + continue + } + if fileRecord == nil { + err := errpkg.New("file record is nil for key " + key) + allErrors = append(allErrors, err) + continue + } + if err := s.fileRecordService.DeleteAndMoveFileRecord(ctx, fileRecord); err != nil { + allErrors = append(allErrors, err) + } + } + } + if len(allErrors) > 0 { + return errpkg.Join(allErrors...) + } + return nil +} diff --git a/internal/service/siteinfo_common/siteinfo_service.go b/internal/service/siteinfo_common/siteinfo_service.go index f715bc9b..0c896c2b 100644 --- a/internal/service/siteinfo_common/siteinfo_service.go +++ b/internal/service/siteinfo_common/siteinfo_service.go @@ -35,6 +35,7 @@ import ( type SiteInfoRepo interface { SaveByType(ctx context.Context, siteType string, data *entity.SiteInfo) (err error) GetByType(ctx context.Context, siteType string) (siteInfo *entity.SiteInfo, exist bool, err error) + IsBrandingFileUsed(ctx context.Context, filePath string) (bool, error) } // siteInfoCommonService site info common service @@ -56,6 +57,7 @@ type SiteInfoCommonService interface { GetSiteTheme(ctx context.Context) (resp *schema.SiteThemeResp, err error) GetSiteSeo(ctx context.Context) (resp *schema.SiteSeoResp, err error) GetSiteInfoByType(ctx context.Context, siteType string, resp interface{}) (err error) + IsBrandingFileUsed(ctx context.Context, filePath string) bool } // NewSiteInfoCommonService new site info common service @@ -233,3 +235,13 @@ func (s *siteInfoCommonService) GetSiteInfoByType(ctx context.Context, siteType _ = json.Unmarshal([]byte(siteInfo.Content), resp) return nil } + +func (s *siteInfoCommonService) IsBrandingFileUsed(ctx context.Context, filePath string) bool { + used, err := s.siteInfoRepo.IsBrandingFileUsed(ctx, filePath) + if err != nil { + log.Errorf("error checking if branding file is used: %v", err) + // will try again with the next clean up + return true + } + return used +} diff --git a/internal/service/uploader/upload.go b/internal/service/uploader/upload.go index d5cc2dfb..2ae5369d 100644 --- a/internal/service/uploader/upload.go +++ b/internal/service/uploader/upload.go @@ -127,7 +127,13 @@ func (us *uploaderService) UploadAvatarFile(ctx *gin.Context, userID string) (ur newFilename := fmt.Sprintf("%s%s", uid.IDStr12(), fileExt) avatarFilePath := path.Join(constant.AvatarSubPath, newFilename) - return us.uploadImageFile(ctx, fileHeader, avatarFilePath) + url, err = us.uploadImageFile(ctx, fileHeader, avatarFilePath) + if err != nil { + return "", err + } + us.fileRecordService.AddFileRecord(ctx, userID, avatarFilePath, url, string(plugin.UserAvatar)) + return url, nil + } func (us *uploaderService) AvatarThumbFile(ctx *gin.Context, fileName string, size int) (url string, err error) { @@ -149,7 +155,7 @@ func (us *uploaderService) AvatarThumbFile(ctx *gin.Context, fileName string, si filePath := fmt.Sprintf("%s/%s/%s", us.serviceConfig.UploadPath, constant.AvatarSubPath, fileName) avatarFile, err = os.ReadFile(filePath) if err != nil { - return "", errors.InternalServer(reason.UnknownError).WithError(err).WithStack() + return "", errors.NotFound(reason.UnknownError).WithError(err) } reader := bytes.NewReader(avatarFile) img, err := imaging.Decode(reader) @@ -282,7 +288,13 @@ func (us *uploaderService) UploadBrandingFile(ctx *gin.Context, userID string) ( newFilename := fmt.Sprintf("%s%s", uid.IDStr12(), fileExt) avatarFilePath := path.Join(constant.BrandingSubPath, newFilename) - return us.uploadImageFile(ctx, fileHeader, avatarFilePath) + url, err = us.uploadImageFile(ctx, fileHeader, avatarFilePath) + if err != nil { + return "", err + } + us.fileRecordService.AddFileRecord(ctx, userID, avatarFilePath, url, string(plugin.AdminBranding)) + return url, nil + } func (us *uploaderService) uploadImageFile(ctx *gin.Context, file *multipart.FileHeader, fileSubPath string) ( diff --git a/internal/service/user_common/user.go b/internal/service/user_common/user.go index 7f50eafe..3df99261 100644 --- a/internal/service/user_common/user.go +++ b/internal/service/user_common/user.go @@ -60,6 +60,7 @@ type UserRepo interface { GetByEmail(ctx context.Context, email string) (userInfo *entity.User, exist bool, err error) GetUserCount(ctx context.Context) (count int64, err error) SearchUserListByName(ctx context.Context, name string, limit int, onlyStaff bool) (userList []*entity.User, err error) + IsAvatarFileUsed(ctx context.Context, filePath string) (bool, error) } // UserCommon user service @@ -245,3 +246,13 @@ func (us *UserCommon) CacheLoginUserInfo(ctx context.Context, userID string, use } return accessToken, userCacheInfo, nil } + +func (us *UserCommon) IsAvatarFileUsed(ctx context.Context, filePath string) bool { + used, err := us.userRepo.IsAvatarFileUsed(ctx, filePath) + if err != nil { + log.Errorf("error checking if branding file is used: %v", err) + // will try again with the next clean up + return true + } + return used +}