Files
tm_back/internal/inquiry/handler.go
T
2025-12-07 23:52:17 +03:30

208 lines
8.6 KiB
Go

package inquiry
import (
"encoding/json"
"tm/pkg/logger"
"tm/pkg/response"
"tm/pkg/security"
"github.com/labstack/echo/v4"
)
// Handler handles HTTP requests for inquiry operations
type Handler struct {
service Service
logger logger.Logger
xssPolicy *security.XSSPolicy
}
// NewInquiryHandler creates a new inquiry handler
func NewHandler(service Service, logger logger.Logger, xssPolicy *security.XSSPolicy) *Handler {
return &Handler{
service: service,
logger: logger,
xssPolicy: xssPolicy,
}
}
// CreateInquiry creates a new inquiry
// @Summary Create new inquiry
// @Description Create a new inquiry with contact information for potential business opportunities. This endpoint allows external users to submit inquiries about services or partnerships. Duplicate submissions are prevented based on email and phone number.
// @Tags Inquiries
// @Accept json
// @Produce json
// @Param inquiry body CreateInquiryForm true "Inquiry information including contact details and company information"
// @Success 201 {object} response.APIResponse{data=InquiryResponse} "Inquiry created successfully with assigned ID and timestamps"
// @Failure 400 {object} response.APIResponse "Bad request - Invalid input data or missing required fields"
// @Failure 409 {object} response.APIResponse "Conflict - Duplicate inquiry already exists with same email or phone number"
// @Failure 422 {object} response.APIResponse "Validation error - Invalid data format or validation rules not met"
// @Failure 500 {object} response.APIResponse "Internal server error"
// @Router /api/v1/inquiries [post]
func (h *Handler) CreateInquiry(c echo.Context) error {
form, err := response.Parse[CreateInquiryForm](c)
if err != nil {
return response.BadRequest(c, "Invalid request format", "")
}
// Validate and sanitize form
if err := form.ValidateAndSanitize(h.xssPolicy); err != nil {
return response.ValidationError(c, err.Error(), "")
}
// Call service
inquiry, err := h.service.Create(c.Request().Context(), form)
if err != nil {
// Check if it's a duplicate inquiry error
if duplicateErr, ok := err.(*DuplicateInquiryError); ok {
// Convert details to JSON string
details, _ := json.Marshal(map[string]interface{}{
"type": duplicateErr.Type,
"existing_id": duplicateErr.ExistingID,
"status": duplicateErr.Status,
"created_at": duplicateErr.CreatedAt,
})
// Return conflict with detailed error information
return c.JSON(409, response.APIResponse{
Success: false,
Message: "Conflict",
Error: &response.APIError{
Code: "DUPLICATE_INQUIRY",
Message: duplicateErr.Message,
Details: string(details),
},
})
}
return response.BadRequest(c, err.Error(), "")
}
return response.Created(c, inquiry, "Inquiry created successfully")
}
// GetInquiryByID gets an inquiry by ID
// @Summary Get inquiry by ID
// @Description Retrieve detailed information about a specific inquiry by its unique identifier. This endpoint provides complete inquiry details including contact information, status, and status history.
// @Tags Admin-Inquiries
// @Accept json
// @Produce json
// @Param id path string true "Inquiry ID"
// @Success 200 {object} response.APIResponse{data=InquiryResponse} "Inquiry retrieved successfully with complete details"
// @Failure 400 {object} response.APIResponse "Bad request - Invalid inquiry ID format"
// @Failure 404 {object} response.APIResponse "Not found - Inquiry with specified ID not found"
// @Failure 500 {object} response.APIResponse "Internal server error"
// @Router /admin/v1/inquiries/{id} [get]
func (h *Handler) GetInquiryByID(c echo.Context) error {
idStr := c.Param("id")
inquiry, err := h.service.GetByID(c.Request().Context(), idStr)
if err != nil {
return response.NotFound(c, "Inquiry not found")
}
return response.Success(c, inquiry, "Inquiry retrieved successfully")
}
// UpdateInquiryStatus updates the status of an inquiry
// @Summary Update inquiry status
// @Description Update the status of an inquiry with reason and optional description. This endpoint allows administrators to change inquiry status following the defined workflow: pending -> reviewed -> approved/rejected.
// @Tags Admin-Inquiries
// @Accept json
// @Produce json
// @Param id path string true "Inquiry ID"
// @Param status body UpdateInquiryStatusForm true "Status update information including new status, reason, and optional description"
// @Success 200 {object} response.APIResponse{data=InquiryResponse} "Inquiry status updated successfully with updated details"
// @Failure 400 {object} response.APIResponse "Bad request - Invalid inquiry ID format or invalid status transition"
// @Failure 404 {object} response.APIResponse "Not found - Inquiry with specified ID not found"
// @Failure 422 {object} response.APIResponse "Validation error - Invalid data format or validation rules not met"
// @Failure 500 {object} response.APIResponse "Internal server error"
// @Router /admin/v1/inquiries/{id}/status [put]
func (h *Handler) UpdateInquiryStatus(c echo.Context) error {
idStr := c.Param("id")
form, err := response.Parse[UpdateInquiryStatusForm](c)
if err != nil {
return response.BadRequest(c, "Invalid request format", "")
}
// Validate and sanitize form
if err := form.ValidateAndSanitize(h.xssPolicy); err != nil {
return response.ValidationError(c, err.Error(), "")
}
// Get user ID from context (assuming it's set by auth middleware)
changedBy := "admin" // TODO: Get from JWT token or context
// changedBy := c.Get("user_id").(string)
// Call service
inquiry, err := h.service.UpdateStatus(c.Request().Context(), idStr, form, changedBy)
if err != nil {
return response.BadRequest(c, err.Error(), "")
}
return response.Success(c, inquiry, "Inquiry status updated successfully")
}
// SearchInquiries searches inquiries with filters
// @Summary Search inquiries
// @Description Search and filter inquiries with pagination support. This endpoint allows administrators to find inquiries based on various criteria including name, company, email, status, and other filters.
// @Tags Admin-Inquiries
// @Accept json
// @Produce json
// @Param q query string false "Search term for full name, company name, or email"
// @Param status query string false "Filter by status (pending, reviewed, approved, rejected)"
// @Param limit query int false "Limit results (1-100)"
// @Param offset query int false "Offset results"
// @Param sort_by query string false "Sort field (full_name, company_name, work_email, status, created_at)"
// @Param sort_order query string false "Sort order (asc, desc)"
// @Success 200 {object} response.APIResponse{data=InquiryListResponse} "Inquiries retrieved successfully with pagination metadata"
// @Failure 400 {object} response.APIResponse "Bad request - Invalid query parameters"
// @Failure 422 {object} response.APIResponse "Validation error - Invalid parameter values"
// @Failure 500 {object} response.APIResponse "Internal server error"
// @Router /admin/v1/inquiries [get]
func (h *Handler) SearchInquiries(c echo.Context) error {
form, err := response.Parse[SearchInquiriesForm](c)
if err != nil {
return response.BadRequest(c, "Invalid request format", "")
}
// Validate and sanitize form
if err := form.ValidateAndSanitize(h.xssPolicy); err != nil {
return response.ValidationError(c, err.Error(), "")
}
// Call service
inquiries, err := h.service.Search(c.Request().Context(), form, response.NewPagination(c))
if err != nil {
return response.InternalServerError(c, "Failed to search inquiries")
}
return response.SuccessWithMeta(c, map[string]interface{}{
"inquiries": inquiries.Inquiries,
}, inquiries.Meta, "Inquiries retrieved successfully")
}
// DeleteInquiry deletes an inquiry
// @Summary Delete inquiry
// @Description Delete an inquiry permanently from the system. This action cannot be undone and will remove all inquiry data including contact information, status history, and timestamps.
// @Tags Admin-Inquiries
// @Accept json
// @Produce json
// @Param id path string true "Inquiry ID"
// @Success 200 {object} response.APIResponse "Inquiry deleted successfully"
// @Failure 400 {object} response.APIResponse "Bad request - Invalid inquiry ID format"
// @Failure 404 {object} response.APIResponse "Not found - Inquiry with specified ID not found"
// @Failure 500 {object} response.APIResponse "Internal server error"
// @Router /admin/v1/inquiries/{id} [delete]
func (h *Handler) DeleteInquiry(c echo.Context) error {
id := c.Param("id")
err := h.service.Delete(c.Request().Context(), id)
if err != nil {
return response.BadRequest(c, err.Error(), "")
}
return response.Success(c, map[string]interface{}{
"message": "Inquiry deleted successfully",
}, "Inquiry deleted successfully")
}