diff --git a/internal/account/handler.go b/internal/account/handler.go index 96c3d6e..84df5b3 100644 --- a/internal/account/handler.go +++ b/internal/account/handler.go @@ -4,50 +4,13 @@ import ( "errors" "github.com/gin-gonic/gin" + "gorm.io/gorm" ) type AccountHandler struct { accountService *AccountService } -type CreateAccountRequest struct { - Username string `json:"username"` - Password string `json:"password"` -} - -type RenameRequest struct { - NewUsername string `json:"new_username"` -} - -type FindByIDRequest struct { - ID uint `json:"id"` -} - -type FindByIDResponse struct { - ID uint `json:"id"` - Username string `json:"username"` -} - -type FindByUsernameRequest struct { - Username string `json:"username"` -} - -type FindByUsernameResponse struct { - ID uint `json:"id"` - Username string `json:"username"` -} - -type ChangePasswordRequest struct { - Username string `json:"username"` - OldPassword string `json:"old_password"` - NewPassword string `json:"new_password"` -} - -type LoginRequest struct { - Username string `json:"username"` - Password string `json:"password"` -} - func NewAccountHandler(accountService *AccountService) *AccountHandler { return &AccountHandler{accountService: accountService} } @@ -78,11 +41,24 @@ func (h *AccountHandler) Rename(c *gin.Context) { c.JSON(400, gin.H{"error": err.Error()}) return } - if err := h.accountService.Rename(c.Request.Context(), accountID, req.NewUsername); err != nil { + token, err := h.accountService.Rename(c.Request.Context(), accountID, req.NewUsername) + if err != nil { + if errors.Is(err, ErrNewUsernameRequired) { + c.JSON(400, gin.H{"error": err.Error()}) + return + } + if errors.Is(err, ErrUsernameTaken) { + c.JSON(409, gin.H{"error": err.Error()}) + return + } + if errors.Is(err, gorm.ErrRecordNotFound) { + c.JSON(404, gin.H{"error": "account not found"}) + return + } c.JSON(500, gin.H{"error": err.Error()}) return } - c.JSON(200, gin.H{"message": "account renamed"}) + c.JSON(200, gin.H{"token": token}) } func (h *AccountHandler) ChangePassword(c *gin.Context) { diff --git a/internal/account/repo.go b/internal/account/repo.go index fcc6796..f4a0e61 100644 --- a/internal/account/repo.go +++ b/internal/account/repo.go @@ -22,12 +22,32 @@ func (ar *AccountRepository) CreateAccount(ctx context.Context, account *Account } func (ar *AccountRepository) Rename(ctx context.Context, id uint, newUsername string) error { - if err := ar.db.WithContext(ctx).Model(&Account{}).Where("id = ?", id).Update("username", newUsername).Error; err != nil { - return err + result := ar.db.WithContext(ctx).Model(&Account{}).Where("id = ?", id).Update("username", newUsername) + if result.Error != nil { + return result.Error + } + if result.RowsAffected == 0 { + return gorm.ErrRecordNotFound } return nil } +func (ar *AccountRepository) RenameWithToken(ctx context.Context, id uint, newUsername string, token string) error { + return ar.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { + result := tx.Model(&Account{}).Where("id = ?", id).Update("username", newUsername) + if result.Error != nil { + return result.Error + } + if result.RowsAffected == 0 { + return gorm.ErrRecordNotFound + } + if err := tx.Model(&Account{}).Where("id = ?", id).Update("token", token).Error; err != nil { + return err + } + return nil + }) +} + func (ar *AccountRepository) ChangePassword(ctx context.Context, id uint, newPassword string) error { if err := ar.db.WithContext(ctx).Model(&Account{}).Where("id = ?", id).Update("password", newPassword).Error; err != nil { return err diff --git a/internal/account/service.go b/internal/account/service.go index 9850b32..f367c7a 100644 --- a/internal/account/service.go +++ b/internal/account/service.go @@ -5,13 +5,20 @@ import ( "errors" "feedsystem_video_go/internal/auth" + "github.com/go-sql-driver/mysql" "golang.org/x/crypto/bcrypt" + "gorm.io/gorm" ) type AccountService struct { accountRepository *AccountRepository } +var ( + ErrUsernameTaken = errors.New("username already exists") + ErrNewUsernameRequired = errors.New("new_username is required") +) + func NewAccountService(accountRepository *AccountRepository) *AccountService { return &AccountService{accountRepository: accountRepository} } @@ -28,11 +35,28 @@ func (as *AccountService) CreateAccount(ctx context.Context, account *Account) e return nil } -func (as *AccountService) Rename(ctx context.Context, accountID uint, newUsername string) error { - if err := as.accountRepository.Rename(ctx, accountID, newUsername); err != nil { - return err +func (as *AccountService) Rename(ctx context.Context, accountID uint, newUsername string) (string, error) { + if newUsername == "" { + return "", ErrNewUsernameRequired } - return nil + + token, err := auth.GenerateToken(accountID, newUsername) + if err != nil { + return "", err + } + + if err := as.accountRepository.RenameWithToken(ctx, accountID, newUsername, token); err != nil { + var mysqlErr *mysql.MySQLError + if errors.As(err, &mysqlErr) && mysqlErr.Number == 1062 { + return "", ErrUsernameTaken + } + if errors.Is(err, gorm.ErrRecordNotFound) { + return "", err + } + return "", err + } + + return token, nil } func (as *AccountService) ChangePassword(ctx context.Context, username, oldPassword, newPassword string) error {