Add Feedback Retrieval Endpoint for Tender ID

- Introduced a new API endpoint to retrieve feedback details by tender ID, enhancing the feedback management system for public users.
- Updated Swagger documentation to accurately reflect the new endpoint, including detailed descriptions, parameters, and response formats.
- Implemented necessary service and repository methods to support the new functionality, ensuring adherence to Clean Architecture principles.
- Modified existing routes to include the new feedback retrieval functionality, maintaining a clear separation of concerns in the handler layer.
- Enhanced feedback types to include 'unlike' and 'undislike' options for better user interaction.
This commit is contained in:
n.nakhostin
2025-08-17 13:29:44 +03:30
parent 4663a9781e
commit a8ef631e43
7 changed files with 329 additions and 8 deletions
+4 -2
View File
@@ -10,8 +10,10 @@ import (
type FeedbackType string
const (
FeedbackTypeLike FeedbackType = "like"
FeedbackTypeDislike FeedbackType = "dislike"
FeedbackTypeLike FeedbackType = "like"
FeedbackTypeDislike FeedbackType = "dislike"
FeedbackTypeUnLike FeedbackType = "unlike"
FeedbackTypeUnDislike FeedbackType = "undislike"
)
// Feedback represents feedback given to a tender by a user
+32
View File
@@ -346,3 +346,35 @@ func (h *Handler) PublicGetFeedback(c echo.Context) error {
return response.Success(c, feedback, "Feedback retrieved successfully")
}
// PublicGetFeedbackByTenderID retrieves feedback by tender ID
// @Summary Get feedback by tender ID
// @Description Retrieve feedback details by tender ID. This endpoint provides basic feedback information for public users.
// @Tags Feedback
// @Accept json
// @Produce json
// @Param tender_id path string true "Tender ID (MongoDB ObjectID format)" minlength(24) maxlength(24)
// @Success 200 {object} response.APIResponse{data=FeedbackResponse} "Feedback retrieved successfully"
// @Failure 400 {object} response.APIResponse{error=string,message=string} "Bad request - Invalid tender ID format"
// @Failure 404 {object} response.APIResponse{error=string,message=string} "Feedback not found"
// @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 {
tenderID := c.Param("tender_id")
if tenderID == "" {
return response.BadRequest(c, "Tender ID is required", "Tender ID parameter is missing")
}
companyID, err := user.GetCompanyIDFromContext(c)
if err != nil {
return response.BadRequest(c, "Company ID required", "User must be associated with a company")
}
feedback, err := h.service.GetFeedbackByTenderID(c.Request().Context(), tenderID, companyID)
if err != nil {
return response.BadRequest(c, "Failed to get feedback", "")
}
return response.Success(c, feedback, "Feedback retrieved successfully")
}
+16
View File
@@ -22,6 +22,7 @@ type Repository interface {
Search(ctx context.Context, criteria FeedbackSearchCriteria) ([]*Feedback, error)
GetFeedbackSummary(ctx context.Context, tenderID string) (*FeedbackSummary, error)
GetFeedbackCountByType(ctx context.Context) (map[FeedbackType]int64, error)
GetByTenderID(ctx context.Context, tenderID, companyID string) (*Feedback, error)
}
// feedbackRepository implements FeedbackRepository interface using MongoDB ORM
@@ -396,6 +397,21 @@ func (r *feedbackRepository) GetCustomerFeedbackHistory(ctx context.Context, cus
return feedback, result.TotalCount, nil
}
func (r *feedbackRepository) GetByTenderID(ctx context.Context, tenderID, companyID string) (*Feedback, error) {
filter := bson.M{"tender_id": tenderID, "company_id": companyID}
result, err := r.repo.FindOne(ctx, filter)
if err != nil {
r.logger.Error("Failed to get feedback by tender ID", map[string]interface{}{
"tender_id": tenderID,
"error": err.Error(),
})
return nil, err
}
return result, nil
}
// buildSearchFilter builds MongoDB filter from search criteria
func (r *feedbackRepository) buildSearchFilter(criteria FeedbackSearchCriteria) bson.M {
filter := bson.M{}
+34
View File
@@ -12,6 +12,7 @@ type FeedbackService interface {
GetFeedback(ctx context.Context, id string) (*FeedbackResponse, error)
ListFeedback(ctx context.Context, criteria FeedbackSearchCriteria, limit, offset int) (*FeedbackListResponse, error)
DeleteFeedback(ctx context.Context, id string) error
GetFeedbackByTenderID(ctx context.Context, tenderID, companyID string) (*FeedbackResponse, error)
}
// feedbackService implements FeedbackService interface
@@ -52,6 +53,27 @@ func (s *feedbackService) ToggleFeedback(ctx context.Context, req ToggleFeedback
return feedback.ToResponse(), nil
}
if existing.FeedbackType == req.FeedbackType {
if existing.FeedbackType == FeedbackTypeLike {
existing.FeedbackType = FeedbackTypeUnLike
} else {
existing.FeedbackType = FeedbackTypeUnDislike
}
err = s.feedbackRepo.Delete(ctx, existing.GetID())
if err != nil {
s.logger.Error("Failed to update existing feedback", map[string]interface{}{
"feedback_id": existing.GetID(),
"tender_id": req.TenderID,
"company_id": *companyID,
"error": err.Error(),
})
return nil, err
}
return existing.ToResponse(), nil
}
if existing.FeedbackType == FeedbackTypeLike {
existing.FeedbackType = FeedbackTypeDislike
} else {
@@ -118,3 +140,15 @@ func (s *feedbackService) ListFeedback(ctx context.Context, criteria FeedbackSea
func (s *feedbackService) DeleteFeedback(ctx context.Context, id string) error {
return s.feedbackRepo.Delete(ctx, id)
}
func (s *feedbackService) GetFeedbackByTenderID(ctx context.Context, tenderID, companyID string) (*FeedbackResponse, error) {
feedback, err := s.feedbackRepo.GetByTenderID(ctx, tenderID, companyID)
if err != nil {
s.logger.Error("Failed to get feedback by tender ID", map[string]interface{}{
"tender_id": tenderID,
"error": err.Error(),
})
return nil, err
}
return feedback.ToResponse(), nil
}