85ef2a1c22
🚀 Create and publish a Docker image / Detect changes in backend and frontend (push) Failing after 10m14s
Frontend CI / build-and-check (push) Failing after 16m12s
🚀 Create and publish a Docker image / Build & publish frontend image (push) Failing after 14m7s
🚀 Create and publish a Docker image / Build & publish backend image (push) Failing after 14m59s
🚀 Create and publish a Docker image / Update stack on Portainer (push) Failing after 14m57s
Backend CI / build-and-test (push) Failing after 13m27s
6340 lines
176 KiB
JSON
6340 lines
176 KiB
JSON
{
|
||
"openapi": "3.0.4",
|
||
"info": {
|
||
"title": "UniVerse API",
|
||
"description": "REST API веб-платформы UniVerse.\n\nАутентификация: JWT Bearer (получить через `POST /api/v1/auth/login/microsoft` или `POST /api/v1/auth/login/dev` в Development).",
|
||
"contact": {
|
||
"name": "UniVerse Dev"
|
||
},
|
||
"version": "v1"
|
||
},
|
||
"paths": {
|
||
"/api/v1/achievements": {
|
||
"get": {
|
||
"tags": [
|
||
"Achievements"
|
||
],
|
||
"summary": "Получить список всех достижений.",
|
||
"description": "Возвращает определения достижений (без информации о получении конкретным пользователем).\n Для достижений конкретного пользователя используйте GET /api/v1/users/{id}/achievements.\n\n**Required:** any authenticated user",
|
||
"responses": {
|
||
"200": {
|
||
"description": "Список достижений.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"type": "array",
|
||
"items": {
|
||
"$ref": "#/components/schemas/AchievementDto"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
},
|
||
"post": {
|
||
"tags": [
|
||
"Achievements"
|
||
],
|
||
"summary": "Создать новое достижение.",
|
||
"description": "Только Admin. Достижения автоматически присваиваются студентам при выполнении условий.\n\n**Required roles:** Admin",
|
||
"requestBody": {
|
||
"description": "Название, описание, иконка, награда в XP/монетах и условие получения.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/CreateAchievementRequest"
|
||
}
|
||
},
|
||
"text/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/CreateAchievementRequest"
|
||
}
|
||
},
|
||
"application/*+json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/CreateAchievementRequest"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"201": {
|
||
"description": "Достижение создано.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/AchievementDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/achievements/{id}": {
|
||
"get": {
|
||
"tags": [
|
||
"Achievements"
|
||
],
|
||
"summary": "Получить достижение по ID.",
|
||
"description": "**Required:** any authenticated user",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID достижения.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Данные достижения.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/AchievementDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Достижение не найдено.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
},
|
||
"put": {
|
||
"tags": [
|
||
"Achievements"
|
||
],
|
||
"summary": "Обновить достижение по ID.",
|
||
"description": "Только Admin.\n\n**Required roles:** Admin",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID достижения.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"requestBody": {
|
||
"description": "Обновляемые поля достижения.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UpdateAchievementRequest"
|
||
}
|
||
},
|
||
"text/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UpdateAchievementRequest"
|
||
}
|
||
},
|
||
"application/*+json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UpdateAchievementRequest"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"200": {
|
||
"description": "Обновлённые данные достижения.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/AchievementDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Достижение не найдено.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
},
|
||
"delete": {
|
||
"tags": [
|
||
"Achievements"
|
||
],
|
||
"summary": "Удалить достижение по ID.",
|
||
"description": "Только Admin. Удаление не отзывает достижение у уже получивших его пользователей.\n\n**Required roles:** Admin",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID достижения.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"204": {
|
||
"description": "Достижение удалено."
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Достижение не найдено.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/auth/login/microsoft": {
|
||
"post": {
|
||
"tags": [
|
||
"Auth"
|
||
],
|
||
"summary": "Вход через Microsoft Entra ID (SPA/PKCE flow).",
|
||
"description": "Фронтенд самостоятельно обрабатывает редирект к Microsoft и передаёт сюда\nполученный authorization code. В ответ возвращается пара JWT-токенов;\nrefresh token устанавливается в HttpOnly cookie.",
|
||
"requestBody": {
|
||
"description": "Authorization code и redirect URI из Microsoft OAuth2.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/LoginMicrosoftRequest"
|
||
}
|
||
},
|
||
"text/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/LoginMicrosoftRequest"
|
||
}
|
||
},
|
||
"application/*+json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/LoginMicrosoftRequest"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"200": {
|
||
"description": "Успешный вход — возвращает access token и данные пользователя.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/AuthResponse"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"400": {
|
||
"description": "Неверный или просроченный authorization code.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"get": {
|
||
"tags": [
|
||
"Auth"
|
||
],
|
||
"summary": "Инициация server-driven входа через Microsoft (редирект-flow).",
|
||
"description": "Браузер переходит на этот URL; backend строит Microsoft authorize URL с CSRF state\nи редиректит пользователя на `login.microsoftonline.com`.\nПосле успешного входа Microsoft редиректит на `GET /api/v1/auth/callback/microsoft`.",
|
||
"parameters": [
|
||
{
|
||
"name": "returnUrl",
|
||
"in": "query",
|
||
"description": "URL для редиректа после успешного входа (опционально).",
|
||
"schema": {
|
||
"type": "string"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"302": {
|
||
"description": "Редирект на Microsoft authorize endpoint."
|
||
},
|
||
"500": {
|
||
"description": "Microsoft authentication не настроен (AzureAd:TenantId/ClientId отсутствуют)."
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"/api/v1/auth/callback/microsoft": {
|
||
"get": {
|
||
"tags": [
|
||
"Auth"
|
||
],
|
||
"summary": "OAuth2 callback — обмен code на токены (server-driven flow).",
|
||
"description": "Microsoft редиректит браузер сюда после успешного входа.\nBackend валидирует CSRF state, обменивает code на токены,\nустанавливает refresh token cookie и редиректит на `returnUrl` с access token в URL-фрагменте.",
|
||
"parameters": [
|
||
{
|
||
"name": "code",
|
||
"in": "query",
|
||
"description": "Authorization code от Microsoft.",
|
||
"schema": {
|
||
"type": "string"
|
||
}
|
||
},
|
||
{
|
||
"name": "state",
|
||
"in": "query",
|
||
"description": "CSRF state для верификации.",
|
||
"schema": {
|
||
"type": "string"
|
||
}
|
||
},
|
||
{
|
||
"name": "error",
|
||
"in": "query",
|
||
"description": "Код ошибки от Microsoft (если вход не удался).",
|
||
"schema": {
|
||
"type": "string"
|
||
}
|
||
},
|
||
{
|
||
"name": "error_description",
|
||
"in": "query",
|
||
"description": "Описание ошибки от Microsoft.",
|
||
"schema": {
|
||
"type": "string"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Если returnUrl не задан — возвращает JSON с токенами (удобно для тестирования).",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/AuthResponse"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"302": {
|
||
"description": "Успешный вход — редирект на returnUrl с токеном в URL-фрагменте."
|
||
},
|
||
"400": {
|
||
"description": "Отсутствует authorization code.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Ошибка от Microsoft или невалидный CSRF state.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"/api/v1/auth/login/dev": {
|
||
"post": {
|
||
"tags": [
|
||
"Auth"
|
||
],
|
||
"summary": "Dev-only вход без OAuth (только в Development-окружении).",
|
||
"description": "Создаёт или находит пользователя по email без реального OAuth flow.\nВозвращает 404 в Production и Staging.",
|
||
"requestBody": {
|
||
"description": "Email, отображаемое имя и роль тестового пользователя.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/DevLoginRequest"
|
||
}
|
||
},
|
||
"text/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/DevLoginRequest"
|
||
}
|
||
},
|
||
"application/*+json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/DevLoginRequest"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"200": {
|
||
"description": "Успешный вход.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/AuthResponse"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Endpoint недоступен вне Development.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"/api/v1/auth/refresh": {
|
||
"post": {
|
||
"tags": [
|
||
"Auth"
|
||
],
|
||
"summary": "Обновление access token по refresh token из HttpOnly cookie.",
|
||
"description": "Refresh token читается из HttpOnly cookie `refreshToken` (устанавливается при входе).\nВозвращает новую пару токенов и обновляет cookie.",
|
||
"responses": {
|
||
"200": {
|
||
"description": "Новая пара токенов.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/AuthResponse"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Refresh token отсутствует, просрочен или отозван.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Аккаунт деактивирован или refresh token недействителен.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"/api/v1/auth/logout": {
|
||
"post": {
|
||
"tags": [
|
||
"Auth"
|
||
],
|
||
"summary": "Выход из системы — отзыв refresh token.",
|
||
"description": "Инвалидирует текущий refresh token в БД и удаляет cookie.\nПосле этого вызова access token остаётся валидным до истечения его TTL (30 минут).\n\n**Required:** any authenticated user",
|
||
"responses": {
|
||
"204": {
|
||
"description": "Выход выполнен успешно."
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/auth/me": {
|
||
"get": {
|
||
"tags": [
|
||
"Auth"
|
||
],
|
||
"summary": "Получение профиля текущего авторизованного пользователя.",
|
||
"description": "**Required:** any authenticated user",
|
||
"responses": {
|
||
"200": {
|
||
"description": "Данные текущего пользователя.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/CurrentUserDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Forbidden",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Пользователь не найден в БД (рассинхронизация токена).",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/courses": {
|
||
"get": {
|
||
"tags": [
|
||
"Courses"
|
||
],
|
||
"summary": "Получить список курсов с фильтрацией и пагинацией.",
|
||
"description": "**Required:** any authenticated user",
|
||
"parameters": [
|
||
{
|
||
"name": "TagId",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
{
|
||
"name": "Search",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "string"
|
||
}
|
||
},
|
||
{
|
||
"name": "IsSynced",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "boolean"
|
||
}
|
||
},
|
||
{
|
||
"name": "Page",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
{
|
||
"name": "PageSize",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Список курсов (пагинированный).",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/CourseDtoPagedResult"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
},
|
||
"post": {
|
||
"tags": [
|
||
"Courses"
|
||
],
|
||
"summary": "Создать новый курс.",
|
||
"description": "Только Admin.\n\n**Required roles:** Admin",
|
||
"requestBody": {
|
||
"description": "Название и описание курса.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/CreateCourseRequest"
|
||
}
|
||
},
|
||
"text/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/CreateCourseRequest"
|
||
}
|
||
},
|
||
"application/*+json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/CreateCourseRequest"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"201": {
|
||
"description": "Курс создан.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/CourseDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/courses/{id}": {
|
||
"get": {
|
||
"tags": [
|
||
"Courses"
|
||
],
|
||
"summary": "Получить курс по ID (включая теги).",
|
||
"description": "**Required:** any authenticated user",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID курса.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Данные курса с тегами.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/CourseDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Курс не найден.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
},
|
||
"put": {
|
||
"tags": [
|
||
"Courses"
|
||
],
|
||
"summary": "Обновить курс по ID.",
|
||
"description": "Только Admin.\n\n**Required roles:** Admin",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID курса.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"requestBody": {
|
||
"description": "Новое название и/или описание.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UpdateCourseRequest"
|
||
}
|
||
},
|
||
"text/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UpdateCourseRequest"
|
||
}
|
||
},
|
||
"application/*+json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UpdateCourseRequest"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"200": {
|
||
"description": "Обновлённые данные курса.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/CourseDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Курс не найден.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
},
|
||
"delete": {
|
||
"tags": [
|
||
"Courses"
|
||
],
|
||
"summary": "Удалить курс по ID.",
|
||
"description": "Только Admin. Удаление курса каскадно удаляет связанные лекции.\n\n**Required roles:** Admin",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID курса.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"204": {
|
||
"description": "Курс удалён."
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Курс не найден.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/courses/{id}/tags": {
|
||
"post": {
|
||
"tags": [
|
||
"Courses"
|
||
],
|
||
"summary": "Привязать тег к курсу.",
|
||
"description": "Только Admin. Тег должен существовать в системе.\n\n**Required roles:** Admin",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID курса.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"requestBody": {
|
||
"description": "ID тега.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
"text/json": {
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
"application/*+json": {
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"204": {
|
||
"description": "Тег привязан."
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Курс или тег не найден.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"409": {
|
||
"description": "Тег уже привязан к курсу.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/courses/{id}/tags/{tagId}": {
|
||
"delete": {
|
||
"tags": [
|
||
"Courses"
|
||
],
|
||
"summary": "Отвязать тег от курса.",
|
||
"description": "Только Admin.\n\n**Required roles:** Admin",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID курса.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
{
|
||
"name": "tagId",
|
||
"in": "path",
|
||
"description": "ID тега.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"204": {
|
||
"description": "Тег отвязан."
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Курс или тег не найден, либо связь не существует.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/lectures": {
|
||
"get": {
|
||
"tags": [
|
||
"Lectures"
|
||
],
|
||
"summary": "Получить каталог лекций с фильтрацией и пагинацией.",
|
||
"description": "Включает флаг `isEnrolled` — записан ли текущий пользователь на лекцию.\n\n**Required:** any authenticated user",
|
||
"parameters": [
|
||
{
|
||
"name": "DateFrom",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "string",
|
||
"format": "date"
|
||
}
|
||
},
|
||
{
|
||
"name": "DateTo",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "string",
|
||
"format": "date"
|
||
}
|
||
},
|
||
{
|
||
"name": "CourseId",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
{
|
||
"name": "TeacherId",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
{
|
||
"name": "Format",
|
||
"in": "query",
|
||
"schema": {
|
||
"$ref": "#/components/schemas/LectureFormat"
|
||
}
|
||
},
|
||
{
|
||
"name": "IsOpen",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "boolean"
|
||
}
|
||
},
|
||
{
|
||
"name": "TagId",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
{
|
||
"name": "Search",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "string"
|
||
}
|
||
},
|
||
{
|
||
"name": "Page",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
{
|
||
"name": "PageSize",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Список лекций (пагинированный).",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/LectureDtoPagedResult"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
},
|
||
"post": {
|
||
"tags": [
|
||
"Lectures"
|
||
],
|
||
"summary": "Создать новую лекцию.",
|
||
"description": "Только Admin. Курс задаётся при создании и не может быть изменён.\n\n**Required roles:** Admin",
|
||
"requestBody": {
|
||
"description": "Данные лекции: курс, преподаватель, локация, время, формат, вместимость.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/CreateLectureRequest"
|
||
}
|
||
},
|
||
"text/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/CreateLectureRequest"
|
||
}
|
||
},
|
||
"application/*+json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/CreateLectureRequest"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"201": {
|
||
"description": "Лекция создана.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/LectureDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/lectures/{id}": {
|
||
"get": {
|
||
"tags": [
|
||
"Lectures"
|
||
],
|
||
"summary": "Получить детальную карточку лекции по ID.",
|
||
"description": "Включает флаг `isEnrolled` — записан ли текущий пользователь на эту лекцию.\n\n**Required:** any authenticated user",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID лекции.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Детальные данные лекции.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/LectureDetailDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Лекция не найдена.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
},
|
||
"put": {
|
||
"tags": [
|
||
"Lectures"
|
||
],
|
||
"summary": "Обновить лекцию по ID.",
|
||
"description": "Admin или Teacher. CourseId изменить нельзя.\n\n**Required roles:** Admin, Teacher",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID лекции.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"requestBody": {
|
||
"description": "Обновляемые поля: преподаватель, локация, время, формат, описание.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UpdateLectureRequest"
|
||
}
|
||
},
|
||
"text/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UpdateLectureRequest"
|
||
}
|
||
},
|
||
"application/*+json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UpdateLectureRequest"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"200": {
|
||
"description": "Обновлённые данные лекции.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/LectureDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin или Teacher.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Лекция не найдена.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
},
|
||
"delete": {
|
||
"tags": [
|
||
"Lectures"
|
||
],
|
||
"summary": "Удалить лекцию по ID.",
|
||
"description": "Только Admin. Каскадно удаляет записи и отзывы.\n\n**Required roles:** Admin",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID лекции.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"204": {
|
||
"description": "Лекция удалена."
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Лекция не найдена.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/lectures/{id}/enroll": {
|
||
"post": {
|
||
"tags": [
|
||
"Lectures"
|
||
],
|
||
"summary": "Записаться на лекцию.",
|
||
"description": "Только Student. Проверяет наличие свободных мест и отсутствие повторной записи.\nПосле посещения начисляются монеты через gamification.\n\n**Required roles:** Student",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID лекции.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"204": {
|
||
"description": "Запись выполнена."
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Student.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Лекция не найдена.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"409": {
|
||
"description": "Студент уже записан или мест нет.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
},
|
||
"delete": {
|
||
"tags": [
|
||
"Lectures"
|
||
],
|
||
"summary": "Отменить запись на лекцию.",
|
||
"description": "Только Student. Отменить можно только свою запись.\n\n**Required roles:** Student",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID лекции.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"204": {
|
||
"description": "Запись отменена."
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Student.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Лекция или запись не найдена.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/lectures/{id}/attendance/{userId}": {
|
||
"patch": {
|
||
"tags": [
|
||
"Lectures"
|
||
],
|
||
"summary": "Отметить посещение студента на лекции.",
|
||
"description": "Admin или Teacher. При отметке `attended=true` начисляются монеты за посещение\nчерез gamification service.\n\n**Required roles:** Admin, Teacher",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID лекции.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
{
|
||
"name": "userId",
|
||
"in": "path",
|
||
"description": "ID студента.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"requestBody": {
|
||
"description": "true — посетил, false — не посетил.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"type": "boolean"
|
||
}
|
||
},
|
||
"text/json": {
|
||
"schema": {
|
||
"type": "boolean"
|
||
}
|
||
},
|
||
"application/*+json": {
|
||
"schema": {
|
||
"type": "boolean"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"204": {
|
||
"description": "Посещение отмечено."
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin или Teacher.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Лекция или запись студента не найдена.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/lectures/{id}/enrollments": {
|
||
"get": {
|
||
"tags": [
|
||
"Lectures"
|
||
],
|
||
"summary": "Получить список записавшихся студентов на лекцию.",
|
||
"description": "Только Admin или Teacher. Включает флаг посещения (`attended`).\n\n**Required roles:** Admin, Teacher",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID лекции.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
{
|
||
"name": "Page",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
{
|
||
"name": "PageSize",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Список записей (пагинированный).",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/EnrollmentDtoPagedResult"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin или Teacher.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Лекция не найдена.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/lectures/{id}/reviews": {
|
||
"get": {
|
||
"tags": [
|
||
"Lectures"
|
||
],
|
||
"summary": "Получить отзывы к лекции.",
|
||
"description": "Только Admin или Teacher.\n\n**Required roles:** Admin, Teacher",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID лекции.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
{
|
||
"name": "Page",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
{
|
||
"name": "PageSize",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Список отзывов (пагинированный).",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ReviewDtoPagedResult"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin или Teacher.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Лекция не найдена.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/locations": {
|
||
"get": {
|
||
"tags": [
|
||
"Locations"
|
||
],
|
||
"summary": "Получить список всех локаций.",
|
||
"description": "**Required:** any authenticated user",
|
||
"responses": {
|
||
"200": {
|
||
"description": "Список локаций.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"type": "array",
|
||
"items": {
|
||
"$ref": "#/components/schemas/LocationDto"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
},
|
||
"post": {
|
||
"tags": [
|
||
"Locations"
|
||
],
|
||
"summary": "Создать новую локацию.",
|
||
"description": "Только Admin. Локации также создаются автоматически при синхронизации с Modeus.\n\n**Required roles:** Admin",
|
||
"requestBody": {
|
||
"description": "Название, корпус, аудитория и/или адрес.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/CreateLocationRequest"
|
||
}
|
||
},
|
||
"text/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/CreateLocationRequest"
|
||
}
|
||
},
|
||
"application/*+json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/CreateLocationRequest"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"201": {
|
||
"description": "Локация создана.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/LocationDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/locations/{id}": {
|
||
"get": {
|
||
"tags": [
|
||
"Locations"
|
||
],
|
||
"summary": "Получить локацию по ID.",
|
||
"description": "**Required:** any authenticated user",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID локации.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Данные локации.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/LocationDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Локация не найдена.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
},
|
||
"put": {
|
||
"tags": [
|
||
"Locations"
|
||
],
|
||
"summary": "Обновить локацию по ID.",
|
||
"description": "Только Admin.\n\n**Required roles:** Admin",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID локации.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"requestBody": {
|
||
"description": "Обновляемые поля: название, корпус, аудитория, адрес.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UpdateLocationRequest"
|
||
}
|
||
},
|
||
"text/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UpdateLocationRequest"
|
||
}
|
||
},
|
||
"application/*+json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UpdateLocationRequest"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"200": {
|
||
"description": "Обновлённые данные локации.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/LocationDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Локация не найдена.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
},
|
||
"delete": {
|
||
"tags": [
|
||
"Locations"
|
||
],
|
||
"summary": "Удалить локацию по ID.",
|
||
"description": "Только Admin. При удалении локации у связанных лекций поле `locationId` становится null.\n\n**Required roles:** Admin",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID локации.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"204": {
|
||
"description": "Локация удалена."
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Локация не найдена.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/notifications": {
|
||
"get": {
|
||
"tags": [
|
||
"Notifications"
|
||
],
|
||
"summary": "Получить уведомления текущего пользователя.",
|
||
"description": "**Required:** any authenticated user",
|
||
"parameters": [
|
||
{
|
||
"name": "Page",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
{
|
||
"name": "PageSize",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Список уведомлений.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UserNotificationDtoPagedResult"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/notifications/read-all": {
|
||
"patch": {
|
||
"tags": [
|
||
"Notifications"
|
||
],
|
||
"summary": "Отметить все уведомления текущего пользователя как прочитанные.",
|
||
"description": "**Required:** any authenticated user",
|
||
"responses": {
|
||
"204": {
|
||
"description": "Уведомления отмечены прочитанными."
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/notifications/send": {
|
||
"post": {
|
||
"tags": [
|
||
"Notifications"
|
||
],
|
||
"summary": "Отправить уведомление немедленно.",
|
||
"description": "Канал задаётся строкой, например `email`. Новые провайдеры добавляются через `INotificationProvider`.\n\n**Required roles:** Admin",
|
||
"requestBody": {
|
||
"description": "Канал, получатель, тема и текст уведомления.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/SendNotificationRequest"
|
||
}
|
||
},
|
||
"text/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/SendNotificationRequest"
|
||
}
|
||
},
|
||
"application/*+json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/SendNotificationRequest"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"202": {
|
||
"description": "Уведомление принято к отправке."
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/notifications/schedule": {
|
||
"post": {
|
||
"tags": [
|
||
"Notifications"
|
||
],
|
||
"summary": "Запланировать отложенную отправку уведомления через Quartz.NET.",
|
||
"description": "**Required roles:** Admin",
|
||
"requestBody": {
|
||
"description": "Уведомление и момент отправки.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ScheduleNotificationRequest"
|
||
}
|
||
},
|
||
"text/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ScheduleNotificationRequest"
|
||
}
|
||
},
|
||
"application/*+json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ScheduleNotificationRequest"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"202": {
|
||
"description": "Уведомление поставлено в очередь Quartz.NET.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ScheduledNotificationResponse"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/reviews": {
|
||
"post": {
|
||
"tags": [
|
||
"Reviews"
|
||
],
|
||
"summary": "Создать отзыв к лекции.",
|
||
"description": "Только Student. После создания отзыв отправляется на LLM-анализ\n(статус `Pending`). LLM оценивает содержательность и начисляет монеты\nскрытно от пользователя.\n\n**Required roles:** Student",
|
||
"requestBody": {
|
||
"description": "ID лекции, оценка (Like/Neutral/Dislike) и текст отзыва.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/CreateReviewRequest"
|
||
}
|
||
},
|
||
"text/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/CreateReviewRequest"
|
||
}
|
||
},
|
||
"application/*+json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/CreateReviewRequest"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"201": {
|
||
"description": "Отзыв создан и поставлен в очередь на LLM-анализ.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ReviewDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Student.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Лекция не найдена.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"409": {
|
||
"description": "Студент уже оставил отзыв к этой лекции.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
},
|
||
"get": {
|
||
"tags": [
|
||
"Reviews"
|
||
],
|
||
"summary": "Получить список всех отзывов.",
|
||
"description": "Только Admin. Возвращает все отзывы независимо от LLM-статуса.\n\n**Required roles:** Admin",
|
||
"parameters": [
|
||
{
|
||
"name": "LlmStatus",
|
||
"in": "query",
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ReviewLlmStatus"
|
||
}
|
||
},
|
||
{
|
||
"name": "Page",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
{
|
||
"name": "PageSize",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Список всех отзывов (пагинированный).",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ReviewDtoPagedResult"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/reviews/llm-prompt": {
|
||
"get": {
|
||
"tags": [
|
||
"Reviews"
|
||
],
|
||
"summary": "Получить текущий промпт LLM-анализа отзывов.",
|
||
"description": "Только Admin. Если настройка ещё не сохранена, возвращает базовый промпт.\n\n**Required roles:** Admin",
|
||
"responses": {
|
||
"200": {
|
||
"description": "Текущий шаблон промпта.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ReviewPromptDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
},
|
||
"put": {
|
||
"tags": [
|
||
"Reviews"
|
||
],
|
||
"summary": "Обновить промпт LLM-анализа отзывов.",
|
||
"description": "Только Admin. Промпт применяется к следующим анализам и ручным повторам.\n\n**Required roles:** Admin",
|
||
"requestBody": {
|
||
"description": "Новый шаблон с плейсхолдерами {lectureContext} и {reviewText}.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UpdateReviewPromptRequest"
|
||
}
|
||
},
|
||
"text/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UpdateReviewPromptRequest"
|
||
}
|
||
},
|
||
"application/*+json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UpdateReviewPromptRequest"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"200": {
|
||
"description": "Сохранённый шаблон промпта.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ReviewPromptDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"400": {
|
||
"description": "Промпт пустой или не содержит обязательные плейсхолдеры.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/reviews/{id}": {
|
||
"get": {
|
||
"tags": [
|
||
"Reviews"
|
||
],
|
||
"summary": "Получить отзыв по ID.",
|
||
"description": "Только Admin или Teacher.\n\n**Required roles:** Admin, Teacher",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID отзыва.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Данные отзыва (включая LLM-статус и сентимент).",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ReviewDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin или Teacher.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Отзыв не найден.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
},
|
||
"put": {
|
||
"tags": [
|
||
"Reviews"
|
||
],
|
||
"summary": "Обновить отзыв.",
|
||
"description": "Разрешено любому авторизованному пользователю, но сервис проверяет владельца.\nИзменение текста сбрасывает LLM-статус в `Pending` (повторный анализ).\n\n**Required:** any authenticated user",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID отзыва.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"requestBody": {
|
||
"description": "Новая оценка и/или текст.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UpdateReviewRequest"
|
||
}
|
||
},
|
||
"text/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UpdateReviewRequest"
|
||
}
|
||
},
|
||
"application/*+json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UpdateReviewRequest"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"200": {
|
||
"description": "Обновлённые данные отзыва.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ReviewDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Отзыв принадлежит другому пользователю.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Отзыв не найден.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
},
|
||
"delete": {
|
||
"tags": [
|
||
"Reviews"
|
||
],
|
||
"summary": "Удалить отзыв.",
|
||
"description": "Владелец может удалить свой отзыв. Admin может удалить любой.\n\n**Required:** any authenticated user",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID отзыва.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"204": {
|
||
"description": "Отзыв удалён."
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Нет прав на удаление (не владелец и не Admin).",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Отзыв не найден.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/reviews/{id}/reanalyze": {
|
||
"post": {
|
||
"tags": [
|
||
"Reviews"
|
||
],
|
||
"summary": "Запустить повторный LLM-анализ отзыва.",
|
||
"description": "Только Admin. Сбрасывает статус отзыва на `Pending` и отправляет его\nна повторную обработку.\n\n**Required roles:** Admin",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID отзыва.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"204": {
|
||
"description": "Повторный анализ запланирован."
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Отзыв не найден.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/sync/schedule": {
|
||
"post": {
|
||
"tags": [
|
||
"Sync"
|
||
],
|
||
"summary": "Запустить синхронизацию расписания лекций из Modeus.",
|
||
"description": "Только Admin. Выполняет upsert лекций и связанных курсов на основе данных\nиз внешнего API `schedule.rdcenter.ru`. Поддерживает фильтрацию по периоду,\nразмеру выборки, аудиториям, участникам, реализациям курсов/циклов,\nспециальностям, годам набора, профилям, учебным планам и типам занятий.\n\n**Required roles:** Admin",
|
||
"requestBody": {
|
||
"description": "Параметры поиска событий во внешнем сервисе расписания.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/SyncScheduleRequest"
|
||
}
|
||
},
|
||
"text/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/SyncScheduleRequest"
|
||
}
|
||
},
|
||
"application/*+json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/SyncScheduleRequest"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"200": {
|
||
"description": "Результат синхронизации: кол-во созданных, обновлённых и пропущенных записей.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/SyncResultDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/sync/status": {
|
||
"get": {
|
||
"tags": [
|
||
"Sync"
|
||
],
|
||
"summary": "Получить статус последней синхронизации.",
|
||
"description": "Только Admin. Возвращает время и результат последней успешной синхронизации.\n\n**Required roles:** Admin",
|
||
"responses": {
|
||
"200": {
|
||
"description": "Статус синхронизации.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/SyncStatusDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/sync/rooms": {
|
||
"post": {
|
||
"tags": [
|
||
"Sync"
|
||
],
|
||
"summary": "Синхронизировать аудитории (локации) из Modeus.",
|
||
"description": "Только Admin. Импортирует аудитории из `schedule.rdcenter.ru` и создаёт\nсоответствующие записи в таблице locations.\n\n**Required roles:** Admin",
|
||
"responses": {
|
||
"200": {
|
||
"description": "Результат синхронизации аудиторий.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/SyncResultDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/sync/employees": {
|
||
"post": {
|
||
"tags": [
|
||
"Sync"
|
||
],
|
||
"summary": "Поиск преподавателей в Modeus по ФИО.",
|
||
"description": "Только Admin. Ищет преподавателей через внешнее API и возвращает список\nдля ручного импорта. Найденные преподаватели не создаются автоматически.\n\n**Required roles:** Admin",
|
||
"parameters": [
|
||
{
|
||
"name": "fullname",
|
||
"in": "query",
|
||
"description": "Полное имя или часть имени преподавателя для поиска.",
|
||
"schema": {
|
||
"type": "string"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Список найденных преподавателей.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"type": "array",
|
||
"items": {
|
||
"$ref": "#/components/schemas/EmployeeDto"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/tags": {
|
||
"get": {
|
||
"tags": [
|
||
"Tags"
|
||
],
|
||
"summary": "Получить список тегов с опциональной фильтрацией по типу и родителю.",
|
||
"description": "**Required:** any authenticated user",
|
||
"parameters": [
|
||
{
|
||
"name": "type",
|
||
"in": "query",
|
||
"description": "Тип тега: Institute, Faculty, Subject, Organization, Topic, Other.",
|
||
"schema": {
|
||
"$ref": "#/components/schemas/TagType"
|
||
}
|
||
},
|
||
{
|
||
"name": "parentId",
|
||
"in": "query",
|
||
"description": "ID родительского тега (фильтрация дочерних).",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Список тегов.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"type": "array",
|
||
"items": {
|
||
"$ref": "#/components/schemas/TagDto"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
},
|
||
"post": {
|
||
"tags": [
|
||
"Tags"
|
||
],
|
||
"summary": "Создать новый тег.",
|
||
"description": "Только Admin.\n\n**Required roles:** Admin",
|
||
"requestBody": {
|
||
"description": "Название, тип и опциональный родительский тег.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/CreateTagRequest"
|
||
}
|
||
},
|
||
"text/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/CreateTagRequest"
|
||
}
|
||
},
|
||
"application/*+json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/CreateTagRequest"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"201": {
|
||
"description": "Тег создан.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/TagDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/tags/{id}": {
|
||
"get": {
|
||
"tags": [
|
||
"Tags"
|
||
],
|
||
"summary": "Получить тег по ID.",
|
||
"description": "**Required:** any authenticated user",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID тега.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Данные тега.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/TagDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Тег не найден.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
},
|
||
"put": {
|
||
"tags": [
|
||
"Tags"
|
||
],
|
||
"summary": "Обновить тег по ID.",
|
||
"description": "Только Admin.\n\n**Required roles:** Admin",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID тега.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"requestBody": {
|
||
"description": "Новое название, тип и/или родительский тег.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UpdateTagRequest"
|
||
}
|
||
},
|
||
"text/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UpdateTagRequest"
|
||
}
|
||
},
|
||
"application/*+json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UpdateTagRequest"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"200": {
|
||
"description": "Обновлённые данные тега.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/TagDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Тег не найден.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
},
|
||
"delete": {
|
||
"tags": [
|
||
"Tags"
|
||
],
|
||
"summary": "Удалить тег по ID.",
|
||
"description": "Только Admin. Удаление тега каскадно удаляет привязки к курсам (`course_tags`).\nДочерние теги остаются, но их `parentId` становится null.\n\n**Required roles:** Admin",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID тега.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"204": {
|
||
"description": "Тег удалён."
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Тег не найден.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/tags/tree": {
|
||
"get": {
|
||
"tags": [
|
||
"Tags"
|
||
],
|
||
"summary": "Получить иерархическое дерево всех тегов.",
|
||
"description": "Возвращает корневые теги с вложенными дочерними тегами.\nПолезно для построения фильтрующих UI-компонентов.\n\n**Required:** any authenticated user",
|
||
"responses": {
|
||
"200": {
|
||
"description": "Иерархический список тегов.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"type": "array",
|
||
"items": {
|
||
"$ref": "#/components/schemas/TagTreeDto"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/users/me": {
|
||
"get": {
|
||
"tags": [
|
||
"Users"
|
||
],
|
||
"summary": "Получить профиль текущего пользователя.",
|
||
"description": "**Required:** any authenticated user",
|
||
"responses": {
|
||
"200": {
|
||
"description": "Данные текущего пользователя.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/CurrentUserDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Пользователь не найден.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
},
|
||
"put": {
|
||
"tags": [
|
||
"Users"
|
||
],
|
||
"summary": "Обновить профиль текущего пользователя (displayName, avatarUrl).",
|
||
"description": "**Required:** any authenticated user",
|
||
"requestBody": {
|
||
"description": "Обновляемые поля профиля.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UpdateUserRequest"
|
||
}
|
||
},
|
||
"text/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UpdateUserRequest"
|
||
}
|
||
},
|
||
"application/*+json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UpdateUserRequest"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"200": {
|
||
"description": "Обновлённые данные текущего пользователя.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/CurrentUserDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Пользователь не найден.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/users/me/stats": {
|
||
"get": {
|
||
"tags": [
|
||
"Users"
|
||
],
|
||
"summary": "Получить статистику текущего пользователя.",
|
||
"description": "**Required:** any authenticated user",
|
||
"responses": {
|
||
"200": {
|
||
"description": "Статистика текущего пользователя.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UserStatsDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Пользователь не найден.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/users/me/enrollments": {
|
||
"get": {
|
||
"tags": [
|
||
"Users"
|
||
],
|
||
"summary": "Получить список записей текущего пользователя на лекции.",
|
||
"description": "**Required:** any authenticated user",
|
||
"parameters": [
|
||
{
|
||
"name": "Page",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
{
|
||
"name": "PageSize",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Список записей (пагинированный).",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/LectureDtoPagedResult"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Пользователь не найден.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/users/me/reviews": {
|
||
"get": {
|
||
"tags": [
|
||
"Users"
|
||
],
|
||
"summary": "Получить отзывы текущего пользователя.",
|
||
"description": "**Required:** any authenticated user",
|
||
"parameters": [
|
||
{
|
||
"name": "Page",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
{
|
||
"name": "PageSize",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Список отзывов (пагинированный).",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ReviewDtoPagedResult"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/users/me/achievements": {
|
||
"get": {
|
||
"tags": [
|
||
"Users"
|
||
],
|
||
"summary": "Получить достижения текущего пользователя.",
|
||
"description": "**Required:** any authenticated user",
|
||
"responses": {
|
||
"200": {
|
||
"description": "Список полученных достижений.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"type": "array",
|
||
"items": {
|
||
"$ref": "#/components/schemas/UserAchievementDto"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/users/me/transactions": {
|
||
"get": {
|
||
"tags": [
|
||
"Users"
|
||
],
|
||
"summary": "Получить историю транзакций монет текущего пользователя.",
|
||
"description": "**Required:** any authenticated user",
|
||
"parameters": [
|
||
{
|
||
"name": "Page",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
{
|
||
"name": "PageSize",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "История транзакций (пагинированная).",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/CoinTransactionDtoPagedResult"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/users/{id}": {
|
||
"get": {
|
||
"tags": [
|
||
"Users"
|
||
],
|
||
"summary": "Получить профиль пользователя по ID.",
|
||
"description": "Только Admin. Для текущего пользователя используйте GET /api/v1/users/me.\n\n**Required roles:** Admin",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID пользователя.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Данные пользователя.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UserDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Пользователь не найден.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
},
|
||
"put": {
|
||
"tags": [
|
||
"Users"
|
||
],
|
||
"summary": "Обновить профиль пользователя (displayName, avatarUrl).",
|
||
"description": "Только Admin. Для текущего пользователя используйте PUT /api/v1/users/me.\n\n**Required roles:** Admin",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID пользователя.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"requestBody": {
|
||
"description": "Обновляемые поля профиля.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UpdateUserRequest"
|
||
}
|
||
},
|
||
"text/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UpdateUserRequest"
|
||
}
|
||
},
|
||
"application/*+json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UpdateUserRequest"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"200": {
|
||
"description": "Обновлённые данные пользователя.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UserDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Пользователь не найден.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/users/{id}/stats": {
|
||
"get": {
|
||
"tags": [
|
||
"Users"
|
||
],
|
||
"summary": "Получить статистику пользователя (XP, монеты, уровень, посещения).",
|
||
"description": "Только Admin. Для текущего пользователя используйте GET /api/v1/users/me/stats.\n\n**Required roles:** Admin",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID пользователя.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Статистика пользователя.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UserStatsDto"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Пользователь не найден.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/users/{id}/enrollments": {
|
||
"get": {
|
||
"tags": [
|
||
"Users"
|
||
],
|
||
"summary": "Получить список записей пользователя на лекции.",
|
||
"description": "Только Admin. Для текущего пользователя используйте GET /api/v1/users/me/enrollments.\n\n**Required roles:** Admin",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID пользователя.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
{
|
||
"name": "Page",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
{
|
||
"name": "PageSize",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Список записей (пагинированный).",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/LectureDtoPagedResult"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Пользователь не найден.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/users/{id}/reviews": {
|
||
"get": {
|
||
"tags": [
|
||
"Users"
|
||
],
|
||
"summary": "Получить отзывы пользователя.",
|
||
"description": "Только Admin. Для текущего пользователя используйте GET /api/v1/users/me/reviews.\n\n**Required roles:** Admin",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID пользователя.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
{
|
||
"name": "Page",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
{
|
||
"name": "PageSize",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Список отзывов (пагинированный).",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ReviewDtoPagedResult"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/users/{id}/achievements": {
|
||
"get": {
|
||
"tags": [
|
||
"Users"
|
||
],
|
||
"summary": "Получить достижения пользователя.",
|
||
"description": "Только Admin. Для текущего пользователя используйте GET /api/v1/users/me/achievements.\n\n**Required roles:** Admin",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID пользователя.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Список полученных достижений.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"type": "array",
|
||
"items": {
|
||
"$ref": "#/components/schemas/UserAchievementDto"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/users/{id}/transactions": {
|
||
"get": {
|
||
"tags": [
|
||
"Users"
|
||
],
|
||
"summary": "Получить историю транзакций монет пользователя.",
|
||
"description": "Только Admin. Для текущего пользователя используйте GET /api/v1/users/me/transactions.\n\n**Required roles:** Admin",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID пользователя.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
{
|
||
"name": "Page",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
{
|
||
"name": "PageSize",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "История транзакций (пагинированная).",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/CoinTransactionDtoPagedResult"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/users": {
|
||
"get": {
|
||
"tags": [
|
||
"Users"
|
||
],
|
||
"summary": "Получить список всех пользователей с фильтрацией и пагинацией.",
|
||
"description": "Только Admin.\n\n**Required roles:** Admin",
|
||
"parameters": [
|
||
{
|
||
"name": "Search",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "string"
|
||
}
|
||
},
|
||
{
|
||
"name": "Role",
|
||
"in": "query",
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UserRole"
|
||
}
|
||
},
|
||
{
|
||
"name": "IsActive",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "boolean"
|
||
}
|
||
},
|
||
{
|
||
"name": "Page",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
{
|
||
"name": "PageSize",
|
||
"in": "query",
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"responses": {
|
||
"200": {
|
||
"description": "Список пользователей (пагинированный).",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/UserDtoPagedResult"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/users/{id}/role": {
|
||
"patch": {
|
||
"tags": [
|
||
"Users"
|
||
],
|
||
"summary": "Изменить набор ролей пользователя.",
|
||
"description": "Только Admin. Доступные роли: Student, Teacher, Admin.\n\n**Required roles:** Admin",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID пользователя.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"requestBody": {
|
||
"description": "Новый набор ролей пользователя.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"type": "array",
|
||
"items": {
|
||
"$ref": "#/components/schemas/UserRole"
|
||
}
|
||
}
|
||
},
|
||
"text/json": {
|
||
"schema": {
|
||
"type": "array",
|
||
"items": {
|
||
"$ref": "#/components/schemas/UserRole"
|
||
}
|
||
}
|
||
},
|
||
"application/*+json": {
|
||
"schema": {
|
||
"type": "array",
|
||
"items": {
|
||
"$ref": "#/components/schemas/UserRole"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"204": {
|
||
"description": "Роли успешно изменены."
|
||
},
|
||
"400": {
|
||
"description": "Bad Request",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Пользователь не найден.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"/api/v1/users/{id}/active": {
|
||
"patch": {
|
||
"tags": [
|
||
"Users"
|
||
],
|
||
"summary": "Активировать или деактивировать аккаунт пользователя.",
|
||
"description": "Только Admin. Деактивированный пользователь не может войти в систему.\n\n**Required roles:** Admin",
|
||
"parameters": [
|
||
{
|
||
"name": "id",
|
||
"in": "path",
|
||
"description": "ID пользователя.",
|
||
"required": true,
|
||
"schema": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
}
|
||
],
|
||
"requestBody": {
|
||
"description": "true — активировать, false — деактивировать.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"type": "boolean"
|
||
}
|
||
},
|
||
"text/json": {
|
||
"schema": {
|
||
"type": "boolean"
|
||
}
|
||
},
|
||
"application/*+json": {
|
||
"schema": {
|
||
"type": "boolean"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"responses": {
|
||
"204": {
|
||
"description": "Статус успешно изменён."
|
||
},
|
||
"401": {
|
||
"description": "Требуется аутентификация.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"403": {
|
||
"description": "Требуется роль Admin.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"404": {
|
||
"description": "Пользователь не найден.",
|
||
"content": {
|
||
"application/json": {
|
||
"schema": {
|
||
"$ref": "#/components/schemas/ProblemDetails"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"security": [
|
||
{
|
||
"Bearer": [ ]
|
||
}
|
||
]
|
||
}
|
||
}
|
||
},
|
||
"components": {
|
||
"schemas": {
|
||
"AchievementDto": {
|
||
"type": "object",
|
||
"properties": {
|
||
"id": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"name": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"description": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"iconUrl": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"xpReward": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"coinReward": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"condition": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"createdAt": {
|
||
"type": "string",
|
||
"format": "date-time"
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"AuthResponse": {
|
||
"type": "object",
|
||
"properties": {
|
||
"accessToken": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"expiresAt": {
|
||
"type": "string",
|
||
"format": "date-time"
|
||
},
|
||
"user": {
|
||
"$ref": "#/components/schemas/UserAuthDto"
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"CoinTransactionDto": {
|
||
"type": "object",
|
||
"properties": {
|
||
"id": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"amount": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"type": {
|
||
"$ref": "#/components/schemas/CoinTransactionType"
|
||
},
|
||
"reviewId": {
|
||
"type": "integer",
|
||
"format": "int32",
|
||
"nullable": true
|
||
},
|
||
"achievementId": {
|
||
"type": "integer",
|
||
"format": "int32",
|
||
"nullable": true
|
||
},
|
||
"description": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"createdAt": {
|
||
"type": "string",
|
||
"format": "date-time"
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"CoinTransactionDtoPagedResult": {
|
||
"type": "object",
|
||
"properties": {
|
||
"items": {
|
||
"type": "array",
|
||
"items": {
|
||
"$ref": "#/components/schemas/CoinTransactionDto"
|
||
},
|
||
"nullable": true
|
||
},
|
||
"totalCount": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"page": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"pageSize": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"totalPages": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"CoinTransactionType": {
|
||
"enum": [
|
||
"ReviewReward",
|
||
"AchievementReward",
|
||
"AttendanceReward",
|
||
"AdminAdjustment"
|
||
],
|
||
"type": "string"
|
||
},
|
||
"CourseDto": {
|
||
"type": "object",
|
||
"properties": {
|
||
"id": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"name": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"description": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"isSynced": {
|
||
"type": "boolean"
|
||
},
|
||
"tags": {
|
||
"type": "array",
|
||
"items": {
|
||
"$ref": "#/components/schemas/TagDto"
|
||
},
|
||
"nullable": true
|
||
},
|
||
"createdAt": {
|
||
"type": "string",
|
||
"format": "date-time"
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"CourseDtoPagedResult": {
|
||
"type": "object",
|
||
"properties": {
|
||
"items": {
|
||
"type": "array",
|
||
"items": {
|
||
"$ref": "#/components/schemas/CourseDto"
|
||
},
|
||
"nullable": true
|
||
},
|
||
"totalCount": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"page": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"pageSize": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"totalPages": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"CreateAchievementRequest": {
|
||
"type": "object",
|
||
"properties": {
|
||
"name": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"description": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"iconUrl": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"xpReward": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"coinReward": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"condition": {
|
||
"type": "string",
|
||
"nullable": true
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"CreateCourseRequest": {
|
||
"type": "object",
|
||
"properties": {
|
||
"name": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"description": {
|
||
"type": "string",
|
||
"nullable": true
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"CreateLectureRequest": {
|
||
"type": "object",
|
||
"properties": {
|
||
"courseId": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"teacherId": {
|
||
"type": "integer",
|
||
"format": "int32",
|
||
"nullable": true
|
||
},
|
||
"locationId": {
|
||
"type": "integer",
|
||
"format": "int32",
|
||
"nullable": true
|
||
},
|
||
"title": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"description": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"format": {
|
||
"$ref": "#/components/schemas/LectureFormat"
|
||
},
|
||
"startsAt": {
|
||
"type": "string",
|
||
"format": "date-time"
|
||
},
|
||
"endsAt": {
|
||
"type": "string",
|
||
"format": "date-time"
|
||
},
|
||
"isOpen": {
|
||
"type": "boolean"
|
||
},
|
||
"maxEnrollments": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"onlineUrl": {
|
||
"type": "string",
|
||
"nullable": true
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"CreateLocationRequest": {
|
||
"type": "object",
|
||
"properties": {
|
||
"name": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"building": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"room": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"address": {
|
||
"type": "string",
|
||
"nullable": true
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"CreateReviewRequest": {
|
||
"type": "object",
|
||
"properties": {
|
||
"lectureId": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"rating": {
|
||
"$ref": "#/components/schemas/ReviewRating"
|
||
},
|
||
"text": {
|
||
"type": "string",
|
||
"nullable": true
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"CreateTagRequest": {
|
||
"type": "object",
|
||
"properties": {
|
||
"name": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"type": {
|
||
"$ref": "#/components/schemas/TagType"
|
||
},
|
||
"parentId": {
|
||
"type": "integer",
|
||
"format": "int32",
|
||
"nullable": true
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"CurrentUserDto": {
|
||
"type": "object",
|
||
"properties": {
|
||
"id": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"email": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"displayName": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"avatarUrl": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"roles": {
|
||
"type": "array",
|
||
"items": {
|
||
"$ref": "#/components/schemas/UserRole"
|
||
},
|
||
"nullable": true
|
||
},
|
||
"xp": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"coins": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"level": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"createdAt": {
|
||
"type": "string",
|
||
"format": "date-time"
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"DevLoginRequest": {
|
||
"type": "object",
|
||
"properties": {
|
||
"email": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"displayName": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"roles": {
|
||
"type": "array",
|
||
"items": {
|
||
"$ref": "#/components/schemas/UserRole"
|
||
},
|
||
"nullable": true
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"EmployeeDto": {
|
||
"type": "object",
|
||
"properties": {
|
||
"id": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"fullName": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"department": {
|
||
"type": "string",
|
||
"nullable": true
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"EnrollmentDto": {
|
||
"type": "object",
|
||
"properties": {
|
||
"id": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"userId": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"userName": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"userEmail": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"attended": {
|
||
"type": "boolean"
|
||
},
|
||
"createdAt": {
|
||
"type": "string",
|
||
"format": "date-time"
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"EnrollmentDtoPagedResult": {
|
||
"type": "object",
|
||
"properties": {
|
||
"items": {
|
||
"type": "array",
|
||
"items": {
|
||
"$ref": "#/components/schemas/EnrollmentDto"
|
||
},
|
||
"nullable": true
|
||
},
|
||
"totalCount": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"page": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"pageSize": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"totalPages": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"EnrollmentSlotRuleDto": {
|
||
"type": "object",
|
||
"properties": {
|
||
"level": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"slots": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"LectureDetailDto": {
|
||
"type": "object",
|
||
"properties": {
|
||
"id": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"courseId": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"courseName": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"teacherId": {
|
||
"type": "integer",
|
||
"format": "int32",
|
||
"nullable": true
|
||
},
|
||
"teacherName": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"locationId": {
|
||
"type": "integer",
|
||
"format": "int32",
|
||
"nullable": true
|
||
},
|
||
"locationName": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"title": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"description": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"format": {
|
||
"$ref": "#/components/schemas/LectureFormat"
|
||
},
|
||
"startsAt": {
|
||
"type": "string",
|
||
"format": "date-time"
|
||
},
|
||
"endsAt": {
|
||
"type": "string",
|
||
"format": "date-time"
|
||
},
|
||
"isOpen": {
|
||
"type": "boolean"
|
||
},
|
||
"maxEnrollments": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"enrollmentsCount": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"onlineUrl": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"createdAt": {
|
||
"type": "string",
|
||
"format": "date-time"
|
||
},
|
||
"isEnrolled": {
|
||
"type": "boolean"
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"LectureDto": {
|
||
"type": "object",
|
||
"properties": {
|
||
"id": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"courseId": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"courseName": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"teacherId": {
|
||
"type": "integer",
|
||
"format": "int32",
|
||
"nullable": true
|
||
},
|
||
"teacherName": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"locationId": {
|
||
"type": "integer",
|
||
"format": "int32",
|
||
"nullable": true
|
||
},
|
||
"locationName": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"title": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"description": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"format": {
|
||
"$ref": "#/components/schemas/LectureFormat"
|
||
},
|
||
"startsAt": {
|
||
"type": "string",
|
||
"format": "date-time"
|
||
},
|
||
"endsAt": {
|
||
"type": "string",
|
||
"format": "date-time"
|
||
},
|
||
"isOpen": {
|
||
"type": "boolean"
|
||
},
|
||
"maxEnrollments": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"enrollmentsCount": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"onlineUrl": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"createdAt": {
|
||
"type": "string",
|
||
"format": "date-time"
|
||
},
|
||
"isEnrolled": {
|
||
"type": "boolean"
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"LectureDtoPagedResult": {
|
||
"type": "object",
|
||
"properties": {
|
||
"items": {
|
||
"type": "array",
|
||
"items": {
|
||
"$ref": "#/components/schemas/LectureDto"
|
||
},
|
||
"nullable": true
|
||
},
|
||
"totalCount": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"page": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"pageSize": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"totalPages": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"LectureFormat": {
|
||
"enum": [
|
||
"Online",
|
||
"Offline"
|
||
],
|
||
"type": "string"
|
||
},
|
||
"LocationDto": {
|
||
"type": "object",
|
||
"properties": {
|
||
"id": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"name": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"building": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"room": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"address": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"createdAt": {
|
||
"type": "string",
|
||
"format": "date-time"
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"LoginMicrosoftRequest": {
|
||
"type": "object",
|
||
"properties": {
|
||
"authorizationCode": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"redirectUri": {
|
||
"type": "string",
|
||
"nullable": true
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"ProblemDetails": {
|
||
"type": "object",
|
||
"properties": {
|
||
"type": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"title": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"status": {
|
||
"type": "integer",
|
||
"format": "int32",
|
||
"nullable": true
|
||
},
|
||
"detail": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"instance": {
|
||
"type": "string",
|
||
"nullable": true
|
||
}
|
||
},
|
||
"additionalProperties": { }
|
||
},
|
||
"ReviewDto": {
|
||
"type": "object",
|
||
"properties": {
|
||
"id": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"lectureId": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"lectureTitle": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"userId": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"userName": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"rating": {
|
||
"$ref": "#/components/schemas/ReviewRating"
|
||
},
|
||
"text": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"llmStatus": {
|
||
"$ref": "#/components/schemas/ReviewLlmStatus"
|
||
},
|
||
"sentiment": {
|
||
"$ref": "#/components/schemas/ReviewSentiment"
|
||
},
|
||
"qualityScore": {
|
||
"type": "number",
|
||
"format": "double",
|
||
"nullable": true
|
||
},
|
||
"isInformative": {
|
||
"type": "boolean",
|
||
"nullable": true
|
||
},
|
||
"llmTags": {
|
||
"type": "array",
|
||
"items": {
|
||
"type": "string"
|
||
},
|
||
"nullable": true
|
||
},
|
||
"llmRawOutput": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"createdAt": {
|
||
"type": "string",
|
||
"format": "date-time"
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"ReviewDtoPagedResult": {
|
||
"type": "object",
|
||
"properties": {
|
||
"items": {
|
||
"type": "array",
|
||
"items": {
|
||
"$ref": "#/components/schemas/ReviewDto"
|
||
},
|
||
"nullable": true
|
||
},
|
||
"totalCount": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"page": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"pageSize": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"totalPages": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"ReviewLlmStatus": {
|
||
"enum": [
|
||
"Pending",
|
||
"Analyzed",
|
||
"Rejected"
|
||
],
|
||
"type": "string"
|
||
},
|
||
"ReviewPromptDto": {
|
||
"type": "object",
|
||
"properties": {
|
||
"prompt": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"updatedAt": {
|
||
"type": "string",
|
||
"format": "date-time",
|
||
"nullable": true
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"ReviewRating": {
|
||
"enum": [
|
||
"Like",
|
||
"Neutral",
|
||
"Dislike"
|
||
],
|
||
"type": "string"
|
||
},
|
||
"ReviewSentiment": {
|
||
"enum": [
|
||
"Positive",
|
||
"Neutral",
|
||
"Negative"
|
||
],
|
||
"type": "string"
|
||
},
|
||
"ScheduleNotificationRequest": {
|
||
"type": "object",
|
||
"properties": {
|
||
"channel": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"recipient": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"subject": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"body": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"sendAt": {
|
||
"type": "string",
|
||
"format": "date-time"
|
||
},
|
||
"recipientName": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"metadata": {
|
||
"type": "object",
|
||
"additionalProperties": {
|
||
"type": "string"
|
||
},
|
||
"nullable": true
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"ScheduledNotificationResponse": {
|
||
"type": "object",
|
||
"properties": {
|
||
"jobId": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"sendAt": {
|
||
"type": "string",
|
||
"format": "date-time"
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"SendNotificationRequest": {
|
||
"type": "object",
|
||
"properties": {
|
||
"channel": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"recipient": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"subject": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"body": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"recipientName": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"metadata": {
|
||
"type": "object",
|
||
"additionalProperties": {
|
||
"type": "string"
|
||
},
|
||
"nullable": true
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"SyncResultDto": {
|
||
"type": "object",
|
||
"properties": {
|
||
"created": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"updated": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"skipped": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"error": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"details": {
|
||
"type": "array",
|
||
"items": {
|
||
"type": "string"
|
||
},
|
||
"nullable": true
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"SyncScheduleRequest": {
|
||
"type": "object",
|
||
"properties": {
|
||
"specialtyCode": {
|
||
"type": "array",
|
||
"items": {
|
||
"type": "string"
|
||
},
|
||
"nullable": true
|
||
},
|
||
"timeMin": {
|
||
"type": "string",
|
||
"format": "date-time",
|
||
"nullable": true
|
||
},
|
||
"timeMax": {
|
||
"type": "string",
|
||
"format": "date-time",
|
||
"nullable": true
|
||
},
|
||
"typeId": {
|
||
"type": "array",
|
||
"items": {
|
||
"type": "string"
|
||
},
|
||
"nullable": true
|
||
},
|
||
"size": {
|
||
"type": "integer",
|
||
"format": "int32",
|
||
"nullable": true
|
||
},
|
||
"roomId": {
|
||
"type": "array",
|
||
"items": {
|
||
"type": "string"
|
||
},
|
||
"nullable": true
|
||
},
|
||
"attendeePersonId": {
|
||
"type": "array",
|
||
"items": {
|
||
"type": "string"
|
||
},
|
||
"nullable": true
|
||
},
|
||
"courseUnitRealizationId": {
|
||
"type": "array",
|
||
"items": {
|
||
"type": "string"
|
||
},
|
||
"nullable": true
|
||
},
|
||
"cycleRealizationId": {
|
||
"type": "array",
|
||
"items": {
|
||
"type": "string"
|
||
},
|
||
"nullable": true
|
||
},
|
||
"learningStartYear": {
|
||
"type": "array",
|
||
"items": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"nullable": true
|
||
},
|
||
"profileName": {
|
||
"type": "array",
|
||
"items": {
|
||
"type": "string"
|
||
},
|
||
"nullable": true
|
||
},
|
||
"curriculumId": {
|
||
"type": "array",
|
||
"items": {
|
||
"type": "string"
|
||
},
|
||
"nullable": true
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"SyncStatusDto": {
|
||
"type": "object",
|
||
"properties": {
|
||
"lastSyncAt": {
|
||
"type": "string",
|
||
"format": "date-time",
|
||
"nullable": true
|
||
},
|
||
"status": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"lastResult": {
|
||
"$ref": "#/components/schemas/SyncResultDto"
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"TagDto": {
|
||
"type": "object",
|
||
"properties": {
|
||
"id": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"name": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"type": {
|
||
"$ref": "#/components/schemas/TagType"
|
||
},
|
||
"parentId": {
|
||
"type": "integer",
|
||
"format": "int32",
|
||
"nullable": true
|
||
},
|
||
"createdAt": {
|
||
"type": "string",
|
||
"format": "date-time"
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"TagTreeDto": {
|
||
"type": "object",
|
||
"properties": {
|
||
"id": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"name": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"type": {
|
||
"$ref": "#/components/schemas/TagType"
|
||
},
|
||
"children": {
|
||
"type": "array",
|
||
"items": {
|
||
"$ref": "#/components/schemas/TagTreeDto"
|
||
},
|
||
"nullable": true
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"TagType": {
|
||
"enum": [
|
||
"Institute",
|
||
"Faculty",
|
||
"Subject",
|
||
"Organization",
|
||
"Topic",
|
||
"Other"
|
||
],
|
||
"type": "string"
|
||
},
|
||
"UpdateAchievementRequest": {
|
||
"type": "object",
|
||
"properties": {
|
||
"name": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"description": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"iconUrl": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"xpReward": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"coinReward": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"condition": {
|
||
"type": "string",
|
||
"nullable": true
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"UpdateCourseRequest": {
|
||
"type": "object",
|
||
"properties": {
|
||
"name": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"description": {
|
||
"type": "string",
|
||
"nullable": true
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"UpdateLectureRequest": {
|
||
"type": "object",
|
||
"properties": {
|
||
"teacherId": {
|
||
"type": "integer",
|
||
"format": "int32",
|
||
"nullable": true
|
||
},
|
||
"locationId": {
|
||
"type": "integer",
|
||
"format": "int32",
|
||
"nullable": true
|
||
},
|
||
"title": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"description": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"format": {
|
||
"$ref": "#/components/schemas/LectureFormat"
|
||
},
|
||
"startsAt": {
|
||
"type": "string",
|
||
"format": "date-time"
|
||
},
|
||
"endsAt": {
|
||
"type": "string",
|
||
"format": "date-time"
|
||
},
|
||
"isOpen": {
|
||
"type": "boolean"
|
||
},
|
||
"maxEnrollments": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"onlineUrl": {
|
||
"type": "string",
|
||
"nullable": true
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"UpdateLocationRequest": {
|
||
"type": "object",
|
||
"properties": {
|
||
"name": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"building": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"room": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"address": {
|
||
"type": "string",
|
||
"nullable": true
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"UpdateReviewPromptRequest": {
|
||
"type": "object",
|
||
"properties": {
|
||
"prompt": {
|
||
"type": "string",
|
||
"nullable": true
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"UpdateReviewRequest": {
|
||
"type": "object",
|
||
"properties": {
|
||
"rating": {
|
||
"$ref": "#/components/schemas/ReviewRating"
|
||
},
|
||
"text": {
|
||
"type": "string",
|
||
"nullable": true
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"UpdateTagRequest": {
|
||
"type": "object",
|
||
"properties": {
|
||
"name": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"type": {
|
||
"$ref": "#/components/schemas/TagType"
|
||
},
|
||
"parentId": {
|
||
"type": "integer",
|
||
"format": "int32",
|
||
"nullable": true
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"UpdateUserRequest": {
|
||
"type": "object",
|
||
"properties": {
|
||
"displayName": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"avatarUrl": {
|
||
"type": "string",
|
||
"nullable": true
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"UserAchievementDto": {
|
||
"type": "object",
|
||
"properties": {
|
||
"id": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"achievement": {
|
||
"$ref": "#/components/schemas/AchievementDto"
|
||
},
|
||
"awardedAt": {
|
||
"type": "string",
|
||
"format": "date-time"
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"UserAuthDto": {
|
||
"type": "object",
|
||
"properties": {
|
||
"id": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"email": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"displayName": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"roles": {
|
||
"type": "array",
|
||
"items": {
|
||
"$ref": "#/components/schemas/UserRole"
|
||
},
|
||
"nullable": true
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"UserDto": {
|
||
"type": "object",
|
||
"properties": {
|
||
"id": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"email": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"displayName": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"avatarUrl": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"roles": {
|
||
"type": "array",
|
||
"items": {
|
||
"$ref": "#/components/schemas/UserRole"
|
||
},
|
||
"nullable": true
|
||
},
|
||
"isActive": {
|
||
"type": "boolean"
|
||
},
|
||
"xp": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"coins": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"level": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"createdAt": {
|
||
"type": "string",
|
||
"format": "date-time"
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"UserDtoPagedResult": {
|
||
"type": "object",
|
||
"properties": {
|
||
"items": {
|
||
"type": "array",
|
||
"items": {
|
||
"$ref": "#/components/schemas/UserDto"
|
||
},
|
||
"nullable": true
|
||
},
|
||
"totalCount": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"page": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"pageSize": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"totalPages": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"UserNotificationDto": {
|
||
"type": "object",
|
||
"properties": {
|
||
"id": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"type": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"title": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"body": {
|
||
"type": "string",
|
||
"nullable": true
|
||
},
|
||
"isRead": {
|
||
"type": "boolean"
|
||
},
|
||
"createdAt": {
|
||
"type": "string",
|
||
"format": "date-time"
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"UserNotificationDtoPagedResult": {
|
||
"type": "object",
|
||
"properties": {
|
||
"items": {
|
||
"type": "array",
|
||
"items": {
|
||
"$ref": "#/components/schemas/UserNotificationDto"
|
||
},
|
||
"nullable": true
|
||
},
|
||
"totalCount": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"page": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"pageSize": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"totalPages": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
},
|
||
"UserRole": {
|
||
"enum": [
|
||
"Student",
|
||
"Teacher",
|
||
"Admin"
|
||
],
|
||
"type": "string"
|
||
},
|
||
"UserStatsDto": {
|
||
"type": "object",
|
||
"properties": {
|
||
"totalLectures": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"attendedLectures": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"totalReviews": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"xp": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"coins": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"level": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"achievementsCount": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"currentLevelXp": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"nextLevelXp": {
|
||
"type": "integer",
|
||
"format": "int32",
|
||
"nullable": true
|
||
},
|
||
"activeEnrollments": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"enrollmentSlotLimit": {
|
||
"type": "integer",
|
||
"format": "int32"
|
||
},
|
||
"enrollmentSlotRules": {
|
||
"type": "array",
|
||
"items": {
|
||
"$ref": "#/components/schemas/EnrollmentSlotRuleDto"
|
||
},
|
||
"nullable": true
|
||
}
|
||
},
|
||
"additionalProperties": false
|
||
}
|
||
},
|
||
"securitySchemes": {
|
||
"Bearer": {
|
||
"type": "http",
|
||
"description": "Введите JWT access token, полученный из `/api/v1/auth/login/microsoft`.\n\nПример: `eyJhbGci...`",
|
||
"scheme": "bearer",
|
||
"bearerFormat": "JWT"
|
||
}
|
||
}
|
||
},
|
||
"tags": [
|
||
{
|
||
"name": "Achievements"
|
||
},
|
||
{
|
||
"name": "Auth"
|
||
},
|
||
{
|
||
"name": "Courses"
|
||
},
|
||
{
|
||
"name": "Lectures"
|
||
},
|
||
{
|
||
"name": "Locations"
|
||
},
|
||
{
|
||
"name": "Notifications"
|
||
},
|
||
{
|
||
"name": "Reviews"
|
||
},
|
||
{
|
||
"name": "Sync"
|
||
},
|
||
{
|
||
"name": "Tags"
|
||
},
|
||
{
|
||
"name": "Users"
|
||
}
|
||
]
|
||
} |