Files
IdP/apps/api-gateway/src/controllers/settings.controller.ts
2026-06-24 16:53:06 +03:00

136 lines
7.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Body, Controller, Delete, Get, Param, Post, Put, UseGuards, UsePipes, ValidationPipe } from '@nestjs/common';
import { ApiBearerAuth, ApiBody, ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger';
import { map } from 'rxjs';
import { CoreGrpcService } from '../core-grpc.service';
import { CurrentAdmin } from '../decorators/current-admin.decorator';
import { ConnectLinkedAccountDto, TestMessagingDeliveryDto, UpsertSettingDto, UpsertSocialProviderDto } from '../dto/settings.dto';
import { AdminGuard, AdminRequestUser, assertAdminPermission } from '../guards/admin.guard';
const settingsWritePipe = new ValidationPipe({
whitelist: true,
transform: true,
forbidNonWhitelisted: false
});
@ApiTags('Глобальные настройки')
@ApiBearerAuth()
@UseGuards(AdminGuard)
@Controller('admin/settings')
export class SettingsController {
constructor(private readonly core: CoreGrpcService) {}
@Get()
@ApiOperation({ summary: 'Список системных настроек', description: 'Возвращает динамические настройки, включая PIN timeout и OAuth providers.' })
@ApiResponse({ status: 200, description: 'Список настроек получен' })
list(@CurrentAdmin() admin: AdminRequestUser) {
assertAdminPermission(admin, 'canManageSettings');
return this.core.settings.ListSettings({}).pipe(
map((response) => {
const payload = response as { settings?: unknown[] };
return { settings: payload.settings ?? [] };
})
);
}
@Get('key/:key')
@ApiOperation({ summary: 'Получить настройку', description: 'Возвращает SystemSetting по ключу.' })
@ApiParam({ name: 'key', description: 'Ключ настройки', example: 'PIN_LOCK_TIMEOUT_MINUTES' })
@ApiResponse({ status: 200, description: 'Настройка получена' })
get(@Param('key') key: string, @CurrentAdmin() admin: AdminRequestUser) {
assertAdminPermission(admin, 'canManageSettings');
return this.core.settings.GetSetting({ key });
}
@Put()
@UsePipes(settingsWritePipe)
@ApiOperation({ summary: 'Создать или обновить настройку', description: 'Меняет значение SystemSetting без изменения кода frontend.' })
@ApiBody({ type: UpsertSettingDto })
@ApiResponse({ status: 200, description: 'Настройка создана или обновлена' })
upsert(@Body() dto: UpsertSettingDto, @CurrentAdmin() admin: AdminRequestUser) {
assertAdminPermission(admin, 'canManageSettings');
return this.core.settings.UpsertSetting({
key: dto.key,
value: dto.value,
description: dto.description,
isSecret: dto.isSecret
});
}
@Delete('key/:key')
@ApiOperation({ summary: 'Удалить настройку', description: 'Удаляет SystemSetting по ключу.' })
@ApiParam({ name: 'key', description: 'Ключ настройки' })
@ApiResponse({ status: 200, description: 'Настройка удалена' })
delete(@Param('key') key: string, @CurrentAdmin() admin: AdminRequestUser) {
assertAdminPermission(admin, 'canManageSettings');
return this.core.settings.DeleteSetting({ key });
}
@Get('oauth/providers')
@ApiOperation({ summary: 'Список OAuth провайдеров', description: 'Возвращает глобальные настройки Google/Yandex и других social login providers.' })
@ApiResponse({ status: 200, description: 'Список провайдеров получен' })
listProviders(@CurrentAdmin() admin: AdminRequestUser) {
assertAdminPermission(admin, 'canManageSettings');
return this.core.settings.ListSocialProviders({});
}
@Put('oauth/providers')
@UsePipes(settingsWritePipe)
@ApiOperation({ summary: 'Создать или обновить OAuth провайдера', description: 'Управляет clientId/clientSecret и глобальным включением Google/Yandex входа.' })
@ApiBody({ type: UpsertSocialProviderDto })
@ApiResponse({ status: 200, description: 'Провайдер создан или обновлен' })
upsertProvider(@Body() dto: UpsertSocialProviderDto, @CurrentAdmin() admin: AdminRequestUser) {
assertAdminPermission(admin, 'canManageSettings');
return this.core.settings.UpsertSocialProvider({
providerName: dto.providerName,
clientId: dto.clientId,
clientSecret: dto.clientSecret,
isEnabled: dto.isEnabled
});
}
@Delete('oauth/providers/:providerName')
@ApiOperation({ summary: 'Удалить OAuth провайдера', description: 'Удаляет глобальную настройку social login provider.' })
@ApiParam({ name: 'providerName', description: 'Название провайдера', example: 'google' })
@ApiResponse({ status: 200, description: 'Провайдер удален' })
deleteProvider(@Param('providerName') providerName: string, @CurrentAdmin() admin: AdminRequestUser) {
assertAdminPermission(admin, 'canManageSettings');
return this.core.settings.DeleteSocialProvider({ providerName });
}
@Post('messaging/test')
@UsePipes(settingsWritePipe)
@ApiOperation({ summary: 'Тест email/SMS', description: 'Отправляет тестовый OTP-код через настроенного провайдера.' })
@ApiBody({ type: TestMessagingDeliveryDto })
@ApiResponse({ status: 200, description: 'Тестовое сообщение отправлено' })
testMessaging(@Body() dto: TestMessagingDeliveryDto, @CurrentAdmin() admin: AdminRequestUser) {
assertAdminPermission(admin, 'canManageSettings');
return this.core.settings.TestMessagingDelivery({ channel: dto.channel, target: dto.target });
}
@Get('linked-accounts/users/:userId')
@ApiOperation({ summary: 'Связанные внешние аккаунты', description: 'Возвращает LinkedAccount записи пользователя для Google/Yandex и других провайдеров.' })
@ApiParam({ name: 'userId', description: 'ID пользователя' })
@ApiResponse({ status: 200, description: 'Список внешних аккаунтов получен' })
listLinkedAccounts(@Param('userId') userId: string) {
return this.core.security.ListLinkedAccounts({ userId });
}
@Put('linked-accounts/users/:userId')
@ApiOperation({ summary: 'Подключить внешний аккаунт', description: 'Создает или обновляет LinkedAccount для social OAuth логина пользователя.' })
@ApiParam({ name: 'userId', description: 'ID пользователя' })
@ApiBody({ type: ConnectLinkedAccountDto })
@ApiResponse({ status: 200, description: 'Внешний аккаунт подключен' })
connectLinkedAccount(@Param('userId') userId: string, @Body() dto: ConnectLinkedAccountDto) {
return this.core.security.ConnectLinkedAccount({ userId, ...dto });
}
@Delete('linked-accounts/users/:userId/:providerName')
@ApiOperation({ summary: 'Отключить внешний аккаунт', description: 'Удаляет связь пользователя с Google/Yandex или другим social provider.' })
@ApiParam({ name: 'userId', description: 'ID пользователя' })
@ApiParam({ name: 'providerName', description: 'Название провайдера', example: 'google' })
@ApiResponse({ status: 200, description: 'Внешний аккаунт отключен' })
disconnectLinkedAccount(@Param('userId') userId: string, @Param('providerName') providerName: string) {
return this.core.security.DisconnectLinkedAccount({ userId, providerName });
}
}