package player import ( "log" "strings" "unicode" "github.com/gofiber/fiber/v2" ) type Handler struct { svc *Service } func NewHandler(svc *Service) *Handler { return &Handler{svc: svc} } // GetProfile 자신의 프로필 조회 (JWT 인증) func (h *Handler) GetProfile(c *fiber.Ctx) error { userID, ok := c.Locals("userID").(uint) if !ok { return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "인증 정보가 올바르지 않습니다"}) } profile, err := h.svc.GetProfile(userID) if err != nil { return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(profile) } // UpdateProfile 자신의 프로필 수정 (JWT 인증) func (h *Handler) UpdateProfile(c *fiber.Ctx) error { userID, ok := c.Locals("userID").(uint) if !ok { return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "인증 정보가 올바르지 않습니다"}) } var req struct { Nickname string `json:"nickname"` } if err := c.BodyParser(&req); err != nil { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "잘못된 요청입니다"}) } req.Nickname = strings.TrimSpace(req.Nickname) if req.Nickname != "" { nicknameRunes := []rune(req.Nickname) if len(nicknameRunes) < 2 || len(nicknameRunes) > 30 { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "닉네임은 2~30자여야 합니다"}) } for _, r := range nicknameRunes { if unicode.IsControl(r) { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "닉네임에 허용되지 않는 문자가 포함되어 있습니다"}) } } } profile, err := h.svc.UpdateProfile(userID, req.Nickname) if err != nil { log.Printf("프로필 수정 실패 (userID=%d): %v", userID, err) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "서버 오류가 발생했습니다"}) } return c.JSON(profile) } // InternalGetProfile 내부 API: username 쿼리 파라미터로 프로필 조회 func (h *Handler) InternalGetProfile(c *fiber.Ctx) error { username := c.Query("username") if username == "" { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "username 파라미터가 필요합니다"}) } profile, err := h.svc.GetProfileByUsername(username) if err != nil { return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(profile) } // InternalSaveGameData 내부 API: username 쿼리 파라미터로 게임 데이터 저장 func (h *Handler) InternalSaveGameData(c *fiber.Ctx) error { username := c.Query("username") if username == "" { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "username 파라미터가 필요합니다"}) } var req GameDataRequest if err := c.BodyParser(&req); err != nil { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "잘못된 요청입니다"}) } if err := h.svc.SaveGameDataByUsername(username, &req); err != nil { // Username from internal API (ServerAuth protected) — low risk of injection log.Printf("게임 데이터 저장 실패 (username=%s): %v", username, err) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "서버 오류가 발생했습니다"}) } return c.JSON(fiber.Map{"message": "게임 데이터가 저장되었습니다"}) }