From 6e8750a566c42dcb64d78dd921688dde544d923f Mon Sep 17 00:00:00 2001 From: anxi0uz Date: Mon, 23 Mar 2026 18:28:01 +0500 Subject: [PATCH] added manager, driver, order, route, vehicle, warehouse endpoints,models and migrations. --- go.mod | 1 + go.sum | 6 + internal/api/api.swagger.yaml | 1019 +++++++++++-- internal/api/gen.go | 1272 ++++++++++++++++- internal/handler/driver.go | 13 + internal/handler/manager.go | 11 + internal/handler/order.go | 17 + internal/handler/route.go | 11 + internal/handler/user.go | 4 +- internal/handler/vehicle.go | 13 + internal/handler/warehouse.go | 13 + internal/models/driver.go | 18 + internal/models/manager.go | 10 + internal/models/order.go | 25 + internal/models/route.go | 33 + internal/models/vehicle.go | 15 + internal/models/warehouse.go | 19 + migrations/20260303130413_create_user.sql | 1 + migrations/20260303130430_create_order.sql | 20 +- migrations/20260322074231_create_manager.sql | 14 + .../20260322080115_create_warehouse.sql | 19 + migrations/20260323124352_create_routes.sql | 20 + 22 files changed, 2463 insertions(+), 111 deletions(-) create mode 100644 internal/handler/driver.go create mode 100644 internal/handler/manager.go create mode 100644 internal/handler/order.go create mode 100644 internal/handler/route.go create mode 100644 internal/handler/vehicle.go create mode 100644 internal/handler/warehouse.go create mode 100644 internal/models/driver.go create mode 100644 internal/models/manager.go create mode 100644 internal/models/order.go create mode 100644 internal/models/route.go create mode 100644 internal/models/vehicle.go create mode 100644 internal/models/warehouse.go create mode 100644 migrations/20260322074231_create_manager.sql create mode 100644 migrations/20260322080115_create_warehouse.sql create mode 100644 migrations/20260323124352_create_routes.sql diff --git a/go.mod b/go.mod index 11ac763..c5d7d86 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,7 @@ require ( ) require ( + github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect diff --git a/go.sum b/go.sum index c8a0e13..7aa4e93 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,7 @@ +github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= +github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= +github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= +github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= @@ -50,6 +54,7 @@ github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= @@ -90,6 +95,7 @@ github.com/samber/slog-chi v1.19.0 h1:fl4qH5Hhk7feHtyp4CxJUt7U1TqjPrZ1uueDW9D+Cp github.com/samber/slog-chi v1.19.0/go.mod h1:a1iIuofF2gS1ii8aXIQhC6TEguLOhOvSM958fY5hToU= github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE= github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas= +github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= diff --git a/internal/api/api.swagger.yaml b/internal/api/api.swagger.yaml index b1ddc82..4def1fa 100644 --- a/internal/api/api.swagger.yaml +++ b/internal/api/api.swagger.yaml @@ -2,7 +2,7 @@ openapi: 3.0.3 info: title: Logiflow API description: API для логистической информационной системы - version: 0.1.0 + version: 0.2.0 contact: name: anxi0uz @@ -10,6 +10,9 @@ servers: - url: http://localhost:3001 description: Local development +security: + - BearerAuth: [] + components: securitySchemes: BearerAuth: @@ -18,6 +21,8 @@ components: bearerFormat: JWT schemas: + # ─── Common ─────────────────────────────────────────────────────────────── + ApiResponse: type: object properties: @@ -44,57 +49,7 @@ components: requestID: type: string - User: - type: object - properties: - id: - type: string - format: uuid - email: - type: string - format: email - slug: - type: string - fullName: - type: string - nullable: true - avatarUrl: - type: string - nullable: true - passwordHash: - type: string - createdAt: - type: string - format: date-time - updatedAt: - type: string - format: date-time - nullable: true - lastLoginAt: - type: string - format: date-time - nullable: true - - UserResponse: - type: object - properties: - id: - type: string - format: uuid - email: - type: string - format: email - slug: - type: string - fullName: - type: string - nullable: true - avatarUrl: - type: string - nullable: true - createdAt: - type: string - format: date-time + # ─── Auth ───────────────────────────────────────────────────────────────── RegisterRequest: type: object @@ -128,21 +83,50 @@ components: properties: refreshToken: type: string - description: Refresh токен, полученный при логине TokenResponse: type: object - required: [accessToken, refreshToken] properties: accessToken: type: string - description: Access токен (JWT) refreshToken: type: string - description: Refresh токен (opaque token, rotation) expiresIn: type: integer - description: Время жизни access токена в секундах + + # ─── User ───────────────────────────────────────────────────────────────── + + User: + type: object + properties: + id: + type: string + format: uuid + email: + type: string + format: email + slug: + type: string + fullName: + type: string + nullable: true + avatarUrl: + type: string + nullable: true + role: + type: string + enum: [admin, manager, driver, client] + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + nullable: true + lastLoginAt: + type: string + format: date-time + nullable: true UserUpdate: type: object @@ -159,11 +143,11 @@ components: password: type: string minLength: 8 - description: Новый пароль (если меняется) + nullable: true currentPassword: type: string minLength: 8 - description: Текущий пароль (обязателен при смене пароля) + nullable: true UserDeleteRequest: type: object @@ -171,14 +155,409 @@ components: properties: password: type: string - description: Текущий пароль для подтверждения удаления + + # ─── Vehicle ────────────────────────────────────────────────────────────── + + Vehicle: + type: object + properties: + id: + type: string + format: uuid + plateNumber: + type: string + brand: + type: string + nullable: true + model: + type: string + nullable: true + year: + type: integer + nullable: true + capacityKg: + type: number + nullable: true + capacityM3: + type: number + nullable: true + status: + type: string + enum: [available, in_transit, maintenance] + slug: + type: string + + VehicleCreate: + type: object + required: [plateNumber] + properties: + plateNumber: + type: string + brand: + type: string + nullable: true + model: + type: string + nullable: true + year: + type: integer + nullable: true + capacityKg: + type: number + nullable: true + capacityM3: + type: number + nullable: true + + VehicleUpdate: + type: object + properties: + brand: + type: string + nullable: true + model: + type: string + nullable: true + year: + type: integer + nullable: true + capacityKg: + type: number + nullable: true + capacityM3: + type: number + nullable: true + status: + type: string + enum: [available, in_transit, maintenance] + nullable: true + + # ─── Warehouse ──────────────────────────────────────────────────────────── + + Warehouse: + type: object + properties: + id: + type: string + format: uuid + slug: + type: string + name: + type: string + address: + type: string + city: + type: string + nullable: true + latitude: + type: number + nullable: true + longitude: + type: number + nullable: true + status: + type: string + enum: [active, inactive] + createdAt: + type: string + format: date-time + + WarehouseCreate: + type: object + required: [name, address] + properties: + name: + type: string + address: + type: string + city: + type: string + nullable: true + latitude: + type: number + nullable: true + longitude: + type: number + nullable: true + + WarehouseUpdate: + type: object + properties: + name: + type: string + nullable: true + address: + type: string + nullable: true + city: + type: string + nullable: true + latitude: + type: number + nullable: true + longitude: + type: number + nullable: true + status: + type: string + enum: [active, inactive] + nullable: true + + # ─── Manager ────────────────────────────────────────────────────────────── + + Manager: + type: object + properties: + id: + type: string + format: uuid + userId: + type: string + format: uuid + warehouseId: + type: string + format: uuid + nullable: true + slug: + type: string + + ManagerCreate: + type: object + required: [userId] + properties: + userId: + type: string + format: uuid + warehouseId: + type: string + format: uuid + nullable: true + + # ─── Driver ─────────────────────────────────────────────────────────────── + + Driver: + type: object + properties: + id: + type: string + format: uuid + userId: + type: string + format: uuid + vehicleId: + type: string + format: uuid + nullable: true + licenseNumber: + type: string + licenseExpiry: + type: string + format: date + rating: + type: number + slug: + type: string + status: + type: string + enum: [available, on_route, off_duty] + + DriverCreate: + type: object + required: [userId, licenseNumber, licenseExpiry] + properties: + userId: + type: string + format: uuid + vehicleId: + type: string + format: uuid + nullable: true + licenseNumber: + type: string + licenseExpiry: + type: string + format: date + + DriverUpdate: + type: object + properties: + vehicleId: + type: string + format: uuid + nullable: true + licenseNumber: + type: string + nullable: true + licenseExpiry: + type: string + format: date + nullable: true + status: + type: string + enum: [available, on_route, off_duty] + nullable: true + + # ─── Order ──────────────────────────────────────────────────────────────── + + Order: + type: object + properties: + id: + type: string + format: uuid + createdById: + type: string + format: uuid + nullable: true + driverId: + type: string + format: uuid + nullable: true + managerId: + type: string + format: uuid + nullable: true + originWarehouseId: + type: string + format: uuid + nullable: true + originAddress: + type: string + nullable: true + destinationAddress: + type: string + cargoDescription: + type: string + nullable: true + weightKg: + type: number + nullable: true + volumeM3: + type: number + nullable: true + status: + type: string + enum: [pending, assigned, in_transit, delivered, cancelled] + totalPrice: + type: number + nullable: true + createdAt: + type: string + format: date-time + assignedAt: + type: string + format: date-time + nullable: true + deliveredAt: + type: string + format: date-time + nullable: true + + OrderCreate: + type: object + required: [destinationAddress] + properties: + originWarehouseId: + type: string + format: uuid + nullable: true + originAddress: + type: string + nullable: true + destinationAddress: + type: string + cargoDescription: + type: string + nullable: true + weightKg: + type: number + nullable: true + volumeM3: + type: number + nullable: true + + OrderStatusUpdate: + type: object + required: [status] + properties: + status: + type: string + enum: [assigned, in_transit, delivered, cancelled] + driverId: + type: string + format: uuid + nullable: true + + # ─── Route ──────────────────────────────────────────────────────────────── + + Coordinate: + type: array + items: + type: number + minItems: 2 + maxItems: 2 + description: "[longitude, latitude] — ORS format" + + Route: + type: object + properties: + id: + type: string + format: uuid + orderId: + type: string + format: uuid + driverId: + type: string + format: uuid + nullable: true + coordinates: + type: array + items: + $ref: "#/components/schemas/Coordinate" + description: Массив координат маршрута от ORS + currentIndex: + type: integer + description: Текущая позиция водителя в массиве координат + startedAt: + type: string + format: date-time + nullable: true + finishedAt: + type: string + format: date-time + nullable: true + distanceKm: + type: number + nullable: true + durationSec: + type: integer + nullable: true + status: + type: string + enum: [pending, active, finished] + + RoutePosition: + type: object + description: Сообщение WebSocket — текущая позиция водителя + properties: + currentIndex: + type: integer + coordinate: + $ref: "#/components/schemas/Coordinate" + status: + type: string + enum: [active, finished] paths: + # ─── Auth ─────────────────────────────────────────────────────────────────── + /auth/register: post: operationId: authRegister summary: Регистрация нового пользователя tags: [Auth] + security: [] requestBody: required: true content: @@ -186,8 +565,8 @@ paths: schema: $ref: "#/components/schemas/RegisterRequest" responses: - "201": - description: Пользователь успешно создан + "200": + description: Пользователь создан, токены выданы content: application/json: schema: @@ -208,8 +587,9 @@ paths: /auth/login: post: operationId: authLogin - summary: Авторизация пользователя + summary: Авторизация tags: [Auth] + security: [] requestBody: required: true content: @@ -233,29 +613,22 @@ paths: /auth/refresh: post: operationId: authRefresh - summary: Обновление access-токена через refresh-токен + summary: Обновление access-токена tags: [Auth] - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/TokenRefreshRequest" + security: [] responses: "200": - description: Токены успешно обновлены + description: Токены обновлены content: application/json: schema: $ref: "#/components/schemas/ApiResponse" "401": - description: Недействительный или истёкший refresh-токен + description: Недействительный refresh-токен content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" - "400": - description: Некорректный запрос /auth/logout: post: @@ -263,15 +636,17 @@ paths: summary: Выход из системы tags: [Auth] responses: - "204": + "200": description: Успешный выход "401": description: Не авторизован + # ─── Me ───────────────────────────────────────────────────────────────────── + /me: get: operationId: getMe - summary: Получить текущего пользователя + summary: Текущий пользователь tags: [Me] responses: "200": @@ -285,7 +660,7 @@ paths: patch: operationId: updateMe - summary: Обновить данные текущего пользователя + summary: Обновить профиль tags: [Me] requestBody: required: true @@ -295,7 +670,7 @@ paths: $ref: "#/components/schemas/UserUpdate" responses: "200": - description: Пользователь обновлён + description: Профиль обновлён content: application/json: schema: @@ -308,10 +683,6 @@ paths: $ref: "#/components/schemas/ErrorResponse" "401": description: Не авторизован - content: - application/json: - schema: - $ref: "#/components/schemas/ErrorResponse" delete: operationId: deleteMe @@ -324,7 +695,7 @@ paths: schema: $ref: "#/components/schemas/UserDeleteRequest" responses: - "204": + "200": description: Аккаунт удалён "400": description: Неверный пароль @@ -334,7 +705,489 @@ paths: $ref: "#/components/schemas/ErrorResponse" "401": description: Не авторизован + + # ─── Vehicles ─────────────────────────────────────────────────────────────── + + /vehicles: + get: + operationId: listVehicles + summary: Список транспортных средств + tags: [Vehicles] + responses: + "200": + description: Список ТС + content: + application/json: + schema: + $ref: "#/components/schemas/ApiResponse" + "401": + description: Не авторизован + + post: + operationId: createVehicle + summary: Добавить ТС + tags: [Vehicles] + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/VehicleCreate" + responses: + "200": + description: ТС создано + content: + application/json: + schema: + $ref: "#/components/schemas/ApiResponse" + "400": + description: Некорректные данные content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" + + /vehicles/{slug}: + parameters: + - name: slug + in: path + required: true + schema: + type: string + + get: + operationId: getVehicle + summary: Получить ТС по slug + tags: [Vehicles] + responses: + "200": + description: Данные ТС + content: + application/json: + schema: + $ref: "#/components/schemas/ApiResponse" + "404": + description: Не найдено + + put: + operationId: updateVehicle + summary: Обновить ТС + tags: [Vehicles] + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/VehicleUpdate" + responses: + "200": + description: ТС обновлено + content: + application/json: + schema: + $ref: "#/components/schemas/ApiResponse" + "404": + description: Не найдено + + delete: + operationId: deleteVehicle + summary: Удалить ТС + tags: [Vehicles] + responses: + "200": + description: ТС удалено + "404": + description: Не найдено + + # ─── Warehouses ───────────────────────────────────────────────────────────── + + /warehouses: + get: + operationId: listWarehouses + summary: Список складов + tags: [Warehouses] + responses: + "200": + description: Список складов + content: + application/json: + schema: + $ref: "#/components/schemas/ApiResponse" + + post: + operationId: createWarehouse + summary: Создать склад + tags: [Warehouses] + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/WarehouseCreate" + responses: + "200": + description: Склад создан + content: + application/json: + schema: + $ref: "#/components/schemas/ApiResponse" + "400": + description: Некорректные данные + + /warehouses/{slug}: + parameters: + - name: slug + in: path + required: true + schema: + type: string + + get: + operationId: getWarehouse + summary: Получить склад по slug + tags: [Warehouses] + responses: + "200": + description: Данные склада + content: + application/json: + schema: + $ref: "#/components/schemas/ApiResponse" + "404": + description: Не найдено + + put: + operationId: updateWarehouse + summary: Обновить склад + tags: [Warehouses] + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/WarehouseUpdate" + responses: + "200": + description: Склад обновлён + content: + application/json: + schema: + $ref: "#/components/schemas/ApiResponse" + + delete: + operationId: deleteWarehouse + summary: Удалить склад + tags: [Warehouses] + responses: + "200": + description: Склад удалён + + # ─── Managers ─────────────────────────────────────────────────────────────── + + /managers: + get: + operationId: listManagers + summary: Список менеджеров + tags: [Managers] + responses: + "200": + description: Список менеджеров + content: + application/json: + schema: + $ref: "#/components/schemas/ApiResponse" + + post: + operationId: createManager + summary: Назначить менеджера + tags: [Managers] + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/ManagerCreate" + responses: + "200": + description: Менеджер создан + content: + application/json: + schema: + $ref: "#/components/schemas/ApiResponse" + "400": + description: Некорректные данные + + /managers/{slug}: + parameters: + - name: slug + in: path + required: true + schema: + type: string + + get: + operationId: getManager + summary: Получить менеджера по slug + tags: [Managers] + responses: + "200": + description: Данные менеджера + content: + application/json: + schema: + $ref: "#/components/schemas/ApiResponse" + "404": + description: Не найдено + + delete: + operationId: deleteManager + summary: Удалить менеджера + tags: [Managers] + responses: + "200": + description: Менеджер удалён + + # ─── Drivers ──────────────────────────────────────────────────────────────── + + /drivers: + get: + operationId: listDrivers + summary: Список водителей + tags: [Drivers] + responses: + "200": + description: Список водителей + content: + application/json: + schema: + $ref: "#/components/schemas/ApiResponse" + + post: + operationId: createDriver + summary: Зарегистрировать водителя + tags: [Drivers] + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/DriverCreate" + responses: + "200": + description: Водитель создан + content: + application/json: + schema: + $ref: "#/components/schemas/ApiResponse" + "400": + description: Некорректные данные + + /drivers/{slug}: + parameters: + - name: slug + in: path + required: true + schema: + type: string + + get: + operationId: getDriver + summary: Получить водителя по slug + tags: [Drivers] + responses: + "200": + description: Данные водителя + content: + application/json: + schema: + $ref: "#/components/schemas/ApiResponse" + "404": + description: Не найдено + + put: + operationId: updateDriver + summary: Обновить данные водителя + tags: [Drivers] + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/DriverUpdate" + responses: + "200": + description: Данные обновлены + content: + application/json: + schema: + $ref: "#/components/schemas/ApiResponse" + + delete: + operationId: deleteDriver + summary: Удалить водителя + tags: [Drivers] + responses: + "200": + description: Водитель удалён + + # ─── Orders ───────────────────────────────────────────────────────────────── + + /orders: + get: + operationId: listOrders + summary: Список заявок + tags: [Orders] + description: > + Клиент видит только свои заявки, менеджер — заявки своего склада, + водитель — назначенные на него, администратор — все. + responses: + "200": + description: Список заявок + content: + application/json: + schema: + $ref: "#/components/schemas/ApiResponse" + + post: + operationId: createOrder + summary: Создать заявку + tags: [Orders] + description: > + Создаёт заявку и запрашивает маршрут в OpenRouteService по адресам. + Координаты сохраняются в таблице routes. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/OrderCreate" + responses: + "200": + description: Заявка создана + content: + application/json: + schema: + $ref: "#/components/schemas/ApiResponse" + "400": + description: Некорректные данные или ORS недоступен + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + + /orders/{id}: + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + + get: + operationId: getOrder + summary: Получить заявку + tags: [Orders] + responses: + "200": + description: Данные заявки + content: + application/json: + schema: + $ref: "#/components/schemas/ApiResponse" + "404": + description: Не найдено + + delete: + operationId: cancelOrder + summary: Отменить заявку + tags: [Orders] + description: Доступно только для статуса pending. + responses: + "200": + description: Заявка отменена + "400": + description: Нельзя отменить заявку в текущем статусе + "403": + description: Нет доступа + + /orders/{id}/status: + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + + patch: + operationId: updateOrderStatus + summary: Обновить статус заявки + tags: [Orders] + description: Менеджер назначает водителя (assigned), водитель обновляет (in_transit / delivered). + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/OrderStatusUpdate" + responses: + "200": + description: Статус обновлён + content: + application/json: + schema: + $ref: "#/components/schemas/ApiResponse" + "400": + description: Недопустимый переход статуса + "403": + description: Нет доступа + + # ─── Routes ───────────────────────────────────────────────────────────────── + + /orders/{id}/route: + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + + get: + operationId: getRoute + summary: Получить маршрут заявки + tags: [Routes] + description: Возвращает весь маршрут с координатами и текущим индексом. + responses: + "200": + description: Данные маршрута + content: + application/json: + schema: + $ref: "#/components/schemas/ApiResponse" + "404": + description: Маршрут не найден + + /orders/{id}/route/ws: + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + + get: + operationId: routeWebSocket + summary: WebSocket трекинг маршрута + tags: [Routes] + description: > + Upgrades to WebSocket. Сервер отправляет RoutePosition каждые N секунд, + двигая current_index по массиву координат в горутине. + Соединение закрывается когда статус маршрута становится finished. + responses: + "101": + description: Switching Protocols — WebSocket установлен + "404": + description: Маршрут не найден diff --git a/internal/api/gen.go b/internal/api/gen.go index 06f9284..557c311 100644 --- a/internal/api/gen.go +++ b/internal/api/gen.go @@ -4,13 +4,64 @@ package api import ( + "context" "fmt" "net/http" "github.com/go-chi/chi/v5" + "github.com/oapi-codegen/runtime" openapi_types "github.com/oapi-codegen/runtime/types" ) +const ( + BearerAuthScopes = "BearerAuth.Scopes" +) + +// Defines values for DriverUpdateStatus. +const ( + DriverUpdateStatusAvailable DriverUpdateStatus = "available" + DriverUpdateStatusOffDuty DriverUpdateStatus = "off_duty" + DriverUpdateStatusOnRoute DriverUpdateStatus = "on_route" +) + +// Valid indicates whether the value is a known member of the DriverUpdateStatus enum. +func (e DriverUpdateStatus) Valid() bool { + switch e { + case DriverUpdateStatusAvailable: + return true + case DriverUpdateStatusOffDuty: + return true + case DriverUpdateStatusOnRoute: + return true + default: + return false + } +} + +// Defines values for OrderStatusUpdateStatus. +const ( + Assigned OrderStatusUpdateStatus = "assigned" + Cancelled OrderStatusUpdateStatus = "cancelled" + Delivered OrderStatusUpdateStatus = "delivered" + InTransit OrderStatusUpdateStatus = "in_transit" +) + +// Valid indicates whether the value is a known member of the OrderStatusUpdateStatus enum. +func (e OrderStatusUpdateStatus) Valid() bool { + switch e { + case Assigned: + return true + case Cancelled: + return true + case Delivered: + return true + case InTransit: + return true + default: + return false + } +} + // Defines values for RegisterRequestRole. const ( Admin RegisterRequestRole = "admin" @@ -35,6 +86,45 @@ func (e RegisterRequestRole) Valid() bool { } } +// Defines values for VehicleUpdateStatus. +const ( + VehicleUpdateStatusAvailable VehicleUpdateStatus = "available" + VehicleUpdateStatusInTransit VehicleUpdateStatus = "in_transit" + VehicleUpdateStatusMaintenance VehicleUpdateStatus = "maintenance" +) + +// Valid indicates whether the value is a known member of the VehicleUpdateStatus enum. +func (e VehicleUpdateStatus) Valid() bool { + switch e { + case VehicleUpdateStatusAvailable: + return true + case VehicleUpdateStatusInTransit: + return true + case VehicleUpdateStatusMaintenance: + return true + default: + return false + } +} + +// Defines values for WarehouseUpdateStatus. +const ( + Active WarehouseUpdateStatus = "active" + Inactive WarehouseUpdateStatus = "inactive" +) + +// Valid indicates whether the value is a known member of the WarehouseUpdateStatus enum. +func (e WarehouseUpdateStatus) Valid() bool { + switch e { + case Active: + return true + case Inactive: + return true + default: + return false + } +} + // ApiResponse defines model for ApiResponse. type ApiResponse struct { Data *map[string]interface{} `json:"data,omitempty"` @@ -43,6 +133,25 @@ type ApiResponse struct { Success *bool `json:"success,omitempty"` } +// DriverCreate defines model for DriverCreate. +type DriverCreate struct { + LicenseExpiry openapi_types.Date `json:"licenseExpiry"` + LicenseNumber string `json:"licenseNumber"` + UserId openapi_types.UUID `json:"userId"` + VehicleId *openapi_types.UUID `json:"vehicleId,omitempty"` +} + +// DriverUpdate defines model for DriverUpdate. +type DriverUpdate struct { + LicenseExpiry *openapi_types.Date `json:"licenseExpiry,omitempty"` + LicenseNumber *string `json:"licenseNumber,omitempty"` + Status *DriverUpdateStatus `json:"status,omitempty"` + VehicleId *openapi_types.UUID `json:"vehicleId,omitempty"` +} + +// DriverUpdateStatus defines model for DriverUpdate.Status. +type DriverUpdateStatus string + // ErrorResponse defines model for ErrorResponse. type ErrorResponse struct { Message *string `json:"message,omitempty"` @@ -56,6 +165,31 @@ type LoginRequest struct { Password string `json:"password"` } +// ManagerCreate defines model for ManagerCreate. +type ManagerCreate struct { + UserId openapi_types.UUID `json:"userId"` + WarehouseId *openapi_types.UUID `json:"warehouseId,omitempty"` +} + +// OrderCreate defines model for OrderCreate. +type OrderCreate struct { + CargoDescription *string `json:"cargoDescription,omitempty"` + DestinationAddress string `json:"destinationAddress"` + OriginAddress *string `json:"originAddress,omitempty"` + OriginWarehouseId *openapi_types.UUID `json:"originWarehouseId,omitempty"` + VolumeM3 *float32 `json:"volumeM3,omitempty"` + WeightKg *float32 `json:"weightKg,omitempty"` +} + +// OrderStatusUpdate defines model for OrderStatusUpdate. +type OrderStatusUpdate struct { + DriverId *openapi_types.UUID `json:"driverId,omitempty"` + Status OrderStatusUpdateStatus `json:"status"` +} + +// OrderStatusUpdateStatus defines model for OrderStatusUpdate.Status. +type OrderStatusUpdateStatus string + // RegisterRequest defines model for RegisterRequest. type RegisterRequest struct { Email openapi_types.Email `json:"email"` @@ -67,75 +201,211 @@ type RegisterRequest struct { // RegisterRequestRole defines model for RegisterRequest.Role. type RegisterRequestRole string -// TokenRefreshRequest defines model for TokenRefreshRequest. -type TokenRefreshRequest struct { - // RefreshToken Refresh токен, полученный при логине - RefreshToken string `json:"refreshToken"` -} - // UserDeleteRequest defines model for UserDeleteRequest. type UserDeleteRequest struct { - // Password Текущий пароль для подтверждения удаления Password string `json:"password"` } // UserUpdate defines model for UserUpdate. type UserUpdate struct { - AvatarUrl *string `json:"avatarUrl,omitempty"` - - // CurrentPassword Текущий пароль (обязателен при смене пароля) + AvatarUrl *string `json:"avatarUrl,omitempty"` CurrentPassword *string `json:"currentPassword,omitempty"` FullName *string `json:"fullName,omitempty"` - - // Password Новый пароль (если меняется) - Password *string `json:"password,omitempty"` + Password *string `json:"password,omitempty"` } +// VehicleCreate defines model for VehicleCreate. +type VehicleCreate struct { + Brand *string `json:"brand,omitempty"` + CapacityKg *float32 `json:"capacityKg,omitempty"` + CapacityM3 *float32 `json:"capacityM3,omitempty"` + Model *string `json:"model,omitempty"` + PlateNumber string `json:"plateNumber"` + Year *int `json:"year,omitempty"` +} + +// VehicleUpdate defines model for VehicleUpdate. +type VehicleUpdate struct { + Brand *string `json:"brand,omitempty"` + CapacityKg *float32 `json:"capacityKg,omitempty"` + CapacityM3 *float32 `json:"capacityM3,omitempty"` + Model *string `json:"model,omitempty"` + Status *VehicleUpdateStatus `json:"status,omitempty"` + Year *int `json:"year,omitempty"` +} + +// VehicleUpdateStatus defines model for VehicleUpdate.Status. +type VehicleUpdateStatus string + +// WarehouseCreate defines model for WarehouseCreate. +type WarehouseCreate struct { + Address string `json:"address"` + City *string `json:"city,omitempty"` + Latitude *float32 `json:"latitude,omitempty"` + Longitude *float32 `json:"longitude,omitempty"` + Name string `json:"name"` +} + +// WarehouseUpdate defines model for WarehouseUpdate. +type WarehouseUpdate struct { + Address *string `json:"address,omitempty"` + City *string `json:"city,omitempty"` + Latitude *float32 `json:"latitude,omitempty"` + Longitude *float32 `json:"longitude,omitempty"` + Name *string `json:"name,omitempty"` + Status *WarehouseUpdateStatus `json:"status,omitempty"` +} + +// WarehouseUpdateStatus defines model for WarehouseUpdate.Status. +type WarehouseUpdateStatus string + // AuthLoginJSONRequestBody defines body for AuthLogin for application/json ContentType. type AuthLoginJSONRequestBody = LoginRequest -// AuthRefreshJSONRequestBody defines body for AuthRefresh for application/json ContentType. -type AuthRefreshJSONRequestBody = TokenRefreshRequest - // AuthRegisterJSONRequestBody defines body for AuthRegister for application/json ContentType. type AuthRegisterJSONRequestBody = RegisterRequest +// CreateDriverJSONRequestBody defines body for CreateDriver for application/json ContentType. +type CreateDriverJSONRequestBody = DriverCreate + +// UpdateDriverJSONRequestBody defines body for UpdateDriver for application/json ContentType. +type UpdateDriverJSONRequestBody = DriverUpdate + +// CreateManagerJSONRequestBody defines body for CreateManager for application/json ContentType. +type CreateManagerJSONRequestBody = ManagerCreate + // DeleteMeJSONRequestBody defines body for DeleteMe for application/json ContentType. type DeleteMeJSONRequestBody = UserDeleteRequest // UpdateMeJSONRequestBody defines body for UpdateMe for application/json ContentType. type UpdateMeJSONRequestBody = UserUpdate +// CreateOrderJSONRequestBody defines body for CreateOrder for application/json ContentType. +type CreateOrderJSONRequestBody = OrderCreate + +// UpdateOrderStatusJSONRequestBody defines body for UpdateOrderStatus for application/json ContentType. +type UpdateOrderStatusJSONRequestBody = OrderStatusUpdate + +// CreateVehicleJSONRequestBody defines body for CreateVehicle for application/json ContentType. +type CreateVehicleJSONRequestBody = VehicleCreate + +// UpdateVehicleJSONRequestBody defines body for UpdateVehicle for application/json ContentType. +type UpdateVehicleJSONRequestBody = VehicleUpdate + +// CreateWarehouseJSONRequestBody defines body for CreateWarehouse for application/json ContentType. +type CreateWarehouseJSONRequestBody = WarehouseCreate + +// UpdateWarehouseJSONRequestBody defines body for UpdateWarehouse for application/json ContentType. +type UpdateWarehouseJSONRequestBody = WarehouseUpdate + // ServerInterface represents all server handlers. type ServerInterface interface { - // Авторизация пользователя + // Авторизация // (POST /auth/login) AuthLogin(w http.ResponseWriter, r *http.Request) // Выход из системы // (POST /auth/logout) AuthLogout(w http.ResponseWriter, r *http.Request) - // Обновление access-токена через refresh-токен + // Обновление access-токена // (POST /auth/refresh) AuthRefresh(w http.ResponseWriter, r *http.Request) // Регистрация нового пользователя // (POST /auth/register) AuthRegister(w http.ResponseWriter, r *http.Request) + // Список водителей + // (GET /drivers) + ListDrivers(w http.ResponseWriter, r *http.Request) + // Зарегистрировать водителя + // (POST /drivers) + CreateDriver(w http.ResponseWriter, r *http.Request) + // Удалить водителя + // (DELETE /drivers/{slug}) + DeleteDriver(w http.ResponseWriter, r *http.Request, slug string) + // Получить водителя по slug + // (GET /drivers/{slug}) + GetDriver(w http.ResponseWriter, r *http.Request, slug string) + // Обновить данные водителя + // (PUT /drivers/{slug}) + UpdateDriver(w http.ResponseWriter, r *http.Request, slug string) + // Список менеджеров + // (GET /managers) + ListManagers(w http.ResponseWriter, r *http.Request) + // Назначить менеджера + // (POST /managers) + CreateManager(w http.ResponseWriter, r *http.Request) + // Удалить менеджера + // (DELETE /managers/{slug}) + DeleteManager(w http.ResponseWriter, r *http.Request, slug string) + // Получить менеджера по slug + // (GET /managers/{slug}) + GetManager(w http.ResponseWriter, r *http.Request, slug string) // Удалить аккаунт // (DELETE /me) DeleteMe(w http.ResponseWriter, r *http.Request) - // Получить текущего пользователя + // Текущий пользователь // (GET /me) GetMe(w http.ResponseWriter, r *http.Request) - // Обновить данные текущего пользователя + // Обновить профиль // (PATCH /me) UpdateMe(w http.ResponseWriter, r *http.Request) + // Список заявок + // (GET /orders) + ListOrders(w http.ResponseWriter, r *http.Request) + // Создать заявку + // (POST /orders) + CreateOrder(w http.ResponseWriter, r *http.Request) + // Отменить заявку + // (DELETE /orders/{id}) + CancelOrder(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) + // Получить заявку + // (GET /orders/{id}) + GetOrder(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) + // Получить маршрут заявки + // (GET /orders/{id}/route) + GetRoute(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) + // WebSocket трекинг маршрута + // (GET /orders/{id}/route/ws) + RouteWebSocket(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) + // Обновить статус заявки + // (PATCH /orders/{id}/status) + UpdateOrderStatus(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) + // Список транспортных средств + // (GET /vehicles) + ListVehicles(w http.ResponseWriter, r *http.Request) + // Добавить ТС + // (POST /vehicles) + CreateVehicle(w http.ResponseWriter, r *http.Request) + // Удалить ТС + // (DELETE /vehicles/{slug}) + DeleteVehicle(w http.ResponseWriter, r *http.Request, slug string) + // Получить ТС по slug + // (GET /vehicles/{slug}) + GetVehicle(w http.ResponseWriter, r *http.Request, slug string) + // Обновить ТС + // (PUT /vehicles/{slug}) + UpdateVehicle(w http.ResponseWriter, r *http.Request, slug string) + // Список складов + // (GET /warehouses) + ListWarehouses(w http.ResponseWriter, r *http.Request) + // Создать склад + // (POST /warehouses) + CreateWarehouse(w http.ResponseWriter, r *http.Request) + // Удалить склад + // (DELETE /warehouses/{slug}) + DeleteWarehouse(w http.ResponseWriter, r *http.Request, slug string) + // Получить склад по slug + // (GET /warehouses/{slug}) + GetWarehouse(w http.ResponseWriter, r *http.Request, slug string) + // Обновить склад + // (PUT /warehouses/{slug}) + UpdateWarehouse(w http.ResponseWriter, r *http.Request, slug string) } // Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint. type Unimplemented struct{} -// Авторизация пользователя +// Авторизация // (POST /auth/login) func (_ Unimplemented) AuthLogin(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotImplemented) @@ -147,7 +417,7 @@ func (_ Unimplemented) AuthLogout(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotImplemented) } -// Обновление access-токена через refresh-токен +// Обновление access-токена // (POST /auth/refresh) func (_ Unimplemented) AuthRefresh(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotImplemented) @@ -159,24 +429,180 @@ func (_ Unimplemented) AuthRegister(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotImplemented) } +// Список водителей +// (GET /drivers) +func (_ Unimplemented) ListDrivers(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Зарегистрировать водителя +// (POST /drivers) +func (_ Unimplemented) CreateDriver(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Удалить водителя +// (DELETE /drivers/{slug}) +func (_ Unimplemented) DeleteDriver(w http.ResponseWriter, r *http.Request, slug string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Получить водителя по slug +// (GET /drivers/{slug}) +func (_ Unimplemented) GetDriver(w http.ResponseWriter, r *http.Request, slug string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Обновить данные водителя +// (PUT /drivers/{slug}) +func (_ Unimplemented) UpdateDriver(w http.ResponseWriter, r *http.Request, slug string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Список менеджеров +// (GET /managers) +func (_ Unimplemented) ListManagers(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Назначить менеджера +// (POST /managers) +func (_ Unimplemented) CreateManager(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Удалить менеджера +// (DELETE /managers/{slug}) +func (_ Unimplemented) DeleteManager(w http.ResponseWriter, r *http.Request, slug string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Получить менеджера по slug +// (GET /managers/{slug}) +func (_ Unimplemented) GetManager(w http.ResponseWriter, r *http.Request, slug string) { + w.WriteHeader(http.StatusNotImplemented) +} + // Удалить аккаунт // (DELETE /me) func (_ Unimplemented) DeleteMe(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotImplemented) } -// Получить текущего пользователя +// Текущий пользователь // (GET /me) func (_ Unimplemented) GetMe(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotImplemented) } -// Обновить данные текущего пользователя +// Обновить профиль // (PATCH /me) func (_ Unimplemented) UpdateMe(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotImplemented) } +// Список заявок +// (GET /orders) +func (_ Unimplemented) ListOrders(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Создать заявку +// (POST /orders) +func (_ Unimplemented) CreateOrder(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Отменить заявку +// (DELETE /orders/{id}) +func (_ Unimplemented) CancelOrder(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Получить заявку +// (GET /orders/{id}) +func (_ Unimplemented) GetOrder(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Получить маршрут заявки +// (GET /orders/{id}/route) +func (_ Unimplemented) GetRoute(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) { + w.WriteHeader(http.StatusNotImplemented) +} + +// WebSocket трекинг маршрута +// (GET /orders/{id}/route/ws) +func (_ Unimplemented) RouteWebSocket(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Обновить статус заявки +// (PATCH /orders/{id}/status) +func (_ Unimplemented) UpdateOrderStatus(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Список транспортных средств +// (GET /vehicles) +func (_ Unimplemented) ListVehicles(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Добавить ТС +// (POST /vehicles) +func (_ Unimplemented) CreateVehicle(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Удалить ТС +// (DELETE /vehicles/{slug}) +func (_ Unimplemented) DeleteVehicle(w http.ResponseWriter, r *http.Request, slug string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Получить ТС по slug +// (GET /vehicles/{slug}) +func (_ Unimplemented) GetVehicle(w http.ResponseWriter, r *http.Request, slug string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Обновить ТС +// (PUT /vehicles/{slug}) +func (_ Unimplemented) UpdateVehicle(w http.ResponseWriter, r *http.Request, slug string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Список складов +// (GET /warehouses) +func (_ Unimplemented) ListWarehouses(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Создать склад +// (POST /warehouses) +func (_ Unimplemented) CreateWarehouse(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Удалить склад +// (DELETE /warehouses/{slug}) +func (_ Unimplemented) DeleteWarehouse(w http.ResponseWriter, r *http.Request, slug string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Получить склад по slug +// (GET /warehouses/{slug}) +func (_ Unimplemented) GetWarehouse(w http.ResponseWriter, r *http.Request, slug string) { + w.WriteHeader(http.StatusNotImplemented) +} + +// Обновить склад +// (PUT /warehouses/{slug}) +func (_ Unimplemented) UpdateWarehouse(w http.ResponseWriter, r *http.Request, slug string) { + w.WriteHeader(http.StatusNotImplemented) +} + // ServerInterfaceWrapper converts contexts to parameters. type ServerInterfaceWrapper struct { Handler ServerInterface @@ -203,6 +629,12 @@ func (siw *ServerInterfaceWrapper) AuthLogin(w http.ResponseWriter, r *http.Requ // AuthLogout operation middleware func (siw *ServerInterfaceWrapper) AuthLogout(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { siw.Handler.AuthLogout(w, r) })) @@ -242,9 +674,250 @@ func (siw *ServerInterfaceWrapper) AuthRegister(w http.ResponseWriter, r *http.R handler.ServeHTTP(w, r) } +// ListDrivers operation middleware +func (siw *ServerInterfaceWrapper) ListDrivers(w http.ResponseWriter, r *http.Request) { + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.ListDrivers(w, r) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// CreateDriver operation middleware +func (siw *ServerInterfaceWrapper) CreateDriver(w http.ResponseWriter, r *http.Request) { + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.CreateDriver(w, r) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// DeleteDriver operation middleware +func (siw *ServerInterfaceWrapper) DeleteDriver(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "slug" ------------- + var slug string + + err = runtime.BindStyledParameterWithOptions("simple", "slug", chi.URLParam(r, "slug"), &slug, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "slug", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.DeleteDriver(w, r, slug) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// GetDriver operation middleware +func (siw *ServerInterfaceWrapper) GetDriver(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "slug" ------------- + var slug string + + err = runtime.BindStyledParameterWithOptions("simple", "slug", chi.URLParam(r, "slug"), &slug, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "slug", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.GetDriver(w, r, slug) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// UpdateDriver operation middleware +func (siw *ServerInterfaceWrapper) UpdateDriver(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "slug" ------------- + var slug string + + err = runtime.BindStyledParameterWithOptions("simple", "slug", chi.URLParam(r, "slug"), &slug, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "slug", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.UpdateDriver(w, r, slug) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// ListManagers operation middleware +func (siw *ServerInterfaceWrapper) ListManagers(w http.ResponseWriter, r *http.Request) { + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.ListManagers(w, r) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// CreateManager operation middleware +func (siw *ServerInterfaceWrapper) CreateManager(w http.ResponseWriter, r *http.Request) { + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.CreateManager(w, r) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// DeleteManager operation middleware +func (siw *ServerInterfaceWrapper) DeleteManager(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "slug" ------------- + var slug string + + err = runtime.BindStyledParameterWithOptions("simple", "slug", chi.URLParam(r, "slug"), &slug, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "slug", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.DeleteManager(w, r, slug) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// GetManager operation middleware +func (siw *ServerInterfaceWrapper) GetManager(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "slug" ------------- + var slug string + + err = runtime.BindStyledParameterWithOptions("simple", "slug", chi.URLParam(r, "slug"), &slug, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "slug", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.GetManager(w, r, slug) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + // DeleteMe operation middleware func (siw *ServerInterfaceWrapper) DeleteMe(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { siw.Handler.DeleteMe(w, r) })) @@ -259,6 +932,12 @@ func (siw *ServerInterfaceWrapper) DeleteMe(w http.ResponseWriter, r *http.Reque // GetMe operation middleware func (siw *ServerInterfaceWrapper) GetMe(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { siw.Handler.GetMe(w, r) })) @@ -273,6 +952,12 @@ func (siw *ServerInterfaceWrapper) GetMe(w http.ResponseWriter, r *http.Request) // UpdateMe operation middleware func (siw *ServerInterfaceWrapper) UpdateMe(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { siw.Handler.UpdateMe(w, r) })) @@ -284,6 +969,467 @@ func (siw *ServerInterfaceWrapper) UpdateMe(w http.ResponseWriter, r *http.Reque handler.ServeHTTP(w, r) } +// ListOrders operation middleware +func (siw *ServerInterfaceWrapper) ListOrders(w http.ResponseWriter, r *http.Request) { + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.ListOrders(w, r) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// CreateOrder operation middleware +func (siw *ServerInterfaceWrapper) CreateOrder(w http.ResponseWriter, r *http.Request) { + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.CreateOrder(w, r) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// CancelOrder operation middleware +func (siw *ServerInterfaceWrapper) CancelOrder(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "id" ------------- + var id openapi_types.UUID + + err = runtime.BindStyledParameterWithOptions("simple", "id", chi.URLParam(r, "id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "uuid"}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.CancelOrder(w, r, id) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// GetOrder operation middleware +func (siw *ServerInterfaceWrapper) GetOrder(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "id" ------------- + var id openapi_types.UUID + + err = runtime.BindStyledParameterWithOptions("simple", "id", chi.URLParam(r, "id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "uuid"}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.GetOrder(w, r, id) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// GetRoute operation middleware +func (siw *ServerInterfaceWrapper) GetRoute(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "id" ------------- + var id openapi_types.UUID + + err = runtime.BindStyledParameterWithOptions("simple", "id", chi.URLParam(r, "id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "uuid"}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.GetRoute(w, r, id) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// RouteWebSocket operation middleware +func (siw *ServerInterfaceWrapper) RouteWebSocket(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "id" ------------- + var id openapi_types.UUID + + err = runtime.BindStyledParameterWithOptions("simple", "id", chi.URLParam(r, "id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "uuid"}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.RouteWebSocket(w, r, id) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// UpdateOrderStatus operation middleware +func (siw *ServerInterfaceWrapper) UpdateOrderStatus(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "id" ------------- + var id openapi_types.UUID + + err = runtime.BindStyledParameterWithOptions("simple", "id", chi.URLParam(r, "id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "uuid"}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.UpdateOrderStatus(w, r, id) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// ListVehicles operation middleware +func (siw *ServerInterfaceWrapper) ListVehicles(w http.ResponseWriter, r *http.Request) { + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.ListVehicles(w, r) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// CreateVehicle operation middleware +func (siw *ServerInterfaceWrapper) CreateVehicle(w http.ResponseWriter, r *http.Request) { + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.CreateVehicle(w, r) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// DeleteVehicle operation middleware +func (siw *ServerInterfaceWrapper) DeleteVehicle(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "slug" ------------- + var slug string + + err = runtime.BindStyledParameterWithOptions("simple", "slug", chi.URLParam(r, "slug"), &slug, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "slug", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.DeleteVehicle(w, r, slug) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// GetVehicle operation middleware +func (siw *ServerInterfaceWrapper) GetVehicle(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "slug" ------------- + var slug string + + err = runtime.BindStyledParameterWithOptions("simple", "slug", chi.URLParam(r, "slug"), &slug, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "slug", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.GetVehicle(w, r, slug) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// UpdateVehicle operation middleware +func (siw *ServerInterfaceWrapper) UpdateVehicle(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "slug" ------------- + var slug string + + err = runtime.BindStyledParameterWithOptions("simple", "slug", chi.URLParam(r, "slug"), &slug, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "slug", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.UpdateVehicle(w, r, slug) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// ListWarehouses operation middleware +func (siw *ServerInterfaceWrapper) ListWarehouses(w http.ResponseWriter, r *http.Request) { + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.ListWarehouses(w, r) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// CreateWarehouse operation middleware +func (siw *ServerInterfaceWrapper) CreateWarehouse(w http.ResponseWriter, r *http.Request) { + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.CreateWarehouse(w, r) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// DeleteWarehouse operation middleware +func (siw *ServerInterfaceWrapper) DeleteWarehouse(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "slug" ------------- + var slug string + + err = runtime.BindStyledParameterWithOptions("simple", "slug", chi.URLParam(r, "slug"), &slug, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "slug", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.DeleteWarehouse(w, r, slug) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// GetWarehouse operation middleware +func (siw *ServerInterfaceWrapper) GetWarehouse(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "slug" ------------- + var slug string + + err = runtime.BindStyledParameterWithOptions("simple", "slug", chi.URLParam(r, "slug"), &slug, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "slug", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.GetWarehouse(w, r, slug) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// UpdateWarehouse operation middleware +func (siw *ServerInterfaceWrapper) UpdateWarehouse(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "slug" ------------- + var slug string + + err = runtime.BindStyledParameterWithOptions("simple", "slug", chi.URLParam(r, "slug"), &slug, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "slug", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.UpdateWarehouse(w, r, slug) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + type UnescapedCookieParamError struct { ParamName string Err error @@ -409,6 +1555,33 @@ func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handl r.Group(func(r chi.Router) { r.Post(options.BaseURL+"/auth/register", wrapper.AuthRegister) }) + r.Group(func(r chi.Router) { + r.Get(options.BaseURL+"/drivers", wrapper.ListDrivers) + }) + r.Group(func(r chi.Router) { + r.Post(options.BaseURL+"/drivers", wrapper.CreateDriver) + }) + r.Group(func(r chi.Router) { + r.Delete(options.BaseURL+"/drivers/{slug}", wrapper.DeleteDriver) + }) + r.Group(func(r chi.Router) { + r.Get(options.BaseURL+"/drivers/{slug}", wrapper.GetDriver) + }) + r.Group(func(r chi.Router) { + r.Put(options.BaseURL+"/drivers/{slug}", wrapper.UpdateDriver) + }) + r.Group(func(r chi.Router) { + r.Get(options.BaseURL+"/managers", wrapper.ListManagers) + }) + r.Group(func(r chi.Router) { + r.Post(options.BaseURL+"/managers", wrapper.CreateManager) + }) + r.Group(func(r chi.Router) { + r.Delete(options.BaseURL+"/managers/{slug}", wrapper.DeleteManager) + }) + r.Group(func(r chi.Router) { + r.Get(options.BaseURL+"/managers/{slug}", wrapper.GetManager) + }) r.Group(func(r chi.Router) { r.Delete(options.BaseURL+"/me", wrapper.DeleteMe) }) @@ -418,6 +1591,57 @@ func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handl r.Group(func(r chi.Router) { r.Patch(options.BaseURL+"/me", wrapper.UpdateMe) }) + r.Group(func(r chi.Router) { + r.Get(options.BaseURL+"/orders", wrapper.ListOrders) + }) + r.Group(func(r chi.Router) { + r.Post(options.BaseURL+"/orders", wrapper.CreateOrder) + }) + r.Group(func(r chi.Router) { + r.Delete(options.BaseURL+"/orders/{id}", wrapper.CancelOrder) + }) + r.Group(func(r chi.Router) { + r.Get(options.BaseURL+"/orders/{id}", wrapper.GetOrder) + }) + r.Group(func(r chi.Router) { + r.Get(options.BaseURL+"/orders/{id}/route", wrapper.GetRoute) + }) + r.Group(func(r chi.Router) { + r.Get(options.BaseURL+"/orders/{id}/route/ws", wrapper.RouteWebSocket) + }) + r.Group(func(r chi.Router) { + r.Patch(options.BaseURL+"/orders/{id}/status", wrapper.UpdateOrderStatus) + }) + r.Group(func(r chi.Router) { + r.Get(options.BaseURL+"/vehicles", wrapper.ListVehicles) + }) + r.Group(func(r chi.Router) { + r.Post(options.BaseURL+"/vehicles", wrapper.CreateVehicle) + }) + r.Group(func(r chi.Router) { + r.Delete(options.BaseURL+"/vehicles/{slug}", wrapper.DeleteVehicle) + }) + r.Group(func(r chi.Router) { + r.Get(options.BaseURL+"/vehicles/{slug}", wrapper.GetVehicle) + }) + r.Group(func(r chi.Router) { + r.Put(options.BaseURL+"/vehicles/{slug}", wrapper.UpdateVehicle) + }) + r.Group(func(r chi.Router) { + r.Get(options.BaseURL+"/warehouses", wrapper.ListWarehouses) + }) + r.Group(func(r chi.Router) { + r.Post(options.BaseURL+"/warehouses", wrapper.CreateWarehouse) + }) + r.Group(func(r chi.Router) { + r.Delete(options.BaseURL+"/warehouses/{slug}", wrapper.DeleteWarehouse) + }) + r.Group(func(r chi.Router) { + r.Get(options.BaseURL+"/warehouses/{slug}", wrapper.GetWarehouse) + }) + r.Group(func(r chi.Router) { + r.Put(options.BaseURL+"/warehouses/{slug}", wrapper.UpdateWarehouse) + }) return r } diff --git a/internal/handler/driver.go b/internal/handler/driver.go new file mode 100644 index 0000000..96bbb2a --- /dev/null +++ b/internal/handler/driver.go @@ -0,0 +1,13 @@ +package handler + +import "net/http" + +func (s *Server) ListDrivers(w http.ResponseWriter, r *http.Request) {} + +func (s *Server) CreateDriver(w http.ResponseWriter, r *http.Request) {} + +func (s *Server) GetDriver(w http.ResponseWriter, r *http.Request, slug string) {} + +func (s *Server) UpdateDriver(w http.ResponseWriter, r *http.Request, slug string) {} + +func (s *Server) DeleteDriver(w http.ResponseWriter, r *http.Request, slug string) {} diff --git a/internal/handler/manager.go b/internal/handler/manager.go new file mode 100644 index 0000000..1cb2c2b --- /dev/null +++ b/internal/handler/manager.go @@ -0,0 +1,11 @@ +package handler + +import "net/http" + +func (s *Server) ListManagers(w http.ResponseWriter, r *http.Request) {} + +func (s *Server) CreateManager(w http.ResponseWriter, r *http.Request) {} + +func (s *Server) GetManager(w http.ResponseWriter, r *http.Request, slug string) {} + +func (s *Server) DeleteManager(w http.ResponseWriter, r *http.Request, slug string) {} diff --git a/internal/handler/order.go b/internal/handler/order.go new file mode 100644 index 0000000..7166494 --- /dev/null +++ b/internal/handler/order.go @@ -0,0 +1,17 @@ +package handler + +import ( + "net/http" + + openapi_types "github.com/oapi-codegen/runtime/types" +) + +func (s *Server) ListOrders(w http.ResponseWriter, r *http.Request) {} + +func (s *Server) CreateOrder(w http.ResponseWriter, r *http.Request) {} + +func (s *Server) GetOrder(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) {} + +func (s *Server) CancelOrder(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) {} + +func (s *Server) UpdateOrderStatus(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) {} diff --git a/internal/handler/route.go b/internal/handler/route.go new file mode 100644 index 0000000..ff2bbe2 --- /dev/null +++ b/internal/handler/route.go @@ -0,0 +1,11 @@ +package handler + +import ( + "net/http" + + openapi_types "github.com/oapi-codegen/runtime/types" +) + +func (s *Server) GetRoute(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) {} + +func (s *Server) RouteWebSocket(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) {} diff --git a/internal/handler/user.go b/internal/handler/user.go index 6cd351d..3f1b1ad 100644 --- a/internal/handler/user.go +++ b/internal/handler/user.go @@ -47,7 +47,7 @@ func (s *Server) AuthLogin(w http.ResponseWriter, r *http.Request) { } if err := bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(req.Password)); err != nil { - slog.WarnContext(ctx, "Failed login to account with", slog.String("email:", string(req.Email)), slog.String("password from request", req.Password)) + slog.WarnContext(ctx, "Failed login to account with", slog.String("email:", string(req.Email))) s.JSON(w, r, http.StatusBadRequest, "Неверный пароль", "error") return } @@ -207,7 +207,7 @@ func (s *Server) DeleteMe(w http.ResponseWriter, r *http.Request) { } jwt := r.Header.Get("Authorization") - tokenKey := "access_token" + jwt + tokenKey := "access_token:" + jwt if err := s.Redis.Del(ctx, tokenKey).Err(); err != nil { slog.ErrorContext(ctx, "Error while deleting access token from redis", slog.String("token", jwt)) s.JSON(w, r, http.StatusInternalServerError, "Internal server error", "error") diff --git a/internal/handler/vehicle.go b/internal/handler/vehicle.go new file mode 100644 index 0000000..59f6260 --- /dev/null +++ b/internal/handler/vehicle.go @@ -0,0 +1,13 @@ +package handler + +import "net/http" + +func (s *Server) ListVehicles(w http.ResponseWriter, r *http.Request) {} + +func (s *Server) CreateVehicle(w http.ResponseWriter, r *http.Request) {} + +func (s *Server) GetVehicle(w http.ResponseWriter, r *http.Request, slug string) {} + +func (s *Server) UpdateVehicle(w http.ResponseWriter, r *http.Request, slug string) {} + +func (s *Server) DeleteVehicle(w http.ResponseWriter, r *http.Request, slug string) {} diff --git a/internal/handler/warehouse.go b/internal/handler/warehouse.go new file mode 100644 index 0000000..ab7cf52 --- /dev/null +++ b/internal/handler/warehouse.go @@ -0,0 +1,13 @@ +package handler + +import "net/http" + +func (s *Server) ListWarehouses(w http.ResponseWriter, r *http.Request) {} + +func (s *Server) CreateWarehouse(w http.ResponseWriter, r *http.Request) {} + +func (s *Server) GetWarehouse(w http.ResponseWriter, r *http.Request, slug string) {} + +func (s *Server) UpdateWarehouse(w http.ResponseWriter, r *http.Request, slug string) {} + +func (s *Server) DeleteWarehouse(w http.ResponseWriter, r *http.Request, slug string) {} diff --git a/internal/models/driver.go b/internal/models/driver.go new file mode 100644 index 0000000..2502ca9 --- /dev/null +++ b/internal/models/driver.go @@ -0,0 +1,18 @@ +package models + +import ( + "time" + + "github.com/google/uuid" +) + +type Driver struct { + ID uuid.UUID `db:"id"` + UserID uuid.UUID `db:"user_id"` + VehicleID *uuid.UUID `db:"vehicle_id"` + LicenseNumber string `db:"license_number"` + LicenseExpiry time.Time `db:"license_expiry"` + Rating float64 `db:"rating"` + Slug string `db:"slug"` + Status string `db:"status"` // available, on_route, off_duty +} diff --git a/internal/models/manager.go b/internal/models/manager.go new file mode 100644 index 0000000..9ff41c4 --- /dev/null +++ b/internal/models/manager.go @@ -0,0 +1,10 @@ +package models + +import "github.com/google/uuid" + +type Manager struct { + ID uuid.UUID `db:"id"` + UserID uuid.UUID `db:"user_id"` + WarehouseID *uuid.UUID `db:"warehouse_id"` + Slug string `db:"slug"` +} diff --git a/internal/models/order.go b/internal/models/order.go new file mode 100644 index 0000000..f1de80b --- /dev/null +++ b/internal/models/order.go @@ -0,0 +1,25 @@ +package models + +import ( + "time" + + "github.com/google/uuid" +) + +type Order struct { + ID uuid.UUID `db:"id"` + CreatedByID *uuid.UUID `db:"created_by_id"` + DriverID *uuid.UUID `db:"driver_id"` + ManagerID *uuid.UUID `db:"manager_id"` + OriginWarehouseID *uuid.UUID `db:"origin_warehouse_id"` + OriginAddress string `db:"origin_address"` + DestinationAddress string `db:"destination_address"` + CargoDescription string `db:"cargo_description"` + WeightKg float64 `db:"weight_kg"` + VolumeM3 float64 `db:"volume_m3"` + Status string `db:"status"` // pending, assigned, in_transit, delivered, cancelled + TotalPrice float64 `db:"total_price"` + CreatedAt time.Time `db:"created_at"` + AssignedAt *time.Time `db:"assigned_at"` + DeliveredAt *time.Time `db:"delivered_at"` +} diff --git a/internal/models/route.go b/internal/models/route.go new file mode 100644 index 0000000..fd55bf6 --- /dev/null +++ b/internal/models/route.go @@ -0,0 +1,33 @@ +package models + +import ( + "encoding/json" + "time" + + "github.com/google/uuid" +) + +// Coordinate represents a [longitude, latitude] pair — ORS array format. +type Coordinate [2]float64 + +type Route struct { + ID uuid.UUID `db:"id"` + OrderID uuid.UUID `db:"order_id"` + DriverID *uuid.UUID `db:"driver_id"` + Coordinates json.RawMessage `db:"coordinates"` // JSONB: [][2]float64 + CurrentIndex int `db:"current_index"` + StartedAt *time.Time `db:"started_at"` + FinishedAt *time.Time `db:"finished_at"` + DistanceKm float64 `db:"distance_km"` + DurationSec int `db:"duration_sec"` + Status string `db:"status"` // pending, active, finished +} + +// ParseCoordinates unmarshals the raw JSONB coordinates into a typed slice. +func (r *Route) ParseCoordinates() ([]Coordinate, error) { + var coords []Coordinate + if err := json.Unmarshal(r.Coordinates, &coords); err != nil { + return nil, err + } + return coords, nil +} diff --git a/internal/models/vehicle.go b/internal/models/vehicle.go new file mode 100644 index 0000000..9d71fb5 --- /dev/null +++ b/internal/models/vehicle.go @@ -0,0 +1,15 @@ +package models + +import "github.com/google/uuid" + +type Vehicle struct { + ID uuid.UUID `db:"id"` + PlateNumber string `db:"plate_number"` + Brand string `db:"brand"` + Model string `db:"model"` + Year int `db:"year"` + CapacityKg float64 `db:"capacity_kg"` + CapacityM3 float64 `db:"capacity_m3"` + Status string `db:"status"` // available, in_transit, maintenance + Slug string `db:"slug"` +} diff --git a/internal/models/warehouse.go b/internal/models/warehouse.go new file mode 100644 index 0000000..c6b1cd2 --- /dev/null +++ b/internal/models/warehouse.go @@ -0,0 +1,19 @@ +package models + +import ( + "time" + + "github.com/google/uuid" +) + +type Warehouse struct { + ID uuid.UUID `db:"id"` + Slug string `db:"slug"` + Name string `db:"name"` + Address string `db:"address"` + City string `db:"city"` + Latitude float64 `db:"latitude"` + Longitude float64 `db:"longitude"` + Status string `db:"status"` // active, inactive + CreatedAt time.Time `db:"created_at"` +} diff --git a/migrations/20260303130413_create_user.sql b/migrations/20260303130413_create_user.sql index 55c1f29..bd6e33c 100644 --- a/migrations/20260303130413_create_user.sql +++ b/migrations/20260303130413_create_user.sql @@ -12,6 +12,7 @@ CREATE TABLE IF NOT EXISTS users ( updated_at TIMESTAMPTZ, last_login_at TIMESTAMPTZ ); + -- +goose StatementEnd -- +goose Down diff --git a/migrations/20260303130430_create_order.sql b/migrations/20260303130430_create_order.sql index b9c449e..ea36dea 100644 --- a/migrations/20260303130430_create_order.sql +++ b/migrations/20260303130430_create_order.sql @@ -1,9 +1,25 @@ -- +goose Up -- +goose StatementBegin -SELECT 'up SQL query'; +CREATE TABLE IF NOT EXISTS orders ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + created_by_id UUID REFERENCES users(id) ON DELETE SET NULL, + driver_id UUID REFERENCES drivers(id) ON DELETE SET NULL, + manager_id UUID REFERENCES managers(id) ON DELETE SET NULL, + origin_warehouse_id UUID REFERENCES warehouses(id) ON DELETE SET NULL, + origin_address VARCHAR(255), + destination_address VARCHAR(255) NOT NULL, + cargo_description TEXT, + weight_kg NUMERIC(10,2), + volume_m3 NUMERIC(10,2), + status VARCHAR(20) DEFAULT 'pending', + total_price NUMERIC(12,2), + created_at TIMESTAMPTZ DEFAULT NOW(), + assigned_at TIMESTAMPTZ, + delivered_at TIMESTAMPTZ +); -- +goose StatementEnd -- +goose Down -- +goose StatementBegin -SELECT 'down SQL query'; +DROP TABLE IF EXISTS orders; -- +goose StatementEnd diff --git a/migrations/20260322074231_create_manager.sql b/migrations/20260322074231_create_manager.sql new file mode 100644 index 0000000..7aeb93e --- /dev/null +++ b/migrations/20260322074231_create_manager.sql @@ -0,0 +1,14 @@ +-- +goose Up +-- +goose StatementBegin +CREATE TABLE IF NOT EXISTS managers ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + user_id UUID UNIQUE REFERENCES users(id) ON DELETE CASCADE, + warehouse_id UUID REFERENCES warehouses(id) ON DELETE SET NULL, + slug VARCHAR(120) UNIQUE NOT NULL +); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP TABLE IF EXISTS managers; +-- +goose StatementEnd diff --git a/migrations/20260322080115_create_warehouse.sql b/migrations/20260322080115_create_warehouse.sql new file mode 100644 index 0000000..3864257 --- /dev/null +++ b/migrations/20260322080115_create_warehouse.sql @@ -0,0 +1,19 @@ +-- +goose Up +-- +goose StatementBegin +CREATE TABLE IF NOT EXISTS warehouses ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + slug VARCHAR(120) UNIQUE NOT NULL, + name VARCHAR(150) NOT NULL, + address VARCHAR(255) NOT NULL, + city VARCHAR(100), + latitude NUMERIC(9,6), + longitude NUMERIC(9,6), + status VARCHAR(20) DEFAULT 'active', + created_at TIMESTAMPTZ DEFAULT NOW() +); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP TABLE IF EXISTS warehouses; +-- +goose StatementEnd diff --git a/migrations/20260323124352_create_routes.sql b/migrations/20260323124352_create_routes.sql new file mode 100644 index 0000000..a8460f2 --- /dev/null +++ b/migrations/20260323124352_create_routes.sql @@ -0,0 +1,20 @@ +-- +goose Up +-- +goose StatementBegin +CREATE TABLE IF NOT EXISTS routes ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + order_id UUID UNIQUE REFERENCES orders(id) ON DELETE CASCADE, + driver_id UUID REFERENCES drivers(id) ON DELETE SET NULL, + coordinates JSONB, + current_index INTEGER DEFAULT 0, + started_at TIMESTAMPTZ, + finished_at TIMESTAMPTZ, + distance_km NUMERIC(10,2), + duration_sec INTEGER, + status VARCHAR(20) DEFAULT 'pending' +); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP TABLE IF EXISTS routes; +-- +goose StatementEnd