sno-quiz/backend/internal/handlers/qr_handler.go
2025-09-17 22:22:14 +03:00

152 lines
4.2 KiB
Go

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,
},
})
}