diff --git a/docs/openapi.yaml b/docs/openapi.yaml index 0ee074a..2d59bb6 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -2,68 +2,64 @@ openapi: 3.0.0 info: title: Codeword Recovery Service API version: 1.0.0 - description: API for handling password recovery for the Codeword service. + description: API для обработки восстановления паролей для сервиса Codeword. +tags: + - name: recover + description: Операции связанные с восстановлением пароля + - name: promocode + description: Операции связанные с промокодами + - name: stats + description: Операции связанные со статистикой paths: /liveness: get: + operationId: Liveness summary: Роут проверки активности + tags: + - recover responses: '200': description: Успех – сервис запущен /readiness: get: - summary: Роут проверки базы данных + operationId: Readiness + summary: Роут проверки баз данных + tags: + - recover responses: '200': description: Успех — сервис готов и соединение с БД живо '503': description: Служба недоступна — не удалось выполнить проверку связи с БД - /recover: post: - summary: Запустите процесс восстановления пароля + operationId: Recovery + summary: Восстановления пароля + tags: + - recover requestBody: required: true content: application/json: schema: - type: object - required: - - email - properties: - email: - type: string - format: email - description: Электронная почта, на которую нужно отправить инструкции по восстановлению - Referrer: - type: string - description: URL-адрес referral, если он доступен - RedirectionURL: - type: string - description: URL-адрес, на который перенаправляется пользователь после отправки электронного письма - + $ref: '#/components/schemas/RecoveryRequest' responses: '200': - description: Запрос на восстановление принят, и возвращен идентификатор записи восстановления - content: - application/json: - schema: - type: object - properties: - id: - type: string - description: Идентификатор запроса на восстановление + description: Запрос на восстановление принят '404': description: Пользователь не найден по электронной почте '500': - description: Внутренняя ошибка сервера – разные причины + description: Внутренняя ошибка сервера /recover/{sign}: get: - summary: Обработать ссылку восстановления, в которой содержится подпись и обменять ее на токены + operationId: RecoveryLink + summary: Обработать ссылку восстановления и обменять ее на токены + tags: + - recover parameters: - in: path name: sign @@ -73,59 +69,41 @@ paths: description: Подпись восстановления как часть URL-адреса восстановления responses: '200': - description: Восстановление успешно, информация для обмена токенов возвращена - content: - application/json: - schema: - type: object - properties: - accessToken: - type: string - refreshToken: - type: string + description: Восстановление успешно, информация для обмена токенов возвращена в cookie '406': description: NotAcceptable - срок действия ссылки для восстановления истек или она недействительна '500': - description: Внутренняя ошибка сервера – разные причины + description: Внутренняя ошибка сервера /promocode/create: post: + operationId: CreatePromoCode summary: Создать новый промокод + tags: + - promocode requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/PromoCodeRequest' + $ref: '#/components/schemas/PromoCodeReq' responses: - '201': + '200': description: Новый промокод успешно создан content: application/json: schema: - $ref: '#/components/schemas/PromoCodeResponse' + $ref: '#/components/schemas/PromoCode' '400': - description: Invalid request payload / Duplicate Codeword - content: - application/json: - schema: - type: object - properties: - error: - type: string + description: Неверный формат запроса или дублирующийся codeword '500': description: Внутренняя ошибка сервера - content: - application/json: - schema: - type: object - properties: - error: - type: string - /promocode/edit: put: + operationId: EditPromoCode summary: Обновить существующий промокод + tags: + - promocode requestBody: required: true content: @@ -138,38 +116,20 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/PromoCodeResponse' + $ref: '#/components/schemas/PromoCode' '400': description: Неверный формат запроса - content: - application/json: - schema: - type: object - properties: - error: - type: string '404': description: Промокод не найден - content: - application/json: - schema: - type: object - properties: - error: - type: string '500': description: Внутренняя ошибка сервера - content: - application/json: - schema: - type: object - properties: - error: - type: string /promocode/getList: post: - summary: Получить список промокодов + operationId: GetList + summary: Получить список промокодов с пагинацией + tags: + - promocode requestBody: required: true content: @@ -185,19 +145,15 @@ paths: $ref: '#/components/schemas/GetPromoCodesListResp' '400': description: Неверный запрос из-за невалидных данных - content: - application/json: - schema: - type: object - properties: - error: - type: string '500': description: Внутренняя ошибка сервера /promocode/activate: post: + operationId: Activate summary: Активировать промокод + tags: + - promocode requestBody: required: true content: @@ -212,7 +168,7 @@ paths: schema: $ref: '#/components/schemas/ActivateResp' '400': - description: Невалидный запрос или отсутствует обязательное поле codeword + description: Невалидный запрос или отсутствует обязательное поле codeword или fastLink '404': description: Промокод не найден '500': @@ -220,7 +176,10 @@ paths: /promocode/{promocodeID}: delete: + operationId: Delete summary: Мягко удалить промокод по его id + tags: + - promocode parameters: - in: path name: promocodeID @@ -233,98 +192,50 @@ paths: description: Промокод успешно помечен как удаленный '400': description: Неверный запрос, отсутствует идентификатор промокода - content: - application/json: - schema: - type: object - properties: - error: - type: string '404': description: Промокод не найден - content: - application/json: - schema: - type: object - properties: - error: - type: string '500': description: Внутренняя ошибка сервера - content: - application/json: - schema: - type: object - properties: - error: - type: string /promocode/fastlink: post: + operationId: CreateFastLink summary: Создать быструю ссылку для промокода + tags: + - promocode requestBody: required: true content: application/json: schema: - type: object - required: - - id - properties: - id: - type: string - description: ID промокода, для которого нужно создать быструю ссылку + $ref: '#/components/schemas/CreateFastLinkRequest' responses: - '201': + '200': description: Быстрая ссылка для промокода успешно создана content: application/json: schema: - type: object - properties: - fastlink: - type: string - description: Быстрая ссылка для активации промокода + $ref: '#/components/schemas/CreateFastLinkResponse' '400': description: Неверный запрос, отсутствует идентификатор промокода - content: - application/json: - schema: - type: object - properties: - error: - type: string '404': description: Промокод не найден - content: - application/json: - schema: - type: object - properties: - error: - type: string '500': description: Внутренняя ошибка сервера - content: - application/json: - schema: - type: object - properties: - error: - type: string + /promocode/stats: - post: + get: + operationId: GetStats summary: Получить статистику промокода + tags: + - stats + description: Идентификатор промокода requestBody: required: true content: application/json: schema: - type: object - properties: - promoCodeID: - type: string - description: Идентификатор промокода + $ref: '#/components/schemas/PromoCodeStatsRequest' responses: '200': description: Статистика промокода успешно получена @@ -334,199 +245,83 @@ paths: $ref: '#/components/schemas/PromoCodeStats' '400': description: Неверный запрос - content: - application/json: - schema: - type: object - properties: - error: - type: string '500': description: Внутренняя ошибка сервера - content: - application/json: - schema: - type: object - properties: - error: - type: string + components: schemas: - PromoCodeRequest: + RecoveryRequest: + type: object + required: + - email + properties: + email: + type: string + format: email + description: Электронная почта, на которую нужно отправить инструкции по восстановлению + redirectionURL: + type: string + description: URL-адрес, на который перенаправляется пользователь + PromoCodeStatsRequest: type: object properties: - codeword: + promoCodeID: type: string - description: Кодовое слово, которое должен ввести пользователь - description: - type: string - description: Описание, необходимое для администратора в панели управления - greetings: - type: string - description: Текст, который будет отправлен пользователю в ответ на активацию кода - dueTo: - type: integer - format: int64 - description: Временная метка окончания активации кода - activationCount: - type: integer - format: int64 - description: Лимит активации кода - bonus: - type: object - properties: - privilege: - type: object - properties: - privilegeID: - type: string - description: Идентификатор привилегии, которую необходимо предоставить - amount: - type: integer - format: uint64 - description: Размер привилегии - discount: - type: object - properties: - layer: - type: integer - factor: - type: number - target: - type: string - threshold: - type: integer - description: Информация о бонусах - - PromoCodeResponse: + required: + - promoCodeID + PromoCodeStats: type: object properties: id: type: string - description: ID созданного промокода - codeword: - type: string - description: Кодовое слово промокода - description: - type: string - description: Описание промокода - greetings: - type: string - description: Текст, который будет отправлен пользователю в ответ на активацию кода - dueTo: + description: Идентификатор промокода + usageCount: type: integer - format: int64 - description: Временная метка окончания активации кода - activationCount: - type: integer - format: int64 - description: Лимит активации кода - bonus: + description: Количество использований промокода + usageMap: type: object - properties: - privilege: - type: object - properties: - privilegeID: - type: string - description: Идентификатор привилегии, которую необходимо предоставить - amount: - type: integer - format: uint64 - description: Размер привилегии - discount: - type: object - properties: - layer: - type: integer - factor: - type: number - target: - type: string - threshold: - type: integer - description: Информация о бонусах - outdated: - type: boolean - offLimit: - type: boolean - delete: - type: boolean - createdAt: + description: Карта использования промокода + additionalProperties: + type: array + items: + $ref: '#/components/schemas/Usage' + + Usage: + type: object + properties: + key: + type: string + description: fastlink или codeword в зависимости от того что применялось + time: type: string format: date-time - description: Время создания промокода + description: Время использования промокода - ReqEditPromoCode: + CreateFastLinkRequest: type: object properties: id: type: string - description: ID промокода, который обновляем - description: - type: string - description: Описание, необходимое менеджеру в админке - greetings: - type: string - description: Текст, выдаваемый пользователю в ответ на активацию промокода - dueTo: - type: integer - format: int64 - description: Временная метка окончания активации кода - activationCount: - type: integer - format: int64 - description: Предел количества активаций промокода - delete: - type: boolean - description: Флаг удаления промокода + description: ID промокода, для которого нужно создать быструю ссылку required: - id - GetPromoCodesListReq: - type: object - required: - - page - - limit - - filter - properties: - page: - type: integer - description: Номер страницы выборки, начиная с 0 - limit: - type: integer - description: Размер страницы выборки - filter: - $ref: '#/components/schemas/GetPromoCodesListReqFilter' - GetPromoCodesListReqFilter: + CreateFastLinkResponse: type: object properties: - text: + fastlink: type: string - description: Полнотекстовый поиск по полям Codeword, Description, Greetings - active: - type: boolean - description: Если true, выбираются записи, где delete, outdated и offLimit равны false - - GetPromoCodesListResp: - type: object - properties: - count: - type: integer - format: int64 - description: Общее количество промокодов в выборке - items: - type: array - items: - $ref: '#/components/schemas/PromoCodeResponse' + description: Быстрая ссылка для активации промокода ActivateReq: type: object + required: + - codeword properties: codeword: type: string - description: Кодовое слово промокода, которое требуется активировать + description: Кодовое слово для активации промокода fastLink: type: string description: Быстрая ссылка для активации промокода @@ -536,17 +331,190 @@ components: properties: greetings: type: string - description: Поле из активированного промокода + description: Слово успешной активации промокода - PromoCodeStats: + GetPromoCodesListReq: + type: object + required: + - page + - limit + properties: + page: + type: integer + description: Номер страницы + limit: + type: integer + description: Максимальное количество элементов на странице + filter: + $ref: '#/components/schemas/Filter' + + Filter: + type: object + properties: + text: + type: string + description: Текстовый фильтр для поиска промокодов + active: + type: boolean + description: Флаг для фильтрации активных промокодов + + GetPromoCodesListResp: + type: object + properties: + count: + type: integer + description: Общее количество промокодов + items: + type: array + items: + $ref: '#/components/schemas/PromoCode' + + PromoCode: type: object properties: id: type: string - description: ID промокода - usageCount: + description: Идентификатор промокода + codeword: + type: string + description: Кодовое слово для активации промокода + description: + type: string + description: Описание промокода + greetings: + type: string + description: Приветственное сообщение после активации промокода + dueTo: + type: integer + description: Дата истечения действия промокода в формате Unix time + activationCount: + type: integer + description: Количество активаций промокода + bonus: type: object - description: Количество использований промокода для каждого пользователя - usageHistory: + description: Бонус, предоставляемый с промокодом + properties: + privilege: + type: object + description: Привилегия + properties: + privilegeID: + type: string + description: Идентификатор привилегии + amount: + type: integer + description: Количество привилегии + discount: + type: object + description: Скидка + properties: + layer: + type: integer + description: Уровень скидки + factor: + type: number + description: Множитель скидки + target: + type: string + description: Слой + threshold: + type: integer + description: Граничное значение + outdated: + type: boolean + description: Флаг + offLimit: + type: boolean + description: Флаг + delete: + type: boolean + description: Флаг + createdAt: + type: string + format: date-time + description: Дата и время создания промокода + fastLinks: + type: array + items: + type: string + description: Список быстрых ссылок для активации промокода + + ReqEditPromoCode: + type: object + properties: + ID: + type: string + description: Идентификатор промокода, который требуется обновить + Description: + type: string + nullable: true + description: Описание промокода + Greetings: + type: string + nullable: true + description: Приветственное сообщение после активации промокода + DueTo: + type: integer + nullable: true + description: Дата окончания промокода в формате Unix time + ActivationCount: + type: integer + nullable: true + description: Количество активаций промокода + Delete: + type: boolean + nullable: true + description: Флаг удаления промокода + PromoCodeReq: + type: object + properties: + codeword: + type: string + description: Кодовое слово для активации промокода + description: + type: string + description: Описание промокода + greetings: + type: string + description: Приветственное сообщение после активации промокода + dueTo: + type: integer + description: Дата истечения действия промокода в формате Unix time + activationCount: + type: integer + description: Количество активаций промокода + bonus: type: object - description: История использования промокода для каждого пользователя + description: Бонус + properties: + privilege: + type: object + description: Привилегия + properties: + privilegeID: + type: string + description: Идентификатор привилегии + amount: + type: integer + description: Количество привилегии + discount: + type: object + description: Скидка + properties: + layer: + type: integer + description: Уровень скидки + factor: + type: number + description: Множитель скидки + target: + type: string + description: Слой + threshold: + type: integer + description: Граничное значение + fastLinks: + type: array + items: + type: string + description: Список быстрых ссылок для активации промокода diff --git a/internal/controller/promocode/promocode_controller.go b/internal/controller/promocode/promocode_controller.go index 7e8c642..bc822a0 100644 --- a/internal/controller/promocode/promocode_controller.go +++ b/internal/controller/promocode/promocode_controller.go @@ -50,7 +50,7 @@ func (p *PromoCodeController) CreatePromoCode(c *fiber.Ctx) error { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"}) } - return c.Status(fiber.StatusCreated).JSON(createdPromoCode) + return c.Status(fiber.StatusOK).JSON(createdPromoCode) } func (p *PromoCodeController) EditPromoCode(c *fiber.Ctx) error { @@ -193,6 +193,10 @@ func (p *PromoCodeController) GetStats(c *fiber.Ctx) error { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid request payload"}) } + if req.PromoCodeID == "" { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "PromoCode ID is required"}) + } + promoStats, err := p.promoCodeService.GetStats(c.Context(), req.PromoCodeID) if err != nil { p.logger.Error("Failed getting promo stats", zap.Error(err))