upvotes
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/promote/production Build is passing

This commit is contained in:
2024-04-23 19:13:48 +03:00
parent a1df10c37e
commit ed403c2c72
11 changed files with 147 additions and 17 deletions

View File

@@ -49,8 +49,8 @@ func (h *FeedbackHandler) GetFeedback(params feedback.GetFeedbacksForProjectPara
}
func (h *FeedbackHandler) UpvoteFeedback(params feedback.UpvoteFeedbackParams) middleware.Responder {
err := h.feedback.Upvote(params.SessionUUID, params.FeedbackUUID)
func (h *FeedbackHandler) VoteFeedback(params feedback.UpvoteFeedbackParams) middleware.Responder {
err := h.feedback.Vote(params.SessionUUID, params.FeedbackUUID, params.Action)
if err != nil {
return feedback.NewUpvoteFeedbackForbidden()
}
@@ -77,6 +77,14 @@ func feedbacksToAPI(feedbacks []*dmodels.Feedback) []*models.Feedback {
}
func feedbackToAPI(feedback *dmodels.Feedback) *models.Feedback {
var upvoted bool
for _, upvote := range feedback.Upvote {
if upvote.SessionUUID == feedback.SessionUUID {
upvoted = true
break
}
}
return &models.Feedback{
FeedbackUUID: feedback.UUID,
SessionUUID: feedback.SessionUUID,
@@ -84,6 +92,8 @@ func feedbackToAPI(feedback *dmodels.Feedback) *models.Feedback {
Text: feedback.Text,
Type: string(feedback.Type),
UserID: feedback.UserID,
Upvotes: int64(len(feedback.Upvote)),
Upvoted: upvoted,
CreatedAt: strfmt.DateTime(feedback.CreatedAt),
}
}

View File

@@ -40,6 +40,12 @@ type Feedback struct {
// Enum: [feature feedback support]
Type string `json:"type,omitempty"`
// upvoted
Upvoted bool `json:"upvoted,omitempty"`
// upvotes
Upvotes int64 `json:"upvotes,omitempty"`
// to have more context about the user
UserID string `json:"user_id,omitempty"`
}

View File

@@ -68,7 +68,7 @@ func init() {
}
}
},
"/feedback/{feedback_uuid}/upvote": {
"/feedback/{feedback_uuid}/vote": {
"post": {
"description": "Upvote a feedback",
"tags": [
@@ -90,6 +90,16 @@ func init() {
"name": "session_uuid",
"in": "query",
"required": true
},
{
"enum": [
"upvote",
"downvote"
],
"type": "string",
"name": "action",
"in": "query",
"required": true
}
],
"responses": {
@@ -198,6 +208,12 @@ func init() {
"support"
]
},
"upvoted": {
"type": "boolean"
},
"upvotes": {
"type": "integer"
},
"user_id": {
"description": "to have more context about the user",
"type": "string"
@@ -257,7 +273,7 @@ func init() {
}
}
},
"/feedback/{feedback_uuid}/upvote": {
"/feedback/{feedback_uuid}/vote": {
"post": {
"description": "Upvote a feedback",
"tags": [
@@ -279,6 +295,16 @@ func init() {
"name": "session_uuid",
"in": "query",
"required": true
},
{
"enum": [
"upvote",
"downvote"
],
"type": "string",
"name": "action",
"in": "query",
"required": true
}
],
"responses": {
@@ -387,6 +413,12 @@ func init() {
"support"
]
},
"upvoted": {
"type": "boolean"
},
"upvotes": {
"type": "integer"
},
"user_id": {
"description": "to have more context about the user",
"type": "string"

View File

@@ -30,7 +30,7 @@ func NewUpvoteFeedback(ctx *middleware.Context, handler UpvoteFeedbackHandler) *
}
/*
UpvoteFeedback swagger:route POST /feedback/{feedback_uuid}/upvote feedback upvoteFeedback
UpvoteFeedback swagger:route POST /feedback/{feedback_uuid}/vote feedback upvoteFeedback
# Upvote a feedback

View File

@@ -32,6 +32,11 @@ type UpvoteFeedbackParams struct {
// HTTP Request Object
HTTPRequest *http.Request `json:"-"`
/*
Required: true
In: query
*/
Action string
/*Feedback UUID
Required: true
In: path
@@ -55,6 +60,11 @@ func (o *UpvoteFeedbackParams) BindRequest(r *http.Request, route *middleware.Ma
qs := runtime.Values(r.URL.Query())
qAction, qhkAction, _ := qs.GetOK("action")
if err := o.bindAction(qAction, qhkAction, route.Formats); err != nil {
res = append(res, err)
}
rFeedbackUUID, rhkFeedbackUUID, _ := route.Params.GetOK("feedback_uuid")
if err := o.bindFeedbackUUID(rFeedbackUUID, rhkFeedbackUUID, route.Formats); err != nil {
res = append(res, err)
@@ -70,6 +80,41 @@ func (o *UpvoteFeedbackParams) BindRequest(r *http.Request, route *middleware.Ma
return nil
}
// bindAction binds and validates parameter Action from query.
func (o *UpvoteFeedbackParams) bindAction(rawData []string, hasKey bool, formats strfmt.Registry) error {
if !hasKey {
return errors.Required("action", "query", rawData)
}
var raw string
if len(rawData) > 0 {
raw = rawData[len(rawData)-1]
}
// Required: true
// AllowEmptyValue: false
if err := validate.RequiredString("action", "query", raw); err != nil {
return err
}
o.Action = raw
if err := o.validateAction(formats); err != nil {
return err
}
return nil
}
// validateAction carries on validations for parameter Action
func (o *UpvoteFeedbackParams) validateAction(formats strfmt.Registry) error {
if err := validate.EnumCase("action", "query", o.Action, []interface{}{"upvote", "downvote"}, true); err != nil {
return err
}
return nil
}
// bindFeedbackUUID binds and validates parameter FeedbackUUID from path.
func (o *UpvoteFeedbackParams) bindFeedbackUUID(rawData []string, hasKey bool, formats strfmt.Registry) error {
var raw string

View File

@@ -16,6 +16,7 @@ import (
type UpvoteFeedbackURL struct {
FeedbackUUID string
Action string
SessionUUID string
_basePath string
@@ -42,7 +43,7 @@ func (o *UpvoteFeedbackURL) SetBasePath(bp string) {
func (o *UpvoteFeedbackURL) Build() (*url.URL, error) {
var _result url.URL
var _path = "/feedback/{feedback_uuid}/upvote"
var _path = "/feedback/{feedback_uuid}/vote"
feedbackUUID := o.FeedbackUUID
if feedbackUUID != "" {
@@ -59,6 +60,11 @@ func (o *UpvoteFeedbackURL) Build() (*url.URL, error) {
qs := make(url.Values)
actionQ := o.Action
if actionQ != "" {
qs.Set("action", actionQ)
}
sessionUUIDQ := o.SessionUUID
if sessionUUIDQ != "" {
qs.Set("session_uuid", sessionUUIDQ)

View File

@@ -292,7 +292,7 @@ func (o *GeraldAPI) initHandlerCache() {
if o.handlers["POST"] == nil {
o.handlers["POST"] = make(map[string]http.Handler)
}
o.handlers["POST"]["/feedback/{feedback_uuid}/upvote"] = feedback.NewUpvoteFeedback(o.context, o.FeedbackUpvoteFeedbackHandler)
o.handlers["POST"]["/feedback/{feedback_uuid}/vote"] = feedback.NewUpvoteFeedback(o.context, o.FeedbackUpvoteFeedbackHandler)
}
// Serve creates a http handler to serve the API over HTTP

View File

@@ -50,7 +50,7 @@ func StartHTTPServer(s *Server, lifecycle fx.Lifecycle) {
// Feedback
api.FeedbackCreateFeedbackHandler = feedback.CreateFeedbackHandlerFunc(s.feedback.CreateFeedback)
api.FeedbackGetFeedbacksHandler = feedback.GetFeedbacksHandlerFunc(s.feedback.GetFeedbacks)
api.FeedbackUpvoteFeedbackHandler = feedback.UpvoteFeedbackHandlerFunc(s.feedback.UpvoteFeedback)
api.FeedbackUpvoteFeedbackHandler = feedback.UpvoteFeedbackHandlerFunc(s.feedback.VoteFeedback)
api.FeedbackGetFeedbacksForProjectHandler = feedback.GetFeedbacksForProjectHandlerFunc(s.feedback.GetFeedbacksForProject)
// Add global middleware here

View File

@@ -36,7 +36,7 @@ func (f *FeedbackService) GetByProjectID(projectID string) ([]*models.Feedback,
return f.db.Feedback.GetByProjectID(projectID)
}
func (f *FeedbackService) Upvote(sessionID, feedbackUUID string) error {
func (f *FeedbackService) Vote(sessionID, feedbackUUID, action string) error {
feedback, err := f.db.Feedback.GetByUUID(feedbackUUID)
if err != nil {
return err
@@ -44,15 +44,27 @@ func (f *FeedbackService) Upvote(sessionID, feedbackUUID string) error {
// check if project type is feature
if feedback.Type != models.FeedbackTypeFeature {
return errors.New("only feature tickets can be upvoted")
return errors.New("only feature tickets can be voted")
}
// check if user has already upvoted
for _, upvote := range feedback.Upvote {
if upvote.SessionUUID == sessionID {
return errors.New("user has already upvoted")
switch action {
case "upvote":
// check if user has already upvoted
for _, upvote := range feedback.Upvote {
if upvote.SessionUUID == sessionID {
return errors.New("user has already upvoted")
}
}
return f.db.Feedback.CreateUpvote(models.NewUpvote(sessionID, feedbackUUID))
case "downvote":
// check if user has already upvoted
for _, upvote := range feedback.Upvote {
if upvote.SessionUUID == sessionID {
return f.db.Feedback.DeleteUpvoteBySessionIDAndFeedbackUUID(sessionID, feedbackUUID)
}
}
}
return f.db.Feedback.CreateUpvote(models.NewUpvote(sessionID, feedbackUUID))
return nil
}