package handlers import ( "Yimaru-Backend/internal/domain" "errors" personasservice "Yimaru-Backend/internal/services/personas" "strconv" "strings" "github.com/gofiber/fiber/v2" ) type listPersonasData struct { Personas []domain.LmsPersona `json:"personas"` TotalCount int64 `json:"total_count"` Limit int `json:"limit"` Offset int `json:"offset"` } // CreatePersona godoc // @Summary Create LMS persona catalog entry // @Tags personas // @Accept json // @Param body body domain.CreateLmsPersonaInput true "Persona" // @Success 201 {object} domain.Response // @Router /api/v1/personas [post] func (h *Handler) CreatePersona(c *fiber.Ctx) error { var req domain.CreateLmsPersonaInput if err := c.BodyParser(&req); err != nil { return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ Message: "Invalid request body", Error: err.Error(), }) } if valErrs, ok := h.validator.Validate(c, req); !ok { return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ Message: "Validation failed", Error: firstValidationError(valErrs), }) } p, err := h.personaSvc.Create(c.Context(), req) if err != nil { if errors.Is(err, personasservice.ErrNameRequired) { return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "Validation failed", Error: err.Error()}) } return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to create persona", Error: err.Error()}) } return c.Status(fiber.StatusCreated).JSON(domain.Response{ Message: "Persona created successfully", Data: p, Success: true, StatusCode: fiber.StatusCreated, }) } // ListPersonas godoc // @Summary List LMS personas (catalog for practice assignment) // @Tags personas // @Param active_only query bool false "When true (default), return only active personas" default(true) // @Param limit query int false "Page size" // @Param offset query int false "Offset" // @Router /api/v1/personas [get] func (h *Handler) ListPersonas(c *fiber.Ctx) error { activeOnlyStr := strings.ToLower(strings.TrimSpace(c.Query("active_only", "true"))) activeOnly := activeOnlyStr != "false" limit, err := strconv.Atoi(c.Query("limit", "20")) if err != nil { return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "Invalid limit", Error: err.Error()}) } offset, err := strconv.Atoi(c.Query("offset", "0")) if err != nil { return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "Invalid offset", Error: err.Error()}) } items, total, err := h.personaSvc.List(c.Context(), activeOnly, int32(limit), int32(offset)) if err != nil { return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to list personas", Error: err.Error()}) } return c.JSON(domain.Response{ Message: "Personas retrieved successfully", Data: listPersonasData{ Personas: items, TotalCount: total, Limit: limit, Offset: offset, }, Success: true, StatusCode: fiber.StatusOK, }) } // GetPersona godoc // @Summary Get LMS persona by ID // @Tags personas // @Param id path int true "Persona ID" // @Router /api/v1/personas/{id} [get] func (h *Handler) GetPersona(c *fiber.Ctx) error { id, err := strconv.ParseInt(c.Params("id"), 10, 64) if err != nil || id <= 0 { msg := "" if err != nil { msg = err.Error() } return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "Invalid persona id", Error: msg}) } p, err := h.personaSvc.GetByID(c.Context(), id) if err != nil { if errors.Is(err, domain.ErrPersonaNotFound) { return c.Status(fiber.StatusNotFound).JSON(domain.ErrorResponse{Message: "Persona not found", Error: err.Error()}) } return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to load persona", Error: err.Error()}) } return c.JSON(domain.Response{Message: "Persona retrieved successfully", Data: p, Success: true, StatusCode: fiber.StatusOK}) } // UpdatePersona godoc // @Summary Update LMS persona // @Tags personas // @Param id path int true "Persona ID" // @Param body body domain.UpdateLmsPersonaInput true "Fields to update" // @Router /api/v1/personas/{id} [put] func (h *Handler) UpdatePersona(c *fiber.Ctx) error { id, err := strconv.ParseInt(c.Params("id"), 10, 64) if err != nil || id <= 0 { msg := "" if err != nil { msg = err.Error() } return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "Invalid persona id", Error: msg}) } var req domain.UpdateLmsPersonaInput if err := c.BodyParser(&req); err != nil { return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "Invalid request body", Error: err.Error()}) } p, err := h.personaSvc.Update(c.Context(), id, req) if err != nil { if errors.Is(err, domain.ErrPersonaNotFound) { return c.Status(fiber.StatusNotFound).JSON(domain.ErrorResponse{Message: "Persona not found", Error: err.Error()}) } if errors.Is(err, personasservice.ErrNameEmptyUpdate) { return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "Validation failed", Error: err.Error()}) } return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to update persona", Error: err.Error()}) } return c.JSON(domain.Response{Message: "Persona updated successfully", Data: p, Success: true, StatusCode: fiber.StatusOK}) } // DeletePersona godoc // @Summary Delete LMS persona (practices referencing it will have persona_id cleared) // @Tags personas // @Param id path int true "Persona ID" // @Router /api/v1/personas/{id} [delete] func (h *Handler) DeletePersona(c *fiber.Ctx) error { id, err := strconv.ParseInt(c.Params("id"), 10, 64) if err != nil || id <= 0 { msg := "" if err != nil { msg = err.Error() } return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "Invalid persona id", Error: msg}) } if err := h.personaSvc.Delete(c.Context(), id); err != nil { return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to delete persona", Error: err.Error()}) } return c.JSON(domain.Response{Message: "Persona deleted successfully", Success: true, StatusCode: fiber.StatusOK}) }