refact: change code struct and fixing little state

This commit is contained in:
pahmiudahgede 2025-02-14 01:25:08 +07:00
parent d6cbd62f1b
commit b741120918
3 changed files with 67 additions and 47 deletions

View File

@ -70,15 +70,15 @@ func (h *UserProfileHandler) UpdateUserPassword(c *fiber.Ctx) error {
return utils.ValidationErrorResponse(c, errors)
}
_, err := h.UserProfileService.UpdateUserPassword(userID, passwordData)
message, err := h.UserProfileService.UpdateUserPassword(userID, passwordData)
if err != nil {
return utils.GenericResponse(c, fiber.StatusBadRequest, err.Error())
}
return utils.GenericResponse(c, fiber.StatusOK, "Password updated successfully")
return utils.GenericResponse(c, fiber.StatusOK, message)
}
func (h *UserProfileHandler) UpdateUserAvatar(c *fiber.Ctx) error {
userID, ok := c.Locals("userID").(string)
if !ok || userID == "" {
return utils.GenericResponse(c, fiber.StatusUnauthorized, "Unauthorized: User session not found")
@ -89,10 +89,10 @@ func (h *UserProfileHandler) UpdateUserAvatar(c *fiber.Ctx) error {
return utils.GenericResponse(c, fiber.StatusBadRequest, "No avatar file uploaded")
}
userResponse, err := h.UserProfileService.UpdateUserAvatar(userID, file)
message, err := h.UserProfileService.UpdateUserAvatar(userID, file)
if err != nil {
return utils.GenericResponse(c, fiber.StatusInternalServerError, err.Error())
}
return utils.SuccessResponse(c, userResponse, "Avatar updated successfully")
return utils.GenericResponse(c, fiber.StatusOK, message)
}

View File

@ -25,6 +25,9 @@ func (r *userProfileRepository) FindByID(userID string) (*model.User, error) {
var user model.User
err := r.DB.Preload("Role").Where("id = ?", userID).First(&user).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, fmt.Errorf("user with ID %s not found", userID)
}
return nil, err
}

View File

@ -16,11 +16,15 @@ import (
"golang.org/x/crypto/bcrypt"
)
const avatarDir = "./public/uploads/avatars"
var allowedExtensions = []string{".jpg", ".jpeg", ".png"}
type UserProfileService interface {
GetUserProfile(userID string) (*dto.UserResponseDTO, error)
UpdateUserProfile(userID string, updateData dto.UpdateUserDTO) (*dto.UserResponseDTO, error)
UpdateUserPassword(userID string, passwordData dto.UpdatePasswordDTO) (string, error)
UpdateUserAvatar(userID string, file *multipart.FileHeader) (*dto.UserResponseDTO, error)
UpdateUserAvatar(userID string, file *multipart.FileHeader) (string, error)
}
type userProfileService struct {
@ -178,68 +182,81 @@ func (s *userProfileService) UpdateUserPassword(userID string, passwordData dto.
return "Password berhasil diupdate", nil
}
func (s *userProfileService) UpdateUserAvatar(userID string, file *multipart.FileHeader) (*dto.UserResponseDTO, error) {
func (s *userProfileService) UpdateUserAvatar(userID string, file *multipart.FileHeader) (string, error) {
avatarDir := "./public/uploads/avatars"
if _, err := os.Stat(avatarDir); os.IsNotExist(err) {
err := os.MkdirAll(avatarDir, os.ModePerm)
if err := ensureAvatarDirectoryExists(); err != nil {
return "", err
}
if err := validateAvatarFile(file); err != nil {
return "", err
}
updatedUser, err := s.UserProfileRepo.FindByID(userID)
if err != nil {
return nil, fmt.Errorf("failed to create avatar directory: %v", err)
return "", fmt.Errorf("failed to retrieve user data: %v", err)
}
if updatedUser.Avatar != nil && *updatedUser.Avatar != "" {
oldAvatarPath := "./public" + *updatedUser.Avatar
if err := os.Remove(oldAvatarPath); err != nil {
return "", fmt.Errorf("failed to remove old avatar: %v", err)
}
}
avatarURL, err := saveAvatarFile(file, userID)
if err != nil {
return "", err
}
err = s.UserProfileRepo.UpdateAvatar(userID, avatarURL)
if err != nil {
return "", fmt.Errorf("failed to update avatar in the database: %v", err)
}
return "Foto profil berhasil diupdate", nil
}
func ensureAvatarDirectoryExists() error {
if _, err := os.Stat(avatarDir); os.IsNotExist(err) {
if err := os.MkdirAll(avatarDir, os.ModePerm); err != nil {
return fmt.Errorf("failed to create avatar directory: %v", err)
}
}
return nil
}
func validateAvatarFile(file *multipart.FileHeader) error {
extension := filepath.Ext(file.Filename)
if extension != ".jpg" && extension != ".jpeg" && extension != ".png" {
return nil, fmt.Errorf("invalid file type, only .jpg, .jpeg, and .png are allowed")
for _, ext := range allowedExtensions {
if extension == ext {
return nil
}
}
return fmt.Errorf("invalid file type, only .jpg, .jpeg, and .png are allowed")
}
func saveAvatarFile(file *multipart.FileHeader, userID string) (string, error) {
extension := filepath.Ext(file.Filename)
avatarFileName := fmt.Sprintf("%s_avatar%s", userID, extension)
avatarPath := filepath.Join(avatarDir, avatarFileName)
src, err := file.Open()
if err != nil {
return nil, fmt.Errorf("failed to open uploaded file: %v", err)
return "", fmt.Errorf("failed to open uploaded file: %v", err)
}
defer src.Close()
dst, err := os.Create(avatarPath)
if err != nil {
return nil, fmt.Errorf("failed to create file: %v", err)
return "", fmt.Errorf("failed to create file: %v", err)
}
defer dst.Close()
_, err = dst.ReadFrom(src)
if err != nil {
return nil, fmt.Errorf("failed to save avatar file: %v", err)
return "", fmt.Errorf("failed to save avatar file: %v", err)
}
avatarURL := fmt.Sprintf("/uploads/avatars/%s", avatarFileName)
err = s.UserProfileRepo.UpdateAvatar(userID, avatarURL)
if err != nil {
return nil, fmt.Errorf("failed to update avatar in the database: %v", err)
}
updatedUser, err := s.UserProfileRepo.FindByID(userID)
if err != nil {
return nil, fmt.Errorf("failed to retrieve updated user data: %v", err)
}
createdAt, _ := utils.FormatDateToIndonesianFormat(updatedUser.CreatedAt)
updatedAt, _ := utils.FormatDateToIndonesianFormat(updatedUser.UpdatedAt)
userResponse := &dto.UserResponseDTO{
ID: updatedUser.ID,
Username: updatedUser.Username,
Avatar: updatedUser.Avatar,
Name: updatedUser.Name,
Phone: updatedUser.Phone,
Email: updatedUser.Email,
EmailVerified: updatedUser.EmailVerified,
RoleName: updatedUser.Role.RoleName,
CreatedAt: createdAt,
UpdatedAt: updatedAt,
}
return userResponse, nil
return fmt.Sprintf("/uploads/avatars/%s", avatarFileName), nil
}