From d705c6a8e92a2b9a69b3fac2ad69cb32cf7bb7e4 Mon Sep 17 00:00:00 2001 From: Lei Da Date: Fri, 6 Sep 2024 10:08:45 +0800 Subject: [PATCH] add new api to get all comments of discussion --- api/handler/discussion.go | 55 +++++++++++++++++++----- api/router/api.go | 1 + component/discussion.go | 21 +++++++++ docs/docs.go | 89 ++++++++++++++++++++++++++++++++++----- docs/swagger.json | 89 ++++++++++++++++++++++++++++++++++----- docs/swagger.yaml | 64 +++++++++++++++++++++++----- 6 files changed, 277 insertions(+), 42 deletions(-) diff --git a/api/handler/discussion.go b/api/handler/discussion.go index 502bac7d..e718118e 100644 --- a/api/handler/discussion.go +++ b/api/handler/discussion.go @@ -32,9 +32,9 @@ func NewDiscussionHandler() (*DiscussionHandler, error) { // @Accept json // @Produce json // @Param current_user query string true "current user, the owner" -// @Param repo_type query string true "repository type" Enums(models,datasets,codes,spaces) -// @Param namespace query string true "namespace" -// @Param name query string true "name" +// @Param repo_type path string true "repository type" Enums(models,datasets,codes,spaces) +// @Param namespace path string true "namespace" +// @Param name path string true "name" // @Param body body component.CreateRepoDiscussionRequest true "body" // @Success 200 {object} types.Response{data=component.CreateDiscussionResponse} "OK" // @Failure 400 {object} types.APIBadRequest "Bad request" @@ -79,7 +79,7 @@ func (h *DiscussionHandler) CreateRepoDiscussion(ctx *gin.Context) { // @Tags Discussion // @Accept json // @Produce json -// @Param id query string true "the discussion id" +// @Param id path string true "the discussion id" // @Param current_user query string true "current user, the owner" // @Param body body component.UpdateDiscussionRequest true "body" // @Success 200 {object} types.Response "OK" @@ -87,6 +87,11 @@ func (h *DiscussionHandler) CreateRepoDiscussion(ctx *gin.Context) { // @Failure 500 {object} types.APIInternalServerError "Internal server error" // @Router /discussions/{id} [put] func (h *DiscussionHandler) UpdateDiscussion(ctx *gin.Context) { + currentUser := httpbase.GetCurrentUser(ctx) + if currentUser == "" { + httpbase.UnauthorizedError(ctx, component.ErrUserNotFound) + return + } id := ctx.Param("id") idInt, err := strconv.ParseInt(id, 10, 64) if err != nil { @@ -99,6 +104,7 @@ func (h *DiscussionHandler) UpdateDiscussion(ctx *gin.Context) { return } req.ID = idInt + req.CurrentUser = currentUser err = h.c.UpdateDiscussion(ctx, req) if err != nil { slog.Error("Failed to update discussion", "error", err, "request", req) @@ -116,7 +122,7 @@ func (h *DiscussionHandler) UpdateDiscussion(ctx *gin.Context) { // @Tags Discussion // @Accept json // @Produce json -// @Param id query string true "the discussion id" +// @Param id path string true "the discussion id" // @Param current_user query string true "current user, the owner of the discussion" // @Success 200 {object} types.Response "OK" // @Failure 400 {object} types.APIBadRequest "Bad request" @@ -151,7 +157,7 @@ func (h *DiscussionHandler) DeleteDiscussion(ctx *gin.Context) { // @Tags Discussion // @Accept json // @Produce json -// @Param id query string true "the discussion id" +// @Param id path string true "the discussion id" // @Success 200 {object} types.Response{data=component.ShowDiscussionResponse} "OK" // @Failure 400 {object} types.APIBadRequest "Bad request" // @Failure 500 {object} types.APIInternalServerError "Internal server error" @@ -181,8 +187,8 @@ func (h *DiscussionHandler) ShowDiscussion(ctx *gin.Context) { // @Accept json // @Produce json // @Param current_user query string false "current user" -// @Param repo_type query string true "repository type" Enums(models,datasets,codes,spaces) -// @Param namespace query string true "namespace" +// @Param repo_type path string true "repository type" Enums(models,datasets,codes,spaces) +// @Param namespace path string true "namespace" // @Param name query string true "name" // @Success 200 {object} types.Response{data=component.ListRepoDiscussionResponse} "OK" // @Failure 400 {object} types.APIBadRequest "Bad request" @@ -218,7 +224,7 @@ func (h *DiscussionHandler) ListRepoDiscussions(ctx *gin.Context) { // @Tags Discussion // @Accept json // @Produce json -// @Param id query string true "the discussion id" +// @Param id path string true "the discussion id" // @Param body body component.CreateCommentRequest true "body" // @Success 200 {object} types.Response{data=component.CreateCommentResponse} "OK" // @Failure 400 {object} types.APIBadRequest "Bad request" @@ -261,7 +267,7 @@ func (h *DiscussionHandler) CreateDiscussionComment(ctx *gin.Context) { // @Tags Discussion // @Accept json // @Produce json -// @Param id query string true "the comment id" +// @Param id path string true "the comment id" // @Param current_user query string true "current user, the owner of the comment" // @Param body body component.UpdateCommentRequest true "body" // @Success 200 {object} types.Response "OK" @@ -303,7 +309,7 @@ func (h *DiscussionHandler) UpdateComment(ctx *gin.Context) { // @Tags Discussion // @Accept json // @Produce json -// @Param id query string true "the comment id" +// @Param id path string true "the comment id" // @Param current_user query string true "current user, the owner of the comment" // @Success 200 {object} types.Response "OK" // @Failure 400 {object} types.APIBadRequest "Bad request" @@ -330,6 +336,33 @@ func (h *DiscussionHandler) DeleteComment(ctx *gin.Context) { httpbase.OK(ctx, nil) } +// ListDiscussionComments godoc +// @Security ApiKey +// @Summary List discussion comments +// @Description list discussion comments +// @Tags Discussion +// @Accept json +// @Produce json +// @Param id path string true "the discussion id" +// @Success 200 {object} types.Response{data=[]component.DiscussionResponse_Comment} "OK" +// @Failure 400 {object} types.APIBadRequest "Bad request" +// @Failure 500 {object} types.APIInternalServerError "Internal server error" +// @Router /discussions/{id}/comments [get] +func (h *DiscussionHandler) ListDiscussionComments(ctx *gin.Context) { + id := ctx.Param("id") + idInt, err := strconv.ParseInt(id, 10, 64) + if err != nil { + httpbase.BadRequest(ctx, fmt.Errorf("invalid discussion id: %w", err).Error()) + } + comments, err := h.c.ListDiscussionComments(ctx, idInt) + if err != nil { + slog.Error("Failed to list discussion comments", "error", err, "id", id) + httpbase.ServerError(ctx, fmt.Errorf("failed to list discussion comments: %w", err)) + return + } + httpbase.OK(ctx, comments) +} + func (h *DiscussionHandler) getRepoType(ctx *gin.Context) types.RepositoryType { repoType := ctx.Param("repo_type") repoType = strings.TrimRight(repoType, "s") diff --git a/api/router/api.go b/api/router/api.go index 5e4642fc..7528268a 100644 --- a/api/router/api.go +++ b/api/router/api.go @@ -701,6 +701,7 @@ func createDiscussionRoutes(apiGroup *gin.RouterGroup, needAPIKey gin.HandlerFun apiGroup.PUT("/discussions/:id", discussionHandler.UpdateDiscussion) apiGroup.DELETE("/discussions/:id", discussionHandler.DeleteDiscussion) apiGroup.POST("/discussions/:id/comments", discussionHandler.CreateDiscussionComment) + apiGroup.GET("/discussions/:id/comments", discussionHandler.ListDiscussionComments) apiGroup.PUT("/discussions/:id/comments/:comment_id", discussionHandler.UpdateComment) apiGroup.DELETE("/discussions/:id/comments/:comment_id", discussionHandler.DeleteComment) } diff --git a/component/discussion.go b/component/discussion.go index aa09d89d..3a246700 100644 --- a/component/discussion.go +++ b/component/discussion.go @@ -230,6 +230,27 @@ func (c *DiscussionComponent) DeleteComment(ctx context.Context, currentUser str return nil } +func (c *DiscussionComponent) ListDiscussionComments(ctx context.Context, discussionID int64) ([]*DiscussionResponse_Comment, error) { + comments, err := c.ds.FindDiscussionComments(ctx, discussionID) + if err != nil { + return nil, fmt.Errorf("failed to find discussion comments by discussion id '%d': %w", discussionID, err) + } + resp := make([]*DiscussionResponse_Comment, 0, len(comments)) + for _, comment := range comments { + resp = append(resp, &DiscussionResponse_Comment{ + ID: comment.ID, + Content: comment.Content, + User: &DiscussionResponse_User{ + ID: comment.User.ID, + Username: comment.User.Username, + Avatar: comment.User.Avatar, + }, + CreatedAt: comment.CreatedAt, + }) + } + return resp, nil +} + //--- request and response ---// type CreateRepoDiscussionRequest struct { diff --git a/docs/docs.go b/docs/docs.go index dd7ffb24..d87e1f19 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -1157,7 +1157,7 @@ const docTemplate = `{ "type": "string", "description": "the comment id", "name": "id", - "in": "query", + "in": "path", "required": true }, { @@ -1220,7 +1220,7 @@ const docTemplate = `{ "type": "string", "description": "the comment id", "name": "id", - "in": "query", + "in": "path", "required": true }, { @@ -1895,7 +1895,7 @@ const docTemplate = `{ "type": "string", "description": "the discussion id", "name": "id", - "in": "query", + "in": "path", "required": true } ], @@ -1954,7 +1954,7 @@ const docTemplate = `{ "type": "string", "description": "the discussion id", "name": "id", - "in": "query", + "in": "path", "required": true }, { @@ -2017,6 +2017,13 @@ const docTemplate = `{ "type": "string", "description": "the discussion id", "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "current user, the owner of the discussion", + "name": "current_user", "in": "query", "required": true } @@ -2044,6 +2051,68 @@ const docTemplate = `{ } }, "/discussions/{id}/comments": { + "get": { + "security": [ + { + "ApiKey": [] + } + ], + "description": "list discussion comments", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Discussion" + ], + "summary": "List discussion comments", + "parameters": [ + { + "type": "string", + "description": "the discussion id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/types.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/component.DiscussionResponse_Comment" + } + } + } + } + ] + } + }, + "400": { + "description": "Bad request", + "schema": { + "$ref": "#/definitions/types.APIBadRequest" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/types.APIInternalServerError" + } + } + } + }, "post": { "security": [ { @@ -2066,7 +2135,7 @@ const docTemplate = `{ "type": "string", "description": "the discussion id", "name": "id", - "in": "query", + "in": "path", "required": true }, { @@ -10207,14 +10276,14 @@ const docTemplate = `{ "type": "string", "description": "repository type", "name": "repo_type", - "in": "query", + "in": "path", "required": true }, { "type": "string", "description": "namespace", "name": "namespace", - "in": "query", + "in": "path", "required": true }, { @@ -10293,21 +10362,21 @@ const docTemplate = `{ "type": "string", "description": "repository type", "name": "repo_type", - "in": "query", + "in": "path", "required": true }, { "type": "string", "description": "namespace", "name": "namespace", - "in": "query", + "in": "path", "required": true }, { "type": "string", "description": "name", "name": "name", - "in": "query", + "in": "path", "required": true }, { diff --git a/docs/swagger.json b/docs/swagger.json index 4e7b021d..433774ac 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -1146,7 +1146,7 @@ "type": "string", "description": "the comment id", "name": "id", - "in": "query", + "in": "path", "required": true }, { @@ -1209,7 +1209,7 @@ "type": "string", "description": "the comment id", "name": "id", - "in": "query", + "in": "path", "required": true }, { @@ -1884,7 +1884,7 @@ "type": "string", "description": "the discussion id", "name": "id", - "in": "query", + "in": "path", "required": true } ], @@ -1943,7 +1943,7 @@ "type": "string", "description": "the discussion id", "name": "id", - "in": "query", + "in": "path", "required": true }, { @@ -2006,6 +2006,13 @@ "type": "string", "description": "the discussion id", "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "current user, the owner of the discussion", + "name": "current_user", "in": "query", "required": true } @@ -2033,6 +2040,68 @@ } }, "/discussions/{id}/comments": { + "get": { + "security": [ + { + "ApiKey": [] + } + ], + "description": "list discussion comments", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Discussion" + ], + "summary": "List discussion comments", + "parameters": [ + { + "type": "string", + "description": "the discussion id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/types.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/component.DiscussionResponse_Comment" + } + } + } + } + ] + } + }, + "400": { + "description": "Bad request", + "schema": { + "$ref": "#/definitions/types.APIBadRequest" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/types.APIInternalServerError" + } + } + } + }, "post": { "security": [ { @@ -2055,7 +2124,7 @@ "type": "string", "description": "the discussion id", "name": "id", - "in": "query", + "in": "path", "required": true }, { @@ -10196,14 +10265,14 @@ "type": "string", "description": "repository type", "name": "repo_type", - "in": "query", + "in": "path", "required": true }, { "type": "string", "description": "namespace", "name": "namespace", - "in": "query", + "in": "path", "required": true }, { @@ -10282,21 +10351,21 @@ "type": "string", "description": "repository type", "name": "repo_type", - "in": "query", + "in": "path", "required": true }, { "type": "string", "description": "namespace", "name": "namespace", - "in": "query", + "in": "path", "required": true }, { "type": "string", "description": "name", "name": "name", - "in": "query", + "in": "path", "required": true }, { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 59570455..0f596f38 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -2382,12 +2382,12 @@ paths: - datasets - codes - spaces - in: query + in: path name: repo_type required: true type: string - description: namespace - in: query + in: path name: namespace required: true type: string @@ -2437,17 +2437,17 @@ paths: - datasets - codes - spaces - in: query + in: path name: repo_type required: true type: string - description: namespace - in: query + in: path name: namespace required: true type: string - description: name - in: query + in: path name: name required: true type: string @@ -4596,7 +4596,7 @@ paths: description: delete a comment by id parameters: - description: the comment id - in: query + in: path name: id required: true type: string @@ -4631,7 +4631,7 @@ paths: description: update a comment content by id parameters: - description: the comment id - in: query + in: path name: id required: true type: string @@ -5058,10 +5058,15 @@ paths: description: delete a discussion parameters: - description: the discussion id - in: query + in: path name: id required: true type: string + - description: current user, the owner of the discussion + in: query + name: current_user + required: true + type: string produces: - application/json responses: @@ -5088,7 +5093,7 @@ paths: description: show a discussion parameters: - description: the discussion id - in: query + in: path name: id required: true type: string @@ -5123,7 +5128,7 @@ paths: description: update a discussion parameters: - description: the discussion id - in: query + in: path name: id required: true type: string @@ -5159,13 +5164,50 @@ paths: tags: - Discussion /discussions/{id}/comments: + get: + consumes: + - application/json + description: list discussion comments + parameters: + - description: the discussion id + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/types.Response' + - properties: + data: + items: + $ref: '#/definitions/component.DiscussionResponse_Comment' + type: array + type: object + "400": + description: Bad request + schema: + $ref: '#/definitions/types.APIBadRequest' + "500": + description: Internal server error + schema: + $ref: '#/definitions/types.APIInternalServerError' + security: + - ApiKey: [] + summary: List discussion comments + tags: + - Discussion post: consumes: - application/json description: create a new discussion comment parameters: - description: the discussion id - in: query + in: path name: id required: true type: string