From a68906b5ef0a0a92976fef5e68ca3d2c50a9f807 Mon Sep 17 00:00:00 2001 From: Steven Weathers Date: Tue, 29 Oct 2024 20:56:54 -0400 Subject: [PATCH] Add poker story put api endpoint This resolves #645 --- docs/swagger/docs.go | 86 +++++++++++++++++++++++++++++++++++++ docs/swagger/swagger.json | 86 +++++++++++++++++++++++++++++++++++++ docs/swagger/swagger.yaml | 56 ++++++++++++++++++++++++ internal/http/http.go | 1 + internal/http/poker.go | 89 ++++++++++++++++++++++++++++++++++++++- 5 files changed, 317 insertions(+), 1 deletion(-) diff --git a/docs/swagger/docs.go b/docs/swagger/docs.go index 5c9efeaf..50ef933a 100644 --- a/docs/swagger/docs.go +++ b/docs/swagger/docs.go @@ -2346,6 +2346,66 @@ const docTemplate = `{ } }, "/battles/{battleId}/plans/{planId}": { + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Updates a poker story", + "produces": [ + "application/json" + ], + "tags": [ + "poker" + ], + "summary": "Update Poker Story", + "parameters": [ + { + "type": "string", + "description": "the poker game ID", + "name": "battleId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "the poker story ID", + "name": "planId", + "in": "path", + "required": true + }, + { + "description": "updated story object", + "name": "story", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/http.storyUpdateRequestBody" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/http.standardJsonResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/http.standardJsonResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/http.standardJsonResponse" + } + } + } + }, "delete": { "security": [ { @@ -11117,6 +11177,32 @@ const docTemplate = `{ } } }, + "http.storyUpdateRequestBody": { + "type": "object", + "properties": { + "acceptanceCriteria": { + "type": "string" + }, + "description": { + "type": "string" + }, + "link": { + "type": "string" + }, + "planName": { + "type": "string" + }, + "priority": { + "type": "integer" + }, + "referenceId": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, "http.storyboardColumnAddRequestBody": { "type": "object", "required": [ diff --git a/docs/swagger/swagger.json b/docs/swagger/swagger.json index 1e10a07e..1b1e8dc7 100644 --- a/docs/swagger/swagger.json +++ b/docs/swagger/swagger.json @@ -2338,6 +2338,66 @@ } }, "/battles/{battleId}/plans/{planId}": { + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Updates a poker story", + "produces": [ + "application/json" + ], + "tags": [ + "poker" + ], + "summary": "Update Poker Story", + "parameters": [ + { + "type": "string", + "description": "the poker game ID", + "name": "battleId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "the poker story ID", + "name": "planId", + "in": "path", + "required": true + }, + { + "description": "updated story object", + "name": "story", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/http.storyUpdateRequestBody" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/http.standardJsonResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/http.standardJsonResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/http.standardJsonResponse" + } + } + } + }, "delete": { "security": [ { @@ -11109,6 +11169,32 @@ } } }, + "http.storyUpdateRequestBody": { + "type": "object", + "properties": { + "acceptanceCriteria": { + "type": "string" + }, + "description": { + "type": "string" + }, + "link": { + "type": "string" + }, + "planName": { + "type": "string" + }, + "priority": { + "type": "integer" + }, + "referenceId": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, "http.storyboardColumnAddRequestBody": { "type": "object", "required": [ diff --git a/docs/swagger/swagger.yaml b/docs/swagger/swagger.yaml index e3da4bee..93f71eaa 100644 --- a/docs/swagger/swagger.yaml +++ b/docs/swagger/swagger.yaml @@ -470,6 +470,23 @@ definitions: success: type: boolean type: object + http.storyUpdateRequestBody: + properties: + acceptanceCriteria: + type: string + description: + type: string + link: + type: string + planName: + type: string + priority: + type: integer + referenceId: + type: string + type: + type: string + type: object http.storyboardColumnAddRequestBody: properties: goalId: @@ -3427,6 +3444,45 @@ paths: summary: Delete Poker Story tags: - poker + put: + description: Updates a poker story + parameters: + - description: the poker game ID + in: path + name: battleId + required: true + type: string + - description: the poker story ID + in: path + name: planId + required: true + type: string + - description: updated story object + in: body + name: story + required: true + schema: + $ref: '#/definitions/http.storyUpdateRequestBody' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/http.standardJsonResponse' + "403": + description: Forbidden + schema: + $ref: '#/definitions/http.standardJsonResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/http.standardJsonResponse' + security: + - ApiKeyAuth: [] + summary: Update Poker Story + tags: + - poker /estimation-scales/public: get: description: get list of all public estimation scales diff --git a/internal/http/http.go b/internal/http/http.go index 91cf1713..9c4b7b11 100644 --- a/internal/http/http.go +++ b/internal/http/http.go @@ -328,6 +328,7 @@ func New(apiService Service, FSS fs.FS, HFS http.FileSystem) *Service { apiRouter.HandleFunc("/battles/{battleId}", a.userOnly(a.handleGetPokerGame())).Methods("GET") apiRouter.HandleFunc("/battles/{battleId}", a.userOnly(a.handlePokerDelete(pokerSvc))).Methods("DELETE") apiRouter.HandleFunc("/battles/{battleId}/plans", a.userOnly(a.handlePokerStoryAdd(pokerSvc))).Methods("POST") + apiRouter.HandleFunc("/battles/{battleId}/plans/{planId}", a.userOnly(a.handlePokerStoryUpdate(pokerSvc))).Methods("PUT") apiRouter.HandleFunc("/battles/{battleId}/plans/{planId}", a.userOnly(a.handlePokerStoryDelete(pokerSvc))).Methods("DELETE") apiRouter.HandleFunc("/arena/{battleId}", pokerSvc.ServeBattleWs()) diff --git a/internal/http/poker.go b/internal/http/poker.go index 0fb2fbc8..8f07de80 100644 --- a/internal/http/poker.go +++ b/internal/http/poker.go @@ -2,6 +2,7 @@ package http import ( "encoding/json" + "fmt" "io" "net/http" "slices" @@ -354,7 +355,93 @@ func (s *Service) handlePokerStoryAdd(pokerSvc *poker.Service) http.HandlerFunc } } -// handlePokerStoryAdd handles deleting a story from poker +type storyUpdateRequestBody struct { + ID string `json:"planId" swaggerignore:"true"` + Name string `json:"planName"` + Type string `json:"type"` + ReferenceID string `json:"referenceId"` + Link string `json:"link"` + Description string `json:"description"` + AcceptanceCriteria string `json:"acceptanceCriteria"` + Priority int32 `json:"priority"` +} + +// handlePokerStoryUpdate handles updating a poker story +// +// @Summary Update Poker Story +// @Description Updates a poker story +// @Param battleId path string true "the poker game ID" +// @Param planId path string true "the poker story ID" +// @Param story body storyUpdateRequestBody true "updated story object" +// @Tags poker +// @Produce json +// @Success 200 object standardJsonResponse{} +// @Success 403 object standardJsonResponse{} +// @Success 500 object standardJsonResponse{} +// @Security ApiKeyAuth +// @Router /battles/{battleId}/plans/{planId} [put] +func (s *Service) handlePokerStoryUpdate(pokerSvc *poker.Service) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + vars := mux.Vars(r) + gameID := vars["battleId"] + idErr := validate.Var(gameID, "required,uuid") + if idErr != nil { + s.Failure(w, r, http.StatusBadRequest, Errorf( + EINVALID, fmt.Errorf("invalid battleId: %v", idErr.Error()).Error()), + ) + return + } + storyID := vars["planId"] + idErr = validate.Var(storyID, "required,uuid") + if idErr != nil { + s.Failure(w, r, http.StatusBadRequest, Errorf( + EINVALID, fmt.Errorf("invalid storyId: %v", idErr.Error()).Error()), + ) + return + } + sessionUserID := ctx.Value(contextKeyUserID).(string) + + body, bodyErr := io.ReadAll(r.Body) + if bodyErr != nil { + s.Failure(w, r, http.StatusBadRequest, Errorf(EINVALID, bodyErr.Error())) + return + } + + var story = storyUpdateRequestBody{} + jsonErr := json.Unmarshal(body, &story) + if jsonErr != nil { + s.Failure(w, r, http.StatusBadRequest, Errorf(EINVALID, jsonErr.Error())) + return + } + + story.ID = storyID + inputErr := validate.Struct(story) + if inputErr != nil { + s.Failure(w, r, http.StatusBadRequest, Errorf(EINVALID, inputErr.Error())) + return + } + + updatedStory, err := json.Marshal(story) + if err != nil { + s.Failure(w, r, http.StatusInternalServerError, Errorf(EINTERNAL, err.Error())) + return + } + + err = pokerSvc.APIEvent(ctx, gameID, sessionUserID, "revise_plan", string(updatedStory)) + if err != nil { + s.Logger.Ctx(ctx).Error("handlePokerStoryUpdate error", zap.Error(err), + zap.String("poker_id", gameID), zap.String("session_user_id", sessionUserID), + zap.String("story_id", storyID)) + s.Failure(w, r, http.StatusInternalServerError, err) + return + } + + s.Success(w, r, http.StatusOK, nil, nil) + } +} + +// handlePokerStoryDelete handles deleting a story from poker // // @Summary Delete Poker Story // @Description Deletes a poker story