diff --git a/.gitea/workflows/cd-back.yml b/.gitea/workflows/cd-back.yml index 6cb35d7..cd8fa68 100644 --- a/.gitea/workflows/cd-back.yml +++ b/.gitea/workflows/cd-back.yml @@ -6,7 +6,7 @@ on: workflow_dispatch: jobs: - deploy-frontend: + deploy-backend: runs-on: ubuntu-latest steps: - name: Checkout code @@ -44,4 +44,4 @@ jobs: docker login -u d3m0k1d -p ${{ steps.import-secrets.outputs.GITEA_TOKEN }} gitea.d3m0k1d.ru docker pull gitea.d3m0k1d.ru/d3m0k1d/backend:latest docker rm -f d3m0k1d-backend || true - docker run --name d3m0k1d-backend -d -p 80:80 --restart unless-stopped gitea.d3m0k1d.ru/d3m0k1d/backend:latest + docker run --name d3m0k1d-backend -d -p 8080:8080 --restart unless-stopped gitea.d3m0k1d.ru/d3m0k1d/backend:latest diff --git a/backend/docs/docs.go b/backend/docs/docs.go index 25c54ed..0ffb957 100644 --- a/backend/docs/docs.go +++ b/backend/docs/docs.go @@ -92,12 +92,39 @@ const docTemplate = `{ "posts" ], "summary": "Get post by id", + "parameters": [ + { + "type": "integer", + "description": "Post ID", + "name": "id", + "in": "path", + "required": true + } + ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_d3m0k1d_ru_backend_internal_storage.PostReq" } + }, + "400": { + "description": "Invalid ID format", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "500": { + "description": "Internal server error", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } } } }, @@ -113,11 +140,29 @@ const docTemplate = `{ "posts" ], "summary": "Update post", + "parameters": [ + { + "type": "integer", + "description": "Post ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Post data", + "name": "post", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_d3m0k1d_ru_backend_internal_storage.PostCreate" + } + } + ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_d3m0k1d_ru_backend_internal_storage.Post" + "$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_d3m0k1d_ru_backend_internal_storage.PostCreate" } } } @@ -184,6 +229,9 @@ const docTemplate = `{ "content": { "type": "string" }, + "id": { + "type": "integer" + }, "title": { "type": "string" } diff --git a/backend/docs/swagger.json b/backend/docs/swagger.json index ca1073b..518167b 100644 --- a/backend/docs/swagger.json +++ b/backend/docs/swagger.json @@ -81,12 +81,39 @@ "posts" ], "summary": "Get post by id", + "parameters": [ + { + "type": "integer", + "description": "Post ID", + "name": "id", + "in": "path", + "required": true + } + ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_d3m0k1d_ru_backend_internal_storage.PostReq" } + }, + "400": { + "description": "Invalid ID format", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "500": { + "description": "Internal server error", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } } } }, @@ -102,11 +129,29 @@ "posts" ], "summary": "Update post", + "parameters": [ + { + "type": "integer", + "description": "Post ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Post data", + "name": "post", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_d3m0k1d_ru_backend_internal_storage.PostCreate" + } + } + ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_d3m0k1d_ru_backend_internal_storage.Post" + "$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_d3m0k1d_ru_backend_internal_storage.PostCreate" } } } @@ -173,6 +218,9 @@ "content": { "type": "string" }, + "id": { + "type": "integer" + }, "title": { "type": "string" } diff --git a/backend/docs/swagger.yaml b/backend/docs/swagger.yaml index ff0700f..ff5bb35 100644 --- a/backend/docs/swagger.yaml +++ b/backend/docs/swagger.yaml @@ -24,6 +24,8 @@ definitions: properties: content: type: string + id: + type: integer title: type: string type: object @@ -91,6 +93,12 @@ paths: consumes: - application/json description: Get post by id + parameters: + - description: Post ID + in: path + name: id + required: true + type: integer produces: - application/json responses: @@ -98,6 +106,18 @@ paths: description: OK schema: $ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_d3m0k1d_ru_backend_internal_storage.PostReq' + "400": + description: Invalid ID format + schema: + additionalProperties: + type: string + type: object + "500": + description: Internal server error + schema: + additionalProperties: + type: string + type: object summary: Get post by id tags: - posts @@ -105,13 +125,25 @@ paths: consumes: - application/json description: Update post + parameters: + - description: Post ID + in: path + name: id + required: true + type: integer + - description: Post data + in: body + name: post + required: true + schema: + $ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_d3m0k1d_ru_backend_internal_storage.PostCreate' produces: - application/json responses: "200": description: OK schema: - $ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_d3m0k1d_ru_backend_internal_storage.Post' + $ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_d3m0k1d_ru_backend_internal_storage.PostCreate' summary: Update post tags: - posts diff --git a/backend/internal/handlers/post_handlers.go b/backend/internal/handlers/post_handlers.go index d5bf7a7..5af0d2b 100644 --- a/backend/internal/handlers/post_handlers.go +++ b/backend/internal/handlers/post_handlers.go @@ -5,6 +5,7 @@ import ( "gitea.d3m0k1d.ru/d3m0k1d/d3m0k1d.ru/backend/internal/repositories" "gitea.d3m0k1d.ru/d3m0k1d/d3m0k1d.ru/backend/internal/storage" "github.com/gin-gonic/gin" + "strconv" ) type PostHandlers struct { @@ -41,11 +42,28 @@ func (h *PostHandlers) GetPosts(c *gin.Context) { // @Description Get post by id // @Tags posts // @Accept json +// @Param id path int true "Post ID" // @Produce json // @Success 200 {object} storage.PostReq +// @Failure 400 {object} map[string]string "Invalid ID format" +// @Failure 500 {object} map[string]string "Internal server error" // @Router /posts/{id} [get] -func GetPost(c *gin.Context) { - log.Info("GetPost") +func (h *PostHandlers) GetPost(c *gin.Context) { + var result storage.PostReq + id_p := c.Param("id") + id, err := strconv.Atoi(id_p) + if err != nil { + log.Error("error request: " + err.Error()) + c.Status(500) + } + result, err = h.repo.GetByID(c.Request.Context(), id) + if err != nil { + log.Error("error request: " + err.Error()) + c.Status(500) + } + log.Info("200 OK GET /posts/" + id_p) + c.JSON(200, result) + // TODO: added validaton for 400 response } // CreatePost godoc @@ -84,11 +102,31 @@ func (h *PostHandlers) CreatePost(c *gin.Context) { // @Description Update post // @Tags posts // @Accept json +// @Param id path int true "Post ID" +// @Param post body storage.PostCreate true "Post data" // @Produce json -// @Success 200 {object} storage.Post +// @Success 200 {object} storage.PostCreate // @Router /posts/{id} [put] -func UpdatePost(c *gin.Context) { - log.Info("UpdatePost") +func (h *PostHandlers) UpdatePost(c *gin.Context) { + id_p := c.Param("id") + id, err := strconv.Atoi(id_p) + if err != nil { + log.Error("error request: " + err.Error()) + c.Status(500) + } + var req storage.Post + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(400, gin.H{"error": err.Error()}) + return + } + err = h.repo.Update(c.Request.Context(), id, req) + if err != nil { + c.JSON(500, gin.H{"error": err.Error()}) + return + } + + c.JSON(200, req) + log.Info("200 OK PUT /posts/" + id_p) } // DeletePost godoc diff --git a/backend/internal/handlers/registry_handlers.go b/backend/internal/handlers/registry_handlers.go index 4a8ff7b..9394aac 100644 --- a/backend/internal/handlers/registry_handlers.go +++ b/backend/internal/handlers/registry_handlers.go @@ -13,9 +13,9 @@ func Register(router *gin.Engine, db *sql.DB) { posts := v1.Group("posts") { posts.GET("/", handler_posts.GetPosts) - posts.GET("/:id", GetPost) + posts.GET("/:id", handler_posts.GetPost) posts.POST("/", handler_posts.CreatePost) - posts.PUT("/:id", UpdatePost) + posts.PUT("/:id", handler_posts.UpdatePost) posts.DELETE("/:id", DeletePost) } } diff --git a/backend/internal/repositories/post_repository.go b/backend/internal/repositories/post_repository.go index 0ee0db3..7917b3f 100644 --- a/backend/internal/repositories/post_repository.go +++ b/backend/internal/repositories/post_repository.go @@ -21,7 +21,7 @@ func NewPostRepository(db *sql.DB) PostRepository { } func (p *postRepository) GetAll(ctx context.Context) ([]storage.PostReq, error) { var result []storage.PostReq - rows, err := p.db.Query("SELECT title content FROM posts") + rows, err := p.db.Query("SELECT id, title, content FROM posts") if err != nil { p.logger.Error(err.Error()) return nil, err @@ -29,11 +29,13 @@ func (p *postRepository) GetAll(ctx context.Context) ([]storage.PostReq, error) for rows.Next() { var title string var content string - err := rows.Scan(&title, &content) + var id int + err := rows.Scan(&id, &title, &content) if err != nil { p.logger.Error("error scan: " + err.Error()) } result = append(result, storage.PostReq{ + ID: id, Title: title, Content: content, }) @@ -43,7 +45,7 @@ func (p *postRepository) GetAll(ctx context.Context) ([]storage.PostReq, error) func (p *postRepository) GetByID(ctx context.Context, id int) (storage.PostReq, error) { var result storage.PostReq - row := p.db.QueryRow("SELECT title content FROM posts WHERE id = ?", id) + row := p.db.QueryRow("SELECT title, content FROM posts WHERE id = ?", id) var title string var content string err := row.Scan(&title, &content) @@ -51,6 +53,7 @@ func (p *postRepository) GetByID(ctx context.Context, id int) (storage.PostReq, p.logger.Error("error scan: " + err.Error()) } result = storage.PostReq{ + ID: id, Title: title, Content: content, } @@ -75,7 +78,16 @@ func (p *postRepository) Create(ctx context.Context, post storage.Post) error { } func (p *postRepository) Update(ctx context.Context, id int, post storage.Post) error { - + _, err := p.db.Exec( + "UPDATE posts SET title = ?, content = ? WHERE id = ?", + post.Title, + post.Content, + id, + ) + if err != nil { + return err + } + p.logger.Info("Post updated:", "id", id) return nil } diff --git a/backend/internal/storage/models.go b/backend/internal/storage/models.go index 4023e90..69c8637 100644 --- a/backend/internal/storage/models.go +++ b/backend/internal/storage/models.go @@ -8,6 +8,7 @@ type Post struct { } type PostReq struct { + ID int `json:"id"` Title string `json:"title"` Content string `json:"content"` }