feat: add feature photo profile

This commit is contained in:
pahmiudahgede 2025-02-01 20:06:21 +07:00
parent a31a913658
commit 10ac83cf4e
6 changed files with 101 additions and 0 deletions

View File

@ -8,6 +8,7 @@ import (
type UserResponseDTO struct {
ID string `json:"id"`
Username string `json:"username"`
Avatar *string `json:"photoprofile,omitempty"`
Name string `json:"name"`
Phone string `json:"phone"`
Email string `json:"email"`

View File

@ -77,3 +77,22 @@ func (h *UserProfileHandler) UpdateUserPassword(c *fiber.Ctx) error {
return utils.LogResponse(c, userResponse, "Password updated successfully")
}
func (h *UserProfileHandler) UpdateUserAvatar(c *fiber.Ctx) error {
userID, ok := c.Locals("userID").(string)
if !ok || userID == "" {
return utils.GenericErrorResponse(c, fiber.StatusUnauthorized, "Unauthorized: User session not found")
}
file, err := c.FormFile("avatar")
if err != nil {
return utils.GenericErrorResponse(c, fiber.StatusBadRequest, "No avatar file uploaded")
}
userResponse, err := h.UserProfileService.UpdateUserAvatar(userID, file)
if err != nil {
return utils.GenericErrorResponse(c, fiber.StatusInternalServerError, err.Error())
}
return utils.LogResponse(c, userResponse, "Avatar updated successfully")
}

View File

@ -8,6 +8,7 @@ import (
type UserProfileRepository interface {
FindByID(userID string) (*model.User, error)
Update(user *model.User) error
UpdateAvatar(userID, avatarURL string) error
}
type userProfileRepository struct {
@ -34,3 +35,12 @@ func (r *userProfileRepository) Update(user *model.User) error {
}
return nil
}
func (r *userProfileRepository) UpdateAvatar(userID, avatarURL string) error {
var user model.User
err := r.DB.Model(&user).Where("id = ?", userID).Update("avatar", avatarURL).Error
if err != nil {
return err
}
return nil
}

View File

@ -4,6 +4,9 @@ import (
"encoding/json"
"errors"
"fmt"
"mime/multipart"
"os"
"path/filepath"
"time"
"github.com/pahmiudahgede/senggoldong/dto"
@ -16,6 +19,7 @@ type UserProfileService interface {
GetUserProfile(userID string) (*dto.UserResponseDTO, error)
UpdateUserProfile(userID string, updateData dto.UpdateUserDTO) (*dto.UserResponseDTO, error)
UpdateUserPassword(userID string, passwordData dto.UpdatePasswordDTO) (*dto.UserResponseDTO, error)
UpdateUserAvatar(userID string, file *multipart.FileHeader) (*dto.UserResponseDTO, error)
}
type userProfileService struct {
@ -188,3 +192,69 @@ func (s *userProfileService) UpdateUserPassword(userID string, passwordData dto.
return userResponse, nil
}
func (s *userProfileService) UpdateUserAvatar(userID string, file *multipart.FileHeader) (*dto.UserResponseDTO, error) {
avatarDir := "./public/uploads/avatars"
if _, err := os.Stat(avatarDir); os.IsNotExist(err) {
err := os.MkdirAll(avatarDir, os.ModePerm)
if err != nil {
return nil, fmt.Errorf("failed to create avatar directory: %v", err)
}
}
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")
}
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)
}
defer src.Close()
dst, err := os.Create(avatarPath)
if err != nil {
return nil, 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)
}
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
}

View File

@ -17,4 +17,5 @@ func UserProfileRouter(api fiber.Router) {
api.Get("/user", middleware.AuthMiddleware, userProfileHandler.GetUserProfile)
api.Put("/user/update-user", middleware.AuthMiddleware, userProfileHandler.UpdateUserProfile)
api.Post("/user/update-user-password", middleware.AuthMiddleware, userProfileHandler.UpdateUserPassword)
api.Put("/user/upload-photoprofile", middleware.AuthMiddleware, userProfileHandler.UpdateUserAvatar)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB