Merge pull request 'develop' (#5) from develop into master
All checks were successful
Backend deploy / deploy-backend (push) Successful in 4m31s
Frontend deploy / deploy-frontend (push) Successful in 2m40s
Backend ci / build (push) Successful in 3m37s

Reviewed-on: #5
This commit was merged in pull request #5.
This commit is contained in:
2026-02-09 16:14:55 +00:00
9 changed files with 197 additions and 17 deletions

View File

@@ -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

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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

View File

@@ -1,6 +1,8 @@
package handlers
import (
"strconv"
"gitea.d3m0k1d.ru/d3m0k1d/d3m0k1d.ru/backend/internal/logger"
"gitea.d3m0k1d.ru/d3m0k1d/d3m0k1d.ru/backend/internal/repositories"
"gitea.d3m0k1d.ru/d3m0k1d/d3m0k1d.ru/backend/internal/storage"
@@ -41,11 +43,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 +103,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

View File

@@ -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)
}
}

View File

@@ -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
}

View File

@@ -8,6 +8,7 @@ type Post struct {
}
type PostReq struct {
ID int `json:"id"`
Title string `json:"title"`
Content string `json:"content"`
}

View File

@@ -64,7 +64,7 @@ export default function About() {
<div>
<h3 className="font-mono font-semibold mb-1">Languages:</h3>
<p className="text-base-content/70">
Golang, Python, Bash, C (Base level), HTML/CSS, Typescript
Golang, Python, Bash, C (Base level), HTML/CSS, Typescript, SQL
</p>
</div>