fix and update
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
import { Body, Controller, ForbiddenException, Get, Param, Patch, Post, Query, UseGuards } from '@nestjs/common';
|
||||
import { BadRequestException, Body, Controller, Delete, ForbiddenException, Get, Param, Patch, Post, Query, UseGuards } from '@nestjs/common';
|
||||
import { ApiBearerAuth, ApiBody, ApiOperation, ApiParam, ApiTags } from '@nestjs/swagger';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { map } from 'rxjs';
|
||||
import { CoreGrpcService } from '../core-grpc.service';
|
||||
import { CurrentAdmin } from '../decorators/current-admin.decorator';
|
||||
import { ListUsersQueryDto, ResetPasswordDto, SetSuperAdminDto, SetUserVerificationDto, UpdateUserDto } from '../dto/admin.dto';
|
||||
import { ListUsersQueryDto, ResetPasswordDto, SetSuperAdminDto, SetUserVerificationDto, UpdateUserDto, UserInsightsQueryDto } from '../dto/admin.dto';
|
||||
import { AdminGuard, AdminRequestUser, assertAdminPermission, SuperAdminGuard } from '../guards/admin.guard';
|
||||
|
||||
@ApiTags('Администрирование')
|
||||
@@ -124,4 +124,112 @@ export class AdminController {
|
||||
verificationIcon: dto.verificationIcon
|
||||
});
|
||||
}
|
||||
|
||||
@Get(':userId/sign-in-history')
|
||||
@ApiOperation({ summary: 'История входов пользователя', description: 'Журнал SignInEvent с поиском по IP, устройству и причине.' })
|
||||
getUserSignInHistory(@Param('userId') userId: string, @Query() query: UserInsightsQueryDto, @CurrentAdmin() admin: AdminRequestUser) {
|
||||
if (!admin.canViewUsers && !admin.canManageUsers) {
|
||||
throw new ForbiddenException('Недостаточно прав для просмотра журнала пользователя');
|
||||
}
|
||||
return firstValueFrom(
|
||||
this.core.admin.GetUserSignInHistory({
|
||||
userId,
|
||||
search: query.search,
|
||||
limit: query.limit,
|
||||
offset: query.offset
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@Get(':userId/activity')
|
||||
@ApiOperation({ summary: 'Активность пользователя', description: 'Созданные документы, чаты, семьи, OAuth-согласия и журнал действий.' })
|
||||
getUserActivity(@Param('userId') userId: string, @Query() query: UserInsightsQueryDto, @CurrentAdmin() admin: AdminRequestUser) {
|
||||
if (!admin.canViewUsers && !admin.canManageUsers) {
|
||||
throw new ForbiddenException('Недостаточно прав для просмотра активности пользователя');
|
||||
}
|
||||
return firstValueFrom(
|
||||
this.core.admin.GetUserActivity({
|
||||
userId,
|
||||
search: query.search,
|
||||
limit: query.limit,
|
||||
offset: query.offset
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@Get(':userId/chats')
|
||||
@ApiOperation({ summary: 'Чаты пользователя для модерации', description: 'Обычные чаты без E2E и ботов.' })
|
||||
listUserChats(@Param('userId') userId: string, @Query() query: UserInsightsQueryDto, @CurrentAdmin() admin: AdminRequestUser) {
|
||||
if (!admin.canModerateChats && !admin.isSuperAdmin) {
|
||||
throw new ForbiddenException('Недостаточно прав для модерации чатов');
|
||||
}
|
||||
return firstValueFrom(
|
||||
this.core.admin.ListUserChatRooms({
|
||||
userId,
|
||||
search: query.search,
|
||||
limit: query.limit,
|
||||
offset: query.offset
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@Get(':userId/chats/search')
|
||||
@ApiOperation({ summary: 'Поиск по сообщениям пользователя', description: 'Поиск по обычным (не E2E) перепискам пользователя.' })
|
||||
searchUserChats(@Param('userId') userId: string, @Query() query: UserInsightsQueryDto, @CurrentAdmin() admin: AdminRequestUser) {
|
||||
if (!admin.canModerateChats && !admin.isSuperAdmin) {
|
||||
throw new ForbiddenException('Недостаточно прав для модерации чатов');
|
||||
}
|
||||
if (!query.search?.trim()) {
|
||||
throw new BadRequestException('Укажите параметр search');
|
||||
}
|
||||
return firstValueFrom(
|
||||
this.core.admin.SearchUserChatMessages({
|
||||
userId,
|
||||
search: query.search.trim(),
|
||||
limit: query.limit,
|
||||
offset: query.offset
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@Get(':userId/chats/:roomId/messages')
|
||||
@ApiOperation({ summary: 'Сообщения чата пользователя', description: 'Просмотр переписки в обычном чате для модерации.' })
|
||||
listUserChatMessages(
|
||||
@Param('userId') userId: string,
|
||||
@Param('roomId') roomId: string,
|
||||
@Query() query: UserInsightsQueryDto,
|
||||
@CurrentAdmin() admin: AdminRequestUser
|
||||
) {
|
||||
if (!admin.canModerateChats && !admin.isSuperAdmin) {
|
||||
throw new ForbiddenException('Недостаточно прав для модерации чатов');
|
||||
}
|
||||
return firstValueFrom(
|
||||
this.core.admin.ListUserChatMessages({
|
||||
userId,
|
||||
roomId,
|
||||
search: query.search,
|
||||
limit: query.limit,
|
||||
beforeMessageId: query.beforeMessageId
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@Delete(':userId/chat-messages/:messageId')
|
||||
@ApiOperation({ summary: 'Удалить сообщение (модерация)', description: 'Мягкое удаление сообщения в обычном чате.' })
|
||||
deleteUserChatMessage(
|
||||
@Param('userId') userId: string,
|
||||
@Param('messageId') messageId: string,
|
||||
@CurrentAdmin() admin: AdminRequestUser
|
||||
) {
|
||||
if (!admin.canModerateChats && !admin.isSuperAdmin) {
|
||||
throw new ForbiddenException('Недостаточно прав для модерации чатов');
|
||||
}
|
||||
void userId;
|
||||
return firstValueFrom(
|
||||
this.core.admin.AdminDeleteChatMessage({
|
||||
actorUserId: admin.id,
|
||||
messageId
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,3 +69,23 @@ export class SetUserVerificationDto {
|
||||
@IsString({ message: 'Значок должен быть строкой' })
|
||||
verificationIcon?: string;
|
||||
}
|
||||
|
||||
export class UserInsightsQueryDto {
|
||||
@ApiPropertyOptional({ description: 'Поиск по событиям, IP, user-agent, тексту активности или чатам' })
|
||||
@IsOptional()
|
||||
@IsString({ message: 'Поисковая строка должна быть текстом' })
|
||||
search?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Лимит записей', default: 50 })
|
||||
@IsOptional()
|
||||
limit?: number;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Смещение для пагинации', default: 0 })
|
||||
@IsOptional()
|
||||
offset?: number;
|
||||
|
||||
@ApiPropertyOptional({ description: 'ID сообщения для пагинации истории чата' })
|
||||
@IsOptional()
|
||||
@IsString({ message: 'beforeMessageId должно быть строкой' })
|
||||
beforeMessageId?: string;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ export interface AdminRequestUser {
|
||||
canViewUsers: boolean;
|
||||
canManageSettings: boolean;
|
||||
canVerifyUsers: boolean;
|
||||
canModerateChats: boolean;
|
||||
roles: string[];
|
||||
permissions: string[];
|
||||
}
|
||||
@@ -60,6 +61,7 @@ export class AdminGuard implements CanActivate {
|
||||
canManageSettings: Boolean(profile.canManageSettings),
|
||||
canViewUsers: Boolean(profile.canViewUsers),
|
||||
canVerifyUsers: Boolean(profile.canVerifyUsers),
|
||||
canModerateChats: Boolean(profile.canModerateChats),
|
||||
roles: profile.roles ?? [],
|
||||
permissions: profile.permissions ?? []
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user