Refactor Feedback Module for Consistency and Clarity

- Updated feedback repository and service methods to use a consistent naming convention, changing `NewTenderRepository` and similar methods to `NewRepository`.
- Refactored feedback handler methods to improve clarity by renaming methods such as `ListFeedback` to `Search` and `GetFeedback` to `Get`.
- Enhanced feedback response structures to include detailed company and tender information, improving the clarity of feedback data returned to API consumers.
- Updated Swagger documentation to reflect changes in feedback response structures and endpoint paths, ensuring accurate representation of the API for consumers.
This commit is contained in:
n.nakhostin
2025-09-24 12:20:19 +03:30
parent cdf15c9d49
commit a342da193e
29 changed files with 666 additions and 702 deletions
+30 -124
View File
@@ -1,7 +1,6 @@
package feedback
import (
"strconv"
"tm/internal/customer"
"tm/internal/user"
"tm/pkg/logger"
@@ -13,15 +12,15 @@ import (
// Handler handles HTTP requests for feedback operations
type Handler struct {
service FeedbackService
service Service
logger logger.Logger
userHandler *user.Handler
customerHandler *customer.Handler
}
// NewFeedbackHandler creates a new feedback handler
func NewFeedbackHandler(
service FeedbackService,
// NewHandler creates a new feedback handler
func NewHandler(
service Service,
userHandler *user.Handler,
customerHandler *customer.Handler,
logger logger.Logger,
@@ -55,65 +54,13 @@ func NewFeedbackHandler(
// @Failure 500 {object} response.APIResponse{error=string,message=string} "Internal server error"
// @Security BearerAuth
// @Router /admin/v1/feedback [get]
func (h *Handler) ListFeedback(c echo.Context) error {
// Parse query parameters
limitStr := c.QueryParam("limit")
offsetStr := c.QueryParam("offset")
limit := 20 // default limit
offset := 0 // default offset
if l, err := strconv.Atoi(limitStr); err == nil && l > 0 && l <= 100 {
limit = l
func (h *Handler) Search(c echo.Context) error {
form, err := response.Parse[SearchForm](c)
if err != nil {
return response.ValidationError(c, "Invalid request data", err.Error())
}
if o, err := strconv.Atoi(offsetStr); err == nil && o >= 0 {
offset = o
}
// Build search criteria
criteria := FeedbackSearchCriteria{
Limit: limit,
Offset: offset,
}
// Parse optional filters
if tenderID := c.QueryParam("tender_id"); tenderID != "" {
criteria.TenderID = &tenderID
}
if customerID := c.QueryParam("customer_id"); customerID != "" {
criteria.CustomerID = &customerID
}
if companyID := c.QueryParam("company_id"); companyID != "" {
criteria.CompanyID = &companyID
}
if feedbackType := c.QueryParam("feedback_type"); feedbackType != "" {
ft := FeedbackType(feedbackType)
criteria.FeedbackType = &ft
}
if dateFrom := c.QueryParam("date_from"); dateFrom != "" {
if df, err := strconv.ParseInt(dateFrom, 10, 64); err == nil {
criteria.DateFrom = &df
}
}
if dateTo := c.QueryParam("date_to"); dateTo != "" {
if dt, err := strconv.ParseInt(dateTo, 10, 64); err == nil {
criteria.DateTo = &dt
}
}
// Validate date range
if criteria.DateFrom != nil && criteria.DateTo != nil && *criteria.DateFrom >= *criteria.DateTo {
return response.ValidationError(c, "Invalid date range", "date_from must be before date_to")
}
// Get enhanced feedback list with related data
feedbackList, err := h.service.ListFeedback(c.Request().Context(), criteria, limit, offset)
feedbackList, err := h.service.Search(c.Request().Context(), *form, response.NewPagination(c))
if err != nil {
return response.InternalServerError(c, "Failed to retrieve feedback list")
}
@@ -134,13 +81,13 @@ func (h *Handler) ListFeedback(c echo.Context) error {
// @Failure 500 {object} response.APIResponse{error=string,message=string} "Internal server error"
// @Security BearerAuth
// @Router /admin/v1/feedback/{id} [get]
func (h *Handler) GetFeedback(c echo.Context) error {
func (h *Handler) Get(c echo.Context) error {
feedbackID := c.Param("id")
if feedbackID == "" {
return response.BadRequest(c, "Feedback ID is required", "Feedback ID parameter is missing")
}
feedback, err := h.service.GetFeedback(c.Request().Context(), feedbackID)
feedback, err := h.service.Get(c.Request().Context(), feedbackID)
if err != nil {
if err == ErrFeedbackNotFound {
return response.NotFound(c, "Feedback not found")
@@ -169,14 +116,14 @@ func (h *Handler) GetFeedback(c echo.Context) error {
// @Failure 500 {object} response.APIResponse{error=string,message=string} "Internal server error"
// @Security BearerAuth
// @Router /admin/v1/feedback/{id} [delete]
func (h *Handler) DeleteFeedback(c echo.Context) error {
func (h *Handler) Delete(c echo.Context) error {
id := c.Param("id")
if id == "" {
return response.BadRequest(c, "Feedback ID is required", "")
}
// Call service
err := h.service.DeleteFeedback(c.Request().Context(), id)
err := h.service.Delete(c.Request().Context(), id)
if err != nil {
switch err {
case ErrFeedbackNotFound:
@@ -206,7 +153,7 @@ func (h *Handler) DeleteFeedback(c echo.Context) error {
// @Failure 500 {object} response.APIResponse{error=string,message=string} "Internal server error"
// @Security BearerAuth
// @Router /api/v1/feedback [post]
func (h *Handler) ToggleFeedback(c echo.Context) error {
func (h *Handler) Toggle(c echo.Context) error {
form, err := response.Parse[ToggleFeedbackForm](c)
if err != nil {
return response.ValidationError(c, "Invalid request data", err.Error())
@@ -230,7 +177,7 @@ func (h *Handler) ToggleFeedback(c echo.Context) error {
}
// Call service
result, err := h.service.ToggleFeedback(c.Request().Context(), *form, &customerID, &companyID)
result, err := h.service.Toggle(c.Request().Context(), *form, &customerID, &companyID)
if err != nil {
return response.InternalServerError(c, "Failed to toggle feedback")
}
@@ -258,61 +205,20 @@ func (h *Handler) ToggleFeedback(c echo.Context) error {
// @Failure 500 {object} response.APIResponse{error=string,message=string} "Internal server error"
// @Security BearerAuth
// @Router /api/v1/feedback [get]
func (h *Handler) PublicListFeedback(c echo.Context) error {
// Parse query parameters
limitStr := c.QueryParam("limit")
offsetStr := c.QueryParam("offset")
limit := 20
offset := 0
if l, err := strconv.Atoi(limitStr); err == nil && l > 0 && l <= 100 {
limit = l
}
if o, err := strconv.Atoi(offsetStr); err == nil && o >= 0 {
offset = o
}
func (h *Handler) PublicList(c echo.Context) error {
companyID, err := user.GetCompanyIDFromContext(c)
if err != nil {
return response.BadRequest(c, "Company ID required", "User must be associated with a company")
}
// Build search criteria
criteria := FeedbackSearchCriteria{
Limit: limit,
Offset: offset,
CompanyID: &companyID,
}
if feedbackType := c.QueryParam("feedback_type"); feedbackType != "" {
ft := FeedbackType(feedbackType)
if ft != FeedbackTypeLike && ft != FeedbackTypeDislike {
return response.BadRequest(c, "Invalid feedback type", "Must be 'like' or 'dislike'")
}
criteria.FeedbackType = &ft
}
if dateFrom := c.QueryParam("date_from"); dateFrom != "" {
if df, err := strconv.ParseInt(dateFrom, 10, 64); err == nil && df >= 0 {
criteria.DateFrom = &df
}
}
if dateTo := c.QueryParam("date_to"); dateTo != "" {
if dt, err := strconv.ParseInt(dateTo, 10, 64); err == nil && dt >= 0 {
criteria.DateTo = &dt
}
}
// Validate date range
if criteria.DateFrom != nil && criteria.DateTo != nil && *criteria.DateFrom >= *criteria.DateTo {
return response.ValidationError(c, "Invalid date range", "date_from must be before date_to")
form, err := response.Parse[SearchForm](c)
if err != nil {
return response.ValidationError(c, "Invalid request data", err.Error())
}
form.Company = &companyID
// Call service
result, err := h.service.ListFeedback(c.Request().Context(), criteria, limit, offset)
result, err := h.service.Search(c.Request().Context(), *form, response.NewPagination(c))
if err != nil {
return response.InternalServerError(c, "Failed to list feedback")
}
@@ -333,13 +239,13 @@ func (h *Handler) PublicListFeedback(c echo.Context) error {
// @Failure 500 {object} response.APIResponse{error=string,message=string} "Internal server error"
// @Security BearerAuth
// @Router /api/v1/feedback/{id} [get]
func (h *Handler) PublicGetFeedback(c echo.Context) error {
func (h *Handler) PublicGet(c echo.Context) error {
feedbackID := c.Param("id")
if feedbackID == "" {
return response.BadRequest(c, "Feedback ID is required", "Feedback ID parameter is missing")
}
feedback, err := h.service.GetFeedback(c.Request().Context(), feedbackID)
feedback, err := h.service.Get(c.Request().Context(), feedbackID)
if err != nil {
return response.BadRequest(c, "Failed to get feedback", "")
}
@@ -360,7 +266,7 @@ func (h *Handler) PublicGetFeedback(c echo.Context) error {
// @Failure 500 {object} response.APIResponse{error=string,message=string} "Internal server error"
// @Security BearerAuth
// @Router /api/v1/feedback/tender/{tender_id} [get]
func (h *Handler) PublicGetFeedbackByTenderID(c echo.Context) error {
func (h *Handler) PublicGetByTenderID(c echo.Context) error {
tenderID := c.Param("tender_id")
if tenderID == "" {
return response.BadRequest(c, "Tender ID is required", "Tender ID parameter is missing")
@@ -371,7 +277,7 @@ func (h *Handler) PublicGetFeedbackByTenderID(c echo.Context) error {
return response.BadRequest(c, "Company ID required", "User must be associated with a company")
}
feedback, err := h.service.GetFeedbackByTenderID(c.Request().Context(), tenderID, companyID)
feedback, err := h.service.GetByTenderID(c.Request().Context(), tenderID, companyID)
if err != nil {
return response.BadRequest(c, "Failed to get feedback", "")
}
@@ -385,22 +291,22 @@ func (h *Handler) PublicGetFeedbackByTenderID(c echo.Context) error {
// @Tags Feedback
// @Accept json
// @Produce json
// @Success 200 {object} response.APIResponse{data=CompanyFeedbackStatsResponse} "Company feedback statistics retrieved successfully"
// @Success 200 {object} response.APIResponse{data=StatsResponse} "Company feedback statistics retrieved successfully"
// @Failure 400 {object} response.APIResponse{error=string,message=string} "Bad request - Missing company association"
// @Failure 401 {object} response.APIResponse{error=string,message=string} "Unauthorized - User not authenticated"
// @Failure 500 {object} response.APIResponse{error=string,message=string} "Internal server error"
// @Security BearerAuth
// @Router /api/v1/feedback/stats/company [get]
func (h *Handler) GetCompanyFeedbackStats(c echo.Context) error {
func (h *Handler) GetCompanyStats(c echo.Context) error {
companyID, err := user.GetCompanyIDFromContext(c)
if err != nil {
return response.BadRequest(c, "Company ID required", "User must be associated with a company")
}
stats, err := h.service.CompanyFeedbackStats(c.Request().Context(), companyID)
stats, err := h.service.CompanyStats(c.Request().Context(), companyID)
if err != nil {
return response.InternalServerError(c, "Failed to retrieve company feedback statistics")
return response.InternalServerError(c, "Failed to retrieve company stats")
}
return response.Success(c, stats, "Company feedback statistics retrieved successfully")
return response.Success(c, stats, "Company stats retrieved successfully")
}