This commit is contained in:
lendry
2026-07-10 10:37:22 +03:00
parent caf12e64f7
commit a4b4577c55
13 changed files with 669 additions and 48 deletions

View File

@@ -481,6 +481,7 @@ export class AdminUserInsightsService {
if (type === 'AUDIO' || type === 'VOICE') return '[Аудио]';
if (type === 'VIDEO') return '[Видео]';
if (type === 'VIDEO_NOTE') return '[Кружок]';
if (type === 'LOCATION') return '[Геопозиция]';
if (type === 'FILE') return '[Файл]';
if (type === 'POLL') return '[Опрос]';
if (type === 'SYSTEM') return '[Системное сообщение]';

View File

@@ -468,11 +468,13 @@ export class ChatService {
if (room.type === 'E2E' && type === 'POLL') {
throw new BadRequestException('Опросы недоступны в секретном E2E чате');
}
const allowedTypes = new Set(['TEXT', 'IMAGE', 'AUDIO', 'VOICE', 'VIDEO', 'VIDEO_NOTE', 'FILE', 'EMOJI', 'POLL']);
const allowedTypes = new Set(['TEXT', 'IMAGE', 'AUDIO', 'VOICE', 'VIDEO', 'VIDEO_NOTE', 'FILE', 'EMOJI', 'POLL', 'LOCATION']);
if (!allowedTypes.has(type)) {
throw new BadRequestException('Неподдерживаемый тип сообщения');
}
const metadata = metadataJson ? JSON.parse(metadataJson) : undefined;
if (type === 'POLL') {
if (!poll?.question?.trim() || !poll.options?.length) {
throw new BadRequestException('Укажите вопрос и варианты опроса');
@@ -480,6 +482,25 @@ export class ChatService {
if (poll.options.length < 2) {
throw new BadRequestException('В опросе должно быть минимум 2 варианта');
}
} else if (type === 'LOCATION') {
if (!isEncrypted) {
const lat = metadata?.latitude;
const lng = metadata?.longitude;
if (
typeof lat !== 'number' ||
typeof lng !== 'number' ||
!Number.isFinite(lat) ||
!Number.isFinite(lng) ||
lat < -90 ||
lat > 90 ||
lng < -180 ||
lng > 180
) {
throw new BadRequestException('Укажите корректные координаты для геолокации');
}
} else if (!content?.trim()) {
throw new BadRequestException('Зашифрованная геолокация не может быть пустой');
}
} else if (type !== 'IMAGE' && type !== 'AUDIO' && type !== 'VOICE' && type !== 'VIDEO' && type !== 'VIDEO_NOTE' && type !== 'FILE') {
if (!content?.trim()) {
throw new BadRequestException('Сообщение не может быть пустым');
@@ -494,8 +515,6 @@ export class ChatService {
throw new BadRequestException('Некорректный ключ медиафайла');
}
const metadata = metadataJson ? JSON.parse(metadataJson) : undefined;
const message = await this.prisma.$transaction(async (tx) => {
const created = await tx.chatMessage.create({
data: {
@@ -742,14 +761,23 @@ export class ChatService {
let forwardStorageKey = source.storageKey ?? undefined;
let forwardMimeType = source.mimeType ?? undefined;
if (!['TEXT', 'EMOJI'].includes(source.type)) {
if (!['TEXT', 'EMOJI', 'LOCATION'].includes(source.type)) {
forwardType = 'TEXT';
forwardContent = this.buildForwardPreview(source.type, source.content);
forwardStorageKey = undefined;
forwardMimeType = undefined;
}
const sourceMetadata = (source.metadata as Record<string, unknown> | null) ?? {};
const metadata = {
...(source.type === 'LOCATION'
? {
latitude: sourceMetadata.latitude,
longitude: sourceMetadata.longitude,
address: sourceMetadata.address,
label: sourceMetadata.label
}
: {}),
forwardedFrom: {
messageId: source.id,
roomId: source.roomId,
@@ -806,6 +834,8 @@ export class ChatService {
return content ? `📄 Пересланный файл: ${content}` : '📄 Пересланный файл';
case 'POLL':
return '📊 Пересланный опрос';
case 'LOCATION':
return content?.trim() ? `📍 Пересланная геопозиция: ${content}` : '📍 Пересланная геопозиция';
default:
return '↪️ Пересланное сообщение';
}
@@ -1052,11 +1082,13 @@ export class ChatService {
? '🎬 Видео'
: message.type === 'VIDEO_NOTE'
? '⭕ Кружок'
: message.type === 'FILE'
? '📄 Файл'
: message.type === 'IMAGE'
? '📷 Фото'
: '📎 Медиа';
: message.type === 'LOCATION'
? '📍 Геопозиция'
: message.type === 'FILE'
? '📄 Файл'
: message.type === 'IMAGE'
? '📷 Фото'
: '📎 Медиа';
for (const member of room.members) {
if (member.userId === senderId) continue;