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:
+121
-3
@@ -4940,6 +4940,120 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/feedback/tender/{tender_id}": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Retrieve feedback details by tender ID. This endpoint provides basic feedback information for public users.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Feedback"
|
||||
],
|
||||
"summary": "Get feedback by tender ID",
|
||||
"parameters": [
|
||||
{
|
||||
"maxLength": 24,
|
||||
"minLength": 24,
|
||||
"type": "string",
|
||||
"description": "Tender ID (MongoDB ObjectID format)",
|
||||
"name": "tender_id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Feedback retrieved successfully",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/response.APIResponse"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/definitions/feedback.FeedbackResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad request - Invalid tender ID format",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/response.APIResponse"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"error": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Feedback not found",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/response.APIResponse"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"error": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal server error",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/response.APIResponse"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"error": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/feedback/{id}": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -5374,7 +5488,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/tenders/read/{id}": {
|
||||
"/api/v1/tenders/details/{id}": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
@@ -6683,11 +6797,15 @@ const docTemplate = `{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"like",
|
||||
"dislike"
|
||||
"dislike",
|
||||
"unlike",
|
||||
"undislike"
|
||||
],
|
||||
"x-enum-varnames": [
|
||||
"FeedbackTypeLike",
|
||||
"FeedbackTypeDislike"
|
||||
"FeedbackTypeDislike",
|
||||
"FeedbackTypeUnLike",
|
||||
"FeedbackTypeUnDislike"
|
||||
]
|
||||
},
|
||||
"feedback.ToggleFeedbackForm": {
|
||||
|
||||
+121
-3
@@ -4934,6 +4934,120 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/feedback/tender/{tender_id}": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Retrieve feedback details by tender ID. This endpoint provides basic feedback information for public users.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Feedback"
|
||||
],
|
||||
"summary": "Get feedback by tender ID",
|
||||
"parameters": [
|
||||
{
|
||||
"maxLength": 24,
|
||||
"minLength": 24,
|
||||
"type": "string",
|
||||
"description": "Tender ID (MongoDB ObjectID format)",
|
||||
"name": "tender_id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Feedback retrieved successfully",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/response.APIResponse"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/definitions/feedback.FeedbackResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad request - Invalid tender ID format",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/response.APIResponse"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"error": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Feedback not found",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/response.APIResponse"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"error": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal server error",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/response.APIResponse"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"error": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/feedback/{id}": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -5368,7 +5482,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/tenders/read/{id}": {
|
||||
"/api/v1/tenders/details/{id}": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
@@ -6677,11 +6791,15 @@
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"like",
|
||||
"dislike"
|
||||
"dislike",
|
||||
"unlike",
|
||||
"undislike"
|
||||
],
|
||||
"x-enum-varnames": [
|
||||
"FeedbackTypeLike",
|
||||
"FeedbackTypeDislike"
|
||||
"FeedbackTypeDislike",
|
||||
"FeedbackTypeUnLike",
|
||||
"FeedbackTypeUnDislike"
|
||||
]
|
||||
},
|
||||
"feedback.ToggleFeedbackForm": {
|
||||
|
||||
@@ -138,6 +138,7 @@ func RegisterPublicRoutes(e *echo.Echo, customerHandler *customer.Handler, tende
|
||||
feedbackGP.Use(customerHandler.AuthMiddleware())
|
||||
feedbackGP.POST("", feedbackHandler.ToggleFeedback)
|
||||
feedbackGP.GET("", feedbackHandler.PublicListFeedback)
|
||||
feedbackGP.GET("/tender/:tender_id", feedbackHandler.PublicGetFeedbackByTenderID)
|
||||
feedbackGP.GET("/:id", feedbackHandler.PublicGetFeedback)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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{}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user