package handlers import ( "log" "sno/internal/middleware" "sno/internal/models" "sno/internal/service" "github.com/gofiber/fiber/v2" ) // QRHandler handles HTTP requests for QR code operations. type QRHandler struct { qrService service.QRService } // NewQRHandler creates a new instance of a QR handler. func NewQRHandler(s service.QRService) *QRHandler { return &QRHandler{qrService: s} } // Validate handles the request to validate a QR code payload. // @Summary Validate QR code payload // @Description Validates a QR code payload and processes the associated action // @Tags qr // @Accept json // @Produce json // @Param request body models.QRValidateRequest true "QR validation request" // @Success 200 {object} object{success=bool,message=string,data=object} // @Failure 400 {object} object{success=bool,message=string} // @Failure 401 {object} object{success=bool,message=string} // @Router /api/qr/validate [post] // @Security ApiKeyAuth func (h *QRHandler) Validate(c *fiber.Ctx) error { var req models.QRValidateRequest if err := c.BodyParser(&req); err != nil { return c.Status(fiber.StatusBadRequest).JSON(Response{ Success: false, Message: "Cannot parse JSON", }) } if req.Payload == "" { return c.Status(fiber.StatusBadRequest).JSON(Response{ Success: false, Message: "Payload cannot be empty", }) } // Get user data from auth middleware userData := middleware.GetTelegramUser(c) if userData == nil { return c.Status(fiber.StatusUnauthorized).JSON(Response{ Success: false, Message: "User not authenticated", }) } resp, err := h.qrService.ValidatePayload(c.Context(), userData.ID, req.Payload) if err != nil { log.Printf("ERROR: Failed to validate QR payload: %v", err) return c.Status(fiber.StatusBadRequest).JSON(Response{ // Using 400 for invalid payloads Success: false, Message: err.Error(), }) } return c.Status(fiber.StatusOK).JSON(Response{ Success: true, Message: "QR payload validated successfully", Data: resp, }) } // GenerateQRCodes handles the request to generate unique QR codes // @Summary Generate QR codes // @Description Generates unique QR codes for rewards, quizzes, or shop items (admin/operator only) // @Tags qr // @Accept json // @Produce json // @Param request body models.GenerateQRCodesRequest true "QR codes generation request" // @Success 200 {object} object{success=bool,message=string,data=models.GenerateQRCodesResponse} // @Failure 400 {object} object{success=bool,message=string} // @Failure 500 {object} object{success=bool,message=string} // @Router /api/admin/qrcodes [post] // @Security ApiKeyAuth func (h *QRHandler) GenerateQRCodes(c *fiber.Ctx) error { var req models.GenerateQRCodesRequest if err := c.BodyParser(&req); err != nil { return c.Status(fiber.StatusBadRequest).JSON(Response{ Success: false, Message: "Cannot parse JSON", }) } // Validate request if req.Type == "" { return c.Status(fiber.StatusBadRequest).JSON(Response{ Success: false, Message: "Type cannot be empty", }) } if req.Value == "" { return c.Status(fiber.StatusBadRequest).JSON(Response{ Success: false, Message: "Value cannot be empty", }) } if req.Count <= 0 || req.Count > 100 { return c.Status(fiber.StatusBadRequest).JSON(Response{ Success: false, Message: "Count must be between 1 and 100", }) } // Validate type validTypes := map[string]bool{ "reward": true, "quiz": true, "shop": true, } if !validTypes[req.Type] { return c.Status(fiber.StatusBadRequest).JSON(Response{ Success: false, Message: "Invalid type. Must be 'reward', 'quiz', or 'shop'", }) } tokens := make([]string, 0, req.Count) for i := 0; i < req.Count; i++ { token, err := h.qrService.GenerateUniqueToken(c.Context(), req.Type, req.Value) if err != nil { log.Printf("ERROR: Failed to generate QR token: %v", err) return c.Status(fiber.StatusInternalServerError).JSON(Response{ Success: false, Message: "Failed to generate QR codes", }) } tokens = append(tokens, token) } return c.Status(fiber.StatusOK).JSON(Response{ Success: true, Message: "QR codes generated successfully", Data: models.GenerateQRCodesResponse{ Tokens: tokens, }, }) }