chore: add qe and integrations with rabbit mq
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
FROM golang:1.26-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN CGO_ENABLED=0 go build -o /server ./cmd/main.go && \
|
||||
go install github.com/pressly/goose/v3/cmd/goose@latest
|
||||
|
||||
FROM alpine:3.19
|
||||
|
||||
RUN apk add --no-cache ca-certificates
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=builder /server /server
|
||||
COPY --from=builder /go/bin/goose /usr/local/bin/goose
|
||||
COPY migrations /app/migrations
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
CMD ["/server"]
|
||||
+33
-2
@@ -1,12 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/rostpoliplast/backend/docs"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
swaggerFiles "github.com/swaggo/files"
|
||||
ginSwagger "github.com/swaggo/gin-swagger"
|
||||
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/rostpoliplast/backend/internal/handlers"
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/rostpoliplast/backend/internal/mq"
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/rostpoliplast/backend/internal/storage"
|
||||
)
|
||||
|
||||
// @securityDefinitions.apikey Bearer
|
||||
@@ -15,6 +22,31 @@ import (
|
||||
// @description Type "Bearer" followed by a space and the JWT token.
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
|
||||
connStr := os.Getenv("DATABASE_URL")
|
||||
if connStr == "" {
|
||||
connStr = "postgres://postgres:postgres@localhost:5432/rostpoliplast?sslmode=disable"
|
||||
}
|
||||
|
||||
pool, err := pgxpool.New(ctx, connStr)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to connect to database: %v", err)
|
||||
}
|
||||
defer pool.Close()
|
||||
|
||||
if err := pool.Ping(ctx); err != nil {
|
||||
log.Fatalf("failed to ping database: %v", err)
|
||||
}
|
||||
|
||||
rabbit, err := mq.NewRabbitMQ()
|
||||
if err != nil {
|
||||
log.Printf("warning: failed to connect to rabbitmq: %v", err)
|
||||
}
|
||||
defer rabbit.Close()
|
||||
|
||||
repo := storage.NewRepository(pool)
|
||||
h := &handlers.Handlers{Repo: repo, MQ: rabbit}
|
||||
|
||||
router := gin.Default()
|
||||
v1 := router.Group("/api/v1")
|
||||
@@ -24,8 +56,7 @@ func main() {
|
||||
docs.SwaggerInfo.Version = "1.0"
|
||||
docs.SwaggerInfo.Schemes = []string{"http", "https"}
|
||||
|
||||
baleHandlers := &handlers.Handlers{}
|
||||
baleHandlers.RegisterRoutes(v1)
|
||||
h.RegisterRoutes(v1)
|
||||
|
||||
{
|
||||
v1.GET("/health", func(c *gin.Context) {
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
environment:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: rostpoliplast
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
ports:
|
||||
- "5432:5432"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
rabbitmq:
|
||||
image: rabbitmq:3-management-alpine
|
||||
environment:
|
||||
RABBITMQ_DEFAULT_USER: guest
|
||||
RABBITMQ_DEFAULT_PASS: guest
|
||||
ports:
|
||||
- "5672:5672"
|
||||
- "15672:15672"
|
||||
healthcheck:
|
||||
test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"]
|
||||
interval: 10s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "8080:8080"
|
||||
environment:
|
||||
DATABASE_URL: postgres://postgres:postgres@postgres:5432/rostpoliplast?sslmode=disable
|
||||
RABBITMQ_URL: amqp://guest:guest@rabbitmq:5672/
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
rabbitmq:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- ./migrations:/app/migrations
|
||||
command: >
|
||||
sh -c "
|
||||
goose -dir=/app/migrations postgres 'postgres://postgres:postgres@postgres:5432/rostpoliplast?sslmode=disable' up &&
|
||||
/server
|
||||
"
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
+370
-1
@@ -14,7 +14,376 @@ const docTemplate = `{
|
||||
},
|
||||
"host": "{{.Host}}",
|
||||
"basePath": "{{.BasePath}}",
|
||||
"paths": {},
|
||||
"paths": {
|
||||
"/bale-types": {
|
||||
"get": {
|
||||
"description": "Возвращает список всех типов тюков",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"bale-types"
|
||||
],
|
||||
"summary": "Получить все типы тюков",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.BaleType"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"description": "Создаёт новый тип тюка",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"bale-types"
|
||||
],
|
||||
"summary": "Создать тип тюка",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Данные типа тюка",
|
||||
"name": "bale_type",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.BaleType"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Created",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.BaleType"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/bale-types/{id}": {
|
||||
"get": {
|
||||
"description": "Возвращает тип тюка по ID",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"bale-types"
|
||||
],
|
||||
"summary": "Получить тип тюка по ID",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "ID типа тюка",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.BaleType"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"description": "Обновляет данные типа тюка по ID",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"bale-types"
|
||||
],
|
||||
"summary": "Обновить тип тюка",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "ID типа тюка",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Данные типа тюка",
|
||||
"name": "bale_type",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.BaleType"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.BaleType"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"description": "Удаляет тип тюка по ID",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"bale-types"
|
||||
],
|
||||
"summary": "Удалить тип тюка",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "ID типа тюка",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/bales": {
|
||||
"get": {
|
||||
"description": "Возвращает список всех тюков",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"bales"
|
||||
],
|
||||
"summary": "Получить все тюки",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.Bale"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"description": "Создаёт новый тюк и отправляет в очередь задач RabbitMQ",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"bales"
|
||||
],
|
||||
"summary": "Создать тюк",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Данные тюка",
|
||||
"name": "bale",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.Bale"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Created",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.Bale"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/bales/{id}": {
|
||||
"get": {
|
||||
"description": "Возвращает тюк по ID",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"bales"
|
||||
],
|
||||
"summary": "Получить тюк по ID",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "ID тюка",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.Bale"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"description": "Обновляет данные тюка по ID",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"bales"
|
||||
],
|
||||
"summary": "Обновить тюк",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "ID тюка",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Данные тюка",
|
||||
"name": "bale",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.Bale"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.Bale"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"description": "Удаляет тюк по ID",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"bales"
|
||||
],
|
||||
"summary": "Удалить тюк",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "ID тюка",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.Bale": {
|
||||
"description": "Тюк - единица готовой продукции",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"typeId": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.BaleType": {
|
||||
"description": "Тип тюка - характеристики тюка",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"height": {
|
||||
"type": "number"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"length": {
|
||||
"type": "number"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"weight": {
|
||||
"type": "number"
|
||||
},
|
||||
"width": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"securityDefinitions": {
|
||||
"Bearer": {
|
||||
"description": "Type \"Bearer\" followed by a space and the JWT token.",
|
||||
|
||||
+370
-1
@@ -3,7 +3,376 @@
|
||||
"info": {
|
||||
"contact": {}
|
||||
},
|
||||
"paths": {},
|
||||
"paths": {
|
||||
"/bale-types": {
|
||||
"get": {
|
||||
"description": "Возвращает список всех типов тюков",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"bale-types"
|
||||
],
|
||||
"summary": "Получить все типы тюков",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.BaleType"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"description": "Создаёт новый тип тюка",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"bale-types"
|
||||
],
|
||||
"summary": "Создать тип тюка",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Данные типа тюка",
|
||||
"name": "bale_type",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.BaleType"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Created",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.BaleType"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/bale-types/{id}": {
|
||||
"get": {
|
||||
"description": "Возвращает тип тюка по ID",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"bale-types"
|
||||
],
|
||||
"summary": "Получить тип тюка по ID",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "ID типа тюка",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.BaleType"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"description": "Обновляет данные типа тюка по ID",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"bale-types"
|
||||
],
|
||||
"summary": "Обновить тип тюка",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "ID типа тюка",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Данные типа тюка",
|
||||
"name": "bale_type",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.BaleType"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.BaleType"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"description": "Удаляет тип тюка по ID",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"bale-types"
|
||||
],
|
||||
"summary": "Удалить тип тюка",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "ID типа тюка",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/bales": {
|
||||
"get": {
|
||||
"description": "Возвращает список всех тюков",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"bales"
|
||||
],
|
||||
"summary": "Получить все тюки",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.Bale"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"description": "Создаёт новый тюк и отправляет в очередь задач RabbitMQ",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"bales"
|
||||
],
|
||||
"summary": "Создать тюк",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Данные тюка",
|
||||
"name": "bale",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.Bale"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Created",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.Bale"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/bales/{id}": {
|
||||
"get": {
|
||||
"description": "Возвращает тюк по ID",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"bales"
|
||||
],
|
||||
"summary": "Получить тюк по ID",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "ID тюка",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.Bale"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"description": "Обновляет данные тюка по ID",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"bales"
|
||||
],
|
||||
"summary": "Обновить тюк",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "ID тюка",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Данные тюка",
|
||||
"name": "bale",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.Bale"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.Bale"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"description": "Удаляет тюк по ID",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"bales"
|
||||
],
|
||||
"summary": "Удалить тюк",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "ID тюка",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.Bale": {
|
||||
"description": "Тюк - единица готовой продукции",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"typeId": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.BaleType": {
|
||||
"description": "Тип тюка - характеристики тюка",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"height": {
|
||||
"type": "number"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"length": {
|
||||
"type": "number"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"weight": {
|
||||
"type": "number"
|
||||
},
|
||||
"width": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"securityDefinitions": {
|
||||
"Bearer": {
|
||||
"description": "Type \"Bearer\" followed by a space and the JWT token.",
|
||||
|
||||
+244
-1
@@ -1,6 +1,249 @@
|
||||
definitions:
|
||||
gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.Bale:
|
||||
description: Тюк - единица готовой продукции
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
timestamp:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
typeId:
|
||||
type: integer
|
||||
type: object
|
||||
gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.BaleType:
|
||||
description: Тип тюка - характеристики тюка
|
||||
properties:
|
||||
height:
|
||||
type: number
|
||||
id:
|
||||
type: integer
|
||||
length:
|
||||
type: number
|
||||
type:
|
||||
type: string
|
||||
weight:
|
||||
type: number
|
||||
width:
|
||||
type: number
|
||||
type: object
|
||||
info:
|
||||
contact: {}
|
||||
paths: {}
|
||||
paths:
|
||||
/bale-types:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Возвращает список всех типов тюков
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.BaleType'
|
||||
type: array
|
||||
summary: Получить все типы тюков
|
||||
tags:
|
||||
- bale-types
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Создаёт новый тип тюка
|
||||
parameters:
|
||||
- description: Данные типа тюка
|
||||
in: body
|
||||
name: bale_type
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.BaleType'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"201":
|
||||
description: Created
|
||||
schema:
|
||||
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.BaleType'
|
||||
summary: Создать тип тюка
|
||||
tags:
|
||||
- bale-types
|
||||
/bale-types/{id}:
|
||||
delete:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Удаляет тип тюка по ID
|
||||
parameters:
|
||||
- description: ID типа тюка
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: integer
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: boolean
|
||||
type: object
|
||||
summary: Удалить тип тюка
|
||||
tags:
|
||||
- bale-types
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Возвращает тип тюка по ID
|
||||
parameters:
|
||||
- description: ID типа тюка
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: integer
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.BaleType'
|
||||
summary: Получить тип тюка по ID
|
||||
tags:
|
||||
- bale-types
|
||||
put:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Обновляет данные типа тюка по ID
|
||||
parameters:
|
||||
- description: ID типа тюка
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: integer
|
||||
- description: Данные типа тюка
|
||||
in: body
|
||||
name: bale_type
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.BaleType'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.BaleType'
|
||||
summary: Обновить тип тюка
|
||||
tags:
|
||||
- bale-types
|
||||
/bales:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Возвращает список всех тюков
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.Bale'
|
||||
type: array
|
||||
summary: Получить все тюки
|
||||
tags:
|
||||
- bales
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Создаёт новый тюк и отправляет в очередь задач RabbitMQ
|
||||
parameters:
|
||||
- description: Данные тюка
|
||||
in: body
|
||||
name: bale
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.Bale'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"201":
|
||||
description: Created
|
||||
schema:
|
||||
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.Bale'
|
||||
summary: Создать тюк
|
||||
tags:
|
||||
- bales
|
||||
/bales/{id}:
|
||||
delete:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Удаляет тюк по ID
|
||||
parameters:
|
||||
- description: ID тюка
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: boolean
|
||||
type: object
|
||||
summary: Удалить тюк
|
||||
tags:
|
||||
- bales
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Возвращает тюк по ID
|
||||
parameters:
|
||||
- description: ID тюка
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.Bale'
|
||||
summary: Получить тюк по ID
|
||||
tags:
|
||||
- bales
|
||||
put:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Обновляет данные тюка по ID
|
||||
parameters:
|
||||
- description: ID тюка
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
- description: Данные тюка
|
||||
in: body
|
||||
name: bale
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.Bale'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_rostpoliplast_backend_internal_storage.Bale'
|
||||
summary: Обновить тюк
|
||||
tags:
|
||||
- bales
|
||||
securityDefinitions:
|
||||
Bearer:
|
||||
description: Type "Bearer" followed by a space and the JWT token.
|
||||
|
||||
+11
-9
@@ -4,6 +4,8 @@ go 1.26.2
|
||||
|
||||
require (
|
||||
github.com/gin-gonic/gin v1.12.0
|
||||
github.com/jackc/pgx/v5 v5.9.2
|
||||
github.com/rabbitmq/amqp091-go v1.11.0
|
||||
github.com/swaggo/files v1.0.1
|
||||
github.com/swaggo/gin-swagger v1.6.1
|
||||
github.com/swaggo/swag v1.8.12
|
||||
@@ -30,29 +32,29 @@ require (
|
||||
github.com/goccy/go-yaml v1.19.2 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/pgx/v5 v5.9.2 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.6 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-isatty v0.0.21 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/quic-go/qpack v0.6.0 // indirect
|
||||
github.com/quic-go/quic-go v0.59.0 // indirect
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.3.1 // indirect
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect
|
||||
golang.org/x/arch v0.22.0 // indirect
|
||||
golang.org/x/crypto v0.48.0 // indirect
|
||||
golang.org/x/net v0.51.0 // indirect
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/sys v0.41.0 // indirect
|
||||
golang.org/x/text v0.34.0 // indirect
|
||||
golang.org/x/tools v0.41.0 // indirect
|
||||
google.golang.org/protobuf v1.36.10 // indirect
|
||||
golang.org/x/crypto v0.50.0 // indirect
|
||||
golang.org/x/net v0.53.0 // indirect
|
||||
golang.org/x/sync v0.20.0 // indirect
|
||||
golang.org/x/sys v0.43.0 // indirect
|
||||
golang.org/x/text v0.36.0 // indirect
|
||||
golang.org/x/tools v0.44.0 // indirect
|
||||
google.golang.org/protobuf v1.36.11 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
|
||||
+24
-19
@@ -76,8 +76,8 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
|
||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.21 h1:xYae+lCNBP7QuW4PUnNG61ffM4hVIfm+zUzDuSzYLGs=
|
||||
github.com/mattn/go-isatty v0.0.21/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
@@ -92,8 +92,12 @@ github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
|
||||
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
|
||||
github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw=
|
||||
github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
|
||||
github.com/rabbitmq/amqp091-go v1.11.0 h1:HxIctVm9Gid/Vtn706necmZ7Wj6pgGI2eqplRbEY8O8=
|
||||
github.com/rabbitmq/amqp091-go v1.11.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
@@ -120,28 +124,30 @@ github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2W
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0 h1:yXUhImUjjAInNcpTcAlPHiT7bIXhshCTL3jVBkF3xaE=
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
|
||||
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
|
||||
golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI=
|
||||
golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
||||
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
|
||||
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
|
||||
golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=
|
||||
golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
|
||||
golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
|
||||
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
|
||||
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
|
||||
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -149,9 +155,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
|
||||
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
@@ -160,16 +165,16 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
|
||||
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
|
||||
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
|
||||
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc=
|
||||
golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg=
|
||||
golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c=
|
||||
golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
||||
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/skip2/go-qrcode"
|
||||
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/rostpoliplast/backend/internal/storage"
|
||||
)
|
||||
|
||||
type BaleTypeHandlers struct {
|
||||
Repo *storage.Repository
|
||||
}
|
||||
|
||||
func (h *BaleTypeHandlers) RegisterRoutes(g *gin.RouterGroup) {
|
||||
g.GET("/bale-types", h.GetBaleTypes)
|
||||
g.GET("/bale-types/qr/:id", h.GetBaleTypeQR)
|
||||
g.GET("/bale-types/:id", h.GetBaleTypeByID)
|
||||
g.POST("/bale-types", h.CreateBaleType)
|
||||
g.PUT("/bale-types/:id", h.UpdateBaleType)
|
||||
g.DELETE("/bale-types/:id", h.DeleteBaleType)
|
||||
}
|
||||
|
||||
// GetBaleTypes Получить список всех типов тюков
|
||||
// @Summary Получить все типы тюков
|
||||
// @Description Возвращает список всех типов тюков
|
||||
// @Tags bale-types
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {array} storage.BaleType
|
||||
// @Router /bale-types [get]
|
||||
func (h *BaleTypeHandlers) GetBaleTypes(c *gin.Context) {
|
||||
types, err := h.Repo.GetBaleTypes(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, types)
|
||||
}
|
||||
|
||||
// GetBaleTypeByID Получить тип тюка по ID
|
||||
// @Summary Получить тип тюка по ID
|
||||
// @Description Возвращает тип тюка по ID
|
||||
// @Tags bale-types
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int true "ID типа тюка"
|
||||
// @Success 200 {object} storage.BaleType
|
||||
// @Router /bale-types/{id} [get]
|
||||
func (h *BaleTypeHandlers) GetBaleTypeByID(c *gin.Context) {
|
||||
id, err := strconv.Atoi(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
|
||||
return
|
||||
}
|
||||
bt, err := h.Repo.GetBaleTypeByID(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, bt)
|
||||
}
|
||||
|
||||
// CreateBaleType Создать новый тип тюка
|
||||
// @Summary Создать тип тюка
|
||||
// @Description Создаёт новый тип тюка
|
||||
// @Tags bale-types
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param bale_type body storage.BaleType true "Данные типа тюка"
|
||||
// @Success 201 {object} storage.BaleType
|
||||
// @Router /bale-types [post]
|
||||
func (h *BaleTypeHandlers) CreateBaleType(c *gin.Context) {
|
||||
var input storage.BaleType
|
||||
if err := c.ShouldBindJSON(&input); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
bt, err := h.Repo.CreateBaleType(c.Request.Context(), input)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusCreated, bt)
|
||||
}
|
||||
|
||||
// UpdateBaleType Обновить тип тюка
|
||||
// @Summary Обновить тип тюка
|
||||
// @Description Обновляет данные типа тюка по ID
|
||||
// @Tags bale-types
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int true "ID типа тюка"
|
||||
// @Param bale_type body storage.BaleType true "Данные типа тюка"
|
||||
// @Success 200 {object} storage.BaleType
|
||||
// @Router /bale-types/{id} [put]
|
||||
func (h *BaleTypeHandlers) UpdateBaleType(c *gin.Context) {
|
||||
id, err := strconv.Atoi(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
|
||||
return
|
||||
}
|
||||
var input storage.BaleType
|
||||
if err := c.ShouldBindJSON(&input); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
bt, err := h.Repo.UpdateBaleType(c.Request.Context(), id, input)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, bt)
|
||||
}
|
||||
|
||||
// DeleteBaleType Удалить тип тюка
|
||||
// @Summary Удалить тип тюка
|
||||
// @Description Удаляет тип тюка по ID
|
||||
// @Tags bale-types
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int true "ID типа тюка"
|
||||
// @Success 200 {object} map[string]bool
|
||||
// @Router /bale-types/{id} [delete]
|
||||
func (h *BaleTypeHandlers) DeleteBaleType(c *gin.Context) {
|
||||
id, err := strconv.Atoi(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
|
||||
return
|
||||
}
|
||||
if err := h.Repo.DeleteBaleType(c.Request.Context(), id); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"deleted": true})
|
||||
}
|
||||
|
||||
// GetBaleTypeQR Получить QR код для маркировки тюка
|
||||
// @Summary Получить QR код для маркировки тюка
|
||||
// @Description Возвращает QR код с URL для регистрации тюка этого типа
|
||||
// @Tags bale-types
|
||||
// @Accept json
|
||||
// @Produce png
|
||||
// @Param id path int true "ID типа тюка"
|
||||
// @Success 200 {file} image/png
|
||||
// @Router /bale-types/qr/{id} [get]
|
||||
func (h *BaleTypeHandlers) GetBaleTypeQR(c *gin.Context) {
|
||||
id, err := strconv.Atoi(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
|
||||
return
|
||||
}
|
||||
|
||||
bt, err := h.Repo.GetBaleTypeByID(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "type not found"})
|
||||
return
|
||||
}
|
||||
|
||||
server := c.Request.URL.Host
|
||||
if server == "" {
|
||||
server = "localhost:8080"
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("http://%s/api/v1/bales?type=%s", server, bt.Type)
|
||||
png, err := qrcode.Encode(url, qrcode.Medium, 256)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.Data(http.StatusOK, "image/png", png)
|
||||
}
|
||||
@@ -1,15 +1,18 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/rostpoliplast/backend/internal/mq"
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/rostpoliplast/backend/internal/storage"
|
||||
)
|
||||
|
||||
type BaleHandlers struct {
|
||||
DB *pgxpool.Pool
|
||||
Repo *storage.Repository
|
||||
MQ *mq.RabbitMQ
|
||||
}
|
||||
|
||||
func (h *BaleHandlers) RegisterRoutes(g *gin.RouterGroup) {
|
||||
@@ -20,22 +23,128 @@ func (h *BaleHandlers) RegisterRoutes(g *gin.RouterGroup) {
|
||||
g.DELETE("/bales/:id", h.DeleteBale)
|
||||
}
|
||||
|
||||
// GetBales Получить список всех тюков
|
||||
// @Summary Получить все тюки
|
||||
// @Description Возвращает список всех тюков
|
||||
// @Tags bales
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {array} storage.Bale
|
||||
// @Router /bales [get]
|
||||
func (h *BaleHandlers) GetBales(c *gin.Context) {
|
||||
c.JSON(200, gin.H{"message": "GetBales"})
|
||||
bales, err := h.Repo.GetBales(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, bales)
|
||||
}
|
||||
|
||||
// GetBaleByID Получить тюк по ID
|
||||
// @Summary Получить тюк по ID
|
||||
// @Description Возвращает тюк по ID
|
||||
// @Tags bales
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "ID тюка"
|
||||
// @Success 200 {object} storage.Bale
|
||||
// @Router /bales/{id} [get]
|
||||
func (h *BaleHandlers) GetBaleByID(c *gin.Context) {
|
||||
c.JSON(200, gin.H{"message": "GetBaleByID"})
|
||||
id := c.Param("id")
|
||||
bale, err := h.Repo.GetBaleByID(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, bale)
|
||||
}
|
||||
|
||||
// CreateBale Создать новый тюк
|
||||
// @Summary Создать тюк
|
||||
// @Description Создаёт новый тюк и отправляет в очередь задач RabbitMQ
|
||||
// @Tags bales
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param bale body storage.Bale false "Данные тюка"
|
||||
// @Param type query string false "Тип тюка (для QR кодов)"
|
||||
// @Success 201 {object} storage.Bale
|
||||
// @Router /bales [post]
|
||||
func (h *BaleHandlers) CreateBale(c *gin.Context) {
|
||||
c.JSON(200, gin.H{"message": "CreateBale"})
|
||||
var input storage.Bale
|
||||
|
||||
if err := c.ShouldBindJSON(&input); err != nil && err.Error() != "EOF" {
|
||||
typeName := c.Query("type")
|
||||
if typeName == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
bt, err := h.Repo.GetBaleTypeByType(c.Request.Context(), typeName)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "type not found"})
|
||||
return
|
||||
}
|
||||
input.TypeID = bt.ID
|
||||
} else if input.TypeID == 0 && c.Query("type") != "" {
|
||||
typeName := c.Query("type")
|
||||
bt, err := h.Repo.GetBaleTypeByType(c.Request.Context(), typeName)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "type not found"})
|
||||
return
|
||||
}
|
||||
input.TypeID = bt.ID
|
||||
}
|
||||
|
||||
bale, err := h.Repo.CreateBale(c.Request.Context(), input)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
if h.MQ != nil {
|
||||
data, _ := json.Marshal(bale)
|
||||
h.MQ.Publish(c.Request.Context(), data)
|
||||
}
|
||||
c.JSON(http.StatusCreated, bale)
|
||||
}
|
||||
|
||||
// UpdateBale Обновить тюк
|
||||
// @Summary Обновить тюк
|
||||
// @Description Обновляет данные тюка по ID
|
||||
// @Tags bales
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "ID тюка"
|
||||
// @Param bale body storage.Bale true "Данные тюка"
|
||||
// @Success 200 {object} storage.Bale
|
||||
// @Router /bales/{id} [put]
|
||||
func (h *BaleHandlers) UpdateBale(c *gin.Context) {
|
||||
c.JSON(200, gin.H{"message": "UpdateBale"})
|
||||
id := c.Param("id")
|
||||
var input storage.Bale
|
||||
if err := c.ShouldBindJSON(&input); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
bale, err := h.Repo.UpdateBale(c.Request.Context(), id, input)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, bale)
|
||||
}
|
||||
|
||||
// DeleteBale Удалить тюк
|
||||
// @Summary Удалить тюк
|
||||
// @Description Удаляет тюк по ID
|
||||
// @Tags bales
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "ID тюка"
|
||||
// @Success 200 {object} map[string]bool
|
||||
// @Router /bales/{id} [delete]
|
||||
func (h *BaleHandlers) DeleteBale(c *gin.Context) {
|
||||
c.JSON(200, gin.H{"message": "DeleteBale"})
|
||||
id := c.Param("id")
|
||||
if err := h.Repo.DeleteBale(c.Request.Context(), id); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"deleted": true})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/rostpoliplast/backend/internal/mq"
|
||||
)
|
||||
|
||||
type QueueHandlers struct {
|
||||
MQ *mq.RabbitMQ
|
||||
}
|
||||
|
||||
func (h *QueueHandlers) RegisterRoutes(g *gin.RouterGroup) {
|
||||
g.GET("/queue/next", h.GetNextTask)
|
||||
}
|
||||
|
||||
// GetNextTask Получить следующую задачу из очереди
|
||||
// @Summary Получить следующую задачу из очереди
|
||||
// @Description Получает и удаляет из очереди следующую задачу (FIFO)
|
||||
// @Tags queue
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} map[string]interface{}
|
||||
// @Success 404 {object} map[string]string
|
||||
// @Router /queue/next [get]
|
||||
func (h *QueueHandlers) GetNextTask(c *gin.Context) {
|
||||
if h.MQ == nil {
|
||||
c.JSON(http.StatusServiceUnavailable, gin.H{"error": "rabbitmq not available"})
|
||||
return
|
||||
}
|
||||
|
||||
data, err := h.MQ.Consume()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "no messages in queue"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"data": string(data),
|
||||
"success": true,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/rostpoliplast/backend/internal/storage"
|
||||
)
|
||||
|
||||
type mockRepo struct {
|
||||
storage.Repository
|
||||
baleTypes []storage.BaleType
|
||||
bales []storage.Bale
|
||||
}
|
||||
|
||||
func (r *mockRepo) GetBaleTypes(ctx context.Context) ([]storage.BaleType, error) {
|
||||
return r.baleTypes, nil
|
||||
}
|
||||
|
||||
func (r *mockRepo) GetBales(ctx context.Context) ([]storage.Bale, error) {
|
||||
return r.bales, nil
|
||||
}
|
||||
|
||||
func TestBaleTypeHandlers_HasRoutes(t *testing.T) {
|
||||
h := &BaleTypeHandlers{}
|
||||
if h == nil {
|
||||
t.Error("BaleTypeHandler is nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBaleHandlers_HasRoutes(t *testing.T) {
|
||||
h := &BaleHandlers{}
|
||||
if h == nil {
|
||||
t.Error("BaleHandler is nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypesFieldMappings(t *testing.T) {
|
||||
bt := storage.BaleType{
|
||||
ID: 1,
|
||||
Type: "test",
|
||||
Weight: 10.0,
|
||||
}
|
||||
if bt.Type != "test" {
|
||||
t.Errorf("expected type 'test', got %s", bt.Type)
|
||||
}
|
||||
if bt.Weight != 10.0 {
|
||||
t.Errorf("expected weight 10.0, got %f", bt.Weight)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBaleFieldMappings(t *testing.T) {
|
||||
b := storage.Bale{
|
||||
ID: 1,
|
||||
TypeID: 1,
|
||||
Type: "standard",
|
||||
}
|
||||
if b.TypeID != 1 {
|
||||
t.Errorf("expected typeId 1, got %d", b.TypeID)
|
||||
}
|
||||
if b.Type != "standard" {
|
||||
t.Errorf("expected type 'standard', got %s", b.Type)
|
||||
}
|
||||
}
|
||||
@@ -2,20 +2,30 @@ package handlers
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/rostpoliplast/backend/internal/mq"
|
||||
"gitea.d3m0k1d.ru/d3m0k1d/rostpoliplast/backend/internal/storage"
|
||||
)
|
||||
|
||||
type Handlers struct {
|
||||
DB *pgxpool.Pool
|
||||
Repo *storage.Repository
|
||||
MQ *mq.RabbitMQ
|
||||
}
|
||||
|
||||
func (h *Handlers) RegisterRoutes(r *gin.RouterGroup) {
|
||||
baleHandlers := &BaleHandlers{
|
||||
DB: h.DB,
|
||||
Repo: h.Repo,
|
||||
MQ: h.MQ,
|
||||
}
|
||||
baleHandlers.RegisterRoutes(r)
|
||||
|
||||
baleTypeHandlers := &BaleTypeHandlers{
|
||||
Repo: h.Repo,
|
||||
}
|
||||
baleTypeHandlers.RegisterRoutes(r)
|
||||
|
||||
queueHandlers := &QueueHandlers{
|
||||
MQ: h.MQ,
|
||||
}
|
||||
queueHandlers.RegisterRoutes(r)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
package mq
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
amqp "github.com/rabbitmq/amqp091-go"
|
||||
)
|
||||
|
||||
type RabbitMQ struct {
|
||||
conn *amqp.Connection
|
||||
channel *amqp.Channel
|
||||
queue amqp.Queue
|
||||
}
|
||||
|
||||
func NewRabbitMQ() (*RabbitMQ, error) {
|
||||
url := os.Getenv("RABBITMQ_URL")
|
||||
if url == "" {
|
||||
url = "amqp://guest:guest@localhost:5672/"
|
||||
}
|
||||
|
||||
conn, err := amqp.Dial(url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to connect to RabbitMQ: %w", err)
|
||||
}
|
||||
|
||||
ch, err := conn.Channel()
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, fmt.Errorf("failed to open channel: %w", err)
|
||||
}
|
||||
|
||||
q, err := ch.QueueDeclare("bales_tasks", true, false, false, false, nil)
|
||||
if err != nil {
|
||||
ch.Close()
|
||||
conn.Close()
|
||||
return nil, fmt.Errorf("failed to declare queue: %w", err)
|
||||
}
|
||||
|
||||
return &RabbitMQ{
|
||||
conn: conn,
|
||||
channel: ch,
|
||||
queue: q,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *RabbitMQ) Publish(ctx context.Context, body []byte) error {
|
||||
return r.channel.PublishWithContext(ctx, "", r.queue.Name, false, false, amqp.Publishing{
|
||||
ContentType: "application/json",
|
||||
Body: body,
|
||||
})
|
||||
}
|
||||
|
||||
func (r *RabbitMQ) Consume() ([]byte, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel()
|
||||
|
||||
msgs, err := r.channel.Consume(r.queue.Name, "", false, false, false, false, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
select {
|
||||
case msg, ok := <-msgs:
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("channel closed")
|
||||
}
|
||||
msg.Ack(false)
|
||||
return msg.Body, nil
|
||||
case <-ctx.Done():
|
||||
return nil, fmt.Errorf("timeout waiting for message")
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RabbitMQ) Close() {
|
||||
if r.channel != nil {
|
||||
r.channel.Close()
|
||||
}
|
||||
if r.conn != nil {
|
||||
r.conn.Close()
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
@@ -13,3 +15,139 @@ func NewRepository(pool *pgxpool.Pool) *Repository {
|
||||
pool: pool,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Repository) GetBales(ctx context.Context) ([]Bale, error) {
|
||||
rows, err := r.pool.Query(ctx, `
|
||||
SELECT b.id, b.type_id, COALESCE(bt.type, ''), b.timestamp
|
||||
FROM bales b
|
||||
LEFT JOIN bale_types bt ON b.type_id = bt.id
|
||||
ORDER BY b.id`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var bales []Bale
|
||||
for rows.Next() {
|
||||
var b Bale
|
||||
if err := rows.Scan(&b.ID, &b.TypeID, &b.Type, &b.Timestamp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bales = append(bales, b)
|
||||
}
|
||||
return bales, nil
|
||||
}
|
||||
|
||||
func (r *Repository) GetBaleByID(ctx context.Context, id string) (*Bale, error) {
|
||||
var b Bale
|
||||
err := r.pool.QueryRow(ctx, `
|
||||
SELECT b.id, b.type_id, COALESCE(bt.type, ''), b.timestamp
|
||||
FROM bales b
|
||||
LEFT JOIN bale_types bt ON b.type_id = bt.id
|
||||
WHERE b.id = $1`, id).Scan(&b.ID, &b.TypeID, &b.Type, &b.Timestamp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &b, nil
|
||||
}
|
||||
|
||||
func (r *Repository) CreateBale(ctx context.Context, input Bale) (*Bale, error) {
|
||||
var b Bale
|
||||
err := r.pool.QueryRow(ctx, `
|
||||
INSERT INTO bales (type_id) VALUES ($1)
|
||||
RETURNING id, type_id, timestamp`, input.TypeID).Scan(&b.ID, &b.TypeID, &b.Timestamp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if input.TypeID > 0 {
|
||||
var bt BaleType
|
||||
r.pool.QueryRow(ctx, "SELECT id, type FROM bale_types WHERE id = $1", b.TypeID).Scan(&bt.ID, &bt.Type)
|
||||
b.Type = bt.Type
|
||||
}
|
||||
return &b, nil
|
||||
}
|
||||
|
||||
func (r *Repository) UpdateBale(ctx context.Context, id string, input Bale) (*Bale, error) {
|
||||
var b Bale
|
||||
err := r.pool.QueryRow(ctx, `
|
||||
UPDATE bales SET type_id = $1 WHERE id = $2
|
||||
RETURNING id, type_id, timestamp`, input.TypeID, id).Scan(&b.ID, &b.TypeID, &b.Timestamp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if input.TypeID > 0 {
|
||||
var bt BaleType
|
||||
r.pool.QueryRow(ctx, "SELECT id, type FROM bale_types WHERE id = $1", b.TypeID).Scan(&bt.ID, &bt.Type)
|
||||
b.Type = bt.Type
|
||||
}
|
||||
return &b, nil
|
||||
}
|
||||
|
||||
func (r *Repository) DeleteBale(ctx context.Context, id string) error {
|
||||
_, err := r.pool.Exec(ctx, "DELETE FROM bales WHERE id = $1", id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *Repository) GetBaleTypes(ctx context.Context) ([]BaleType, error) {
|
||||
rows, err := r.pool.Query(ctx, "SELECT id, type, weight, height, width, length FROM bale_types ORDER BY id")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var types []BaleType
|
||||
for rows.Next() {
|
||||
var bt BaleType
|
||||
if err := rows.Scan(&bt.ID, &bt.Type, &bt.Weight, &bt.Height, &bt.Width, &bt.Length); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
types = append(types, bt)
|
||||
}
|
||||
return types, nil
|
||||
}
|
||||
|
||||
func (r *Repository) GetBaleTypeByID(ctx context.Context, id int) (*BaleType, error) {
|
||||
var bt BaleType
|
||||
err := r.pool.QueryRow(ctx, "SELECT id, type, weight, height, width, length FROM bale_types WHERE id = $1", id).Scan(&bt.ID, &bt.Type, &bt.Weight, &bt.Height, &bt.Width, &bt.Length)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &bt, nil
|
||||
}
|
||||
|
||||
func (r *Repository) GetBaleTypeByType(ctx context.Context, typeName string) (*BaleType, error) {
|
||||
var bt BaleType
|
||||
err := r.pool.QueryRow(ctx, "SELECT id, type, weight, height, width, length FROM bale_types WHERE type = $1", typeName).Scan(&bt.ID, &bt.Type, &bt.Weight, &bt.Height, &bt.Width, &bt.Length)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &bt, nil
|
||||
}
|
||||
|
||||
func (r *Repository) CreateBaleType(ctx context.Context, input BaleType) (*BaleType, error) {
|
||||
var bt BaleType
|
||||
err := r.pool.QueryRow(ctx, `
|
||||
INSERT INTO bale_types (type, weight, height, width, length)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
RETURNING id, type, weight, height, width, length`, input.Type, input.Weight, input.Height, input.Width, input.Length).Scan(&bt.ID, &bt.Type, &bt.Weight, &bt.Height, &bt.Width, &bt.Length)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &bt, nil
|
||||
}
|
||||
|
||||
func (r *Repository) UpdateBaleType(ctx context.Context, id int, input BaleType) (*BaleType, error) {
|
||||
var bt BaleType
|
||||
err := r.pool.QueryRow(ctx, `
|
||||
UPDATE bale_types SET type = $1, weight = $2, height = $3, width = $4, length = $5 WHERE id = $6
|
||||
RETURNING id, type, weight, height, width, length`, input.Type, input.Weight, input.Height, input.Width, input.Length, id).Scan(&bt.ID, &bt.Type, &bt.Weight, &bt.Height, &bt.Width, &bt.Length)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &bt, nil
|
||||
}
|
||||
|
||||
func (r *Repository) DeleteBaleType(ctx context.Context, id int) error {
|
||||
_, err := r.pool.Exec(ctx, "DELETE FROM bale_types WHERE id = $1", id)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package storage
|
||||
|
||||
import "time"
|
||||
|
||||
// BaleType Тип тюка
|
||||
// @Description Тип тюка - характеристики тюка
|
||||
type BaleType struct {
|
||||
ID int `json:"id"`
|
||||
Type string `json:"type"`
|
||||
@@ -9,10 +13,13 @@ type BaleType struct {
|
||||
Length float64 `json:"length"`
|
||||
}
|
||||
|
||||
// Bale Тюк
|
||||
// @Description Тюк - единица готовой продукции
|
||||
type Bale struct {
|
||||
ID int `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
ID int `json:"id"`
|
||||
TypeID int `json:"typeId"`
|
||||
Type string `json:"type"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
CREATE TABLE IF NOT EXISTS bales (
|
||||
id SERIAL PRIMARY KEY,
|
||||
type_id INTEGER,
|
||||
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose StatementBegin
|
||||
CREATE INDEX IF NOT EXISTS idx_bales_timestamp ON bales(timestamp);
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose Down
|
||||
-- +goose StatementBegin
|
||||
DROP TABLE IF EXISTS bales;
|
||||
-- +goose StatementEnd
|
||||
@@ -0,0 +1,28 @@
|
||||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
CREATE TABLE IF NOT EXISTS bale_types (
|
||||
id SERIAL PRIMARY KEY,
|
||||
type VARCHAR(255) NOT NULL,
|
||||
weight DECIMAL(10,2),
|
||||
height DECIMAL(10,2),
|
||||
width DECIMAL(10,2),
|
||||
length DECIMAL(10,2)
|
||||
);
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose StatementBegin
|
||||
ALTER TABLE bales ADD COLUMN IF NOT EXISTS type_id INTEGER REFERENCES bale_types(id);
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose StatementBegin
|
||||
CREATE INDEX IF NOT EXISTS idx_bales_type_id ON bales(type_id);
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose Down
|
||||
-- +goose StatementBegin
|
||||
ALTER TABLE bales DROP COLUMN IF NOT EXISTS type_id;
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose StatementBegin
|
||||
DROP TABLE IF EXISTS bale_types;
|
||||
-- +goose StatementEnd
|
||||
Reference in New Issue
Block a user