first commit

This commit is contained in:
lendry
2026-06-24 14:37:15 +03:00
commit 995adeedd4
188 changed files with 28810 additions and 0 deletions

View File

@@ -0,0 +1,125 @@
import { Body, Controller, Delete, Get, Param, 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, 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 });
}
@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 });
}
}