fix sso core folder

This commit is contained in:
lendry
2026-06-24 14:45:45 +03:00
parent 995adeedd4
commit d2bbf35d40
45 changed files with 6592 additions and 1 deletions

View File

@@ -0,0 +1,166 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../infra/prisma.service';
import { NotificationPublisherService } from '../infra/notification-publisher.service';
@Injectable()
export class NotificationsService {
constructor(
private readonly prisma: PrismaService,
private readonly publisher: NotificationPublisherService
) {}
async create(
userId: string,
type: string,
title: string,
message: string,
payload?: Record<string, unknown>,
options?: { skipPublish?: boolean }
) {
const notification = await this.prisma.notification.create({
data: {
userId,
type,
title,
message,
payload: (payload ?? undefined) as never
}
});
if (!options?.skipPublish) {
await this.publisher.publish({
userId,
type,
title,
message,
payload: {
notificationId: notification.id,
...(payload ?? {})
}
});
}
return this.toResponse(notification);
}
async publishRealtime(userId: string, type: string, title: string, message: string, payload?: Record<string, unknown>) {
await this.publisher.publish({ userId, type, title, message, payload });
}
async list(userId: string, limit = 30, unreadOnly = false) {
const notifications = await this.prisma.notification.findMany({
where: {
userId,
...(unreadOnly ? { isRead: false } : {})
},
orderBy: { createdAt: 'desc' },
take: Math.min(Math.max(limit, 1), 100)
});
const inviteIds = notifications
.filter((item) => item.type === 'family_invite')
.map((item) => (item.payload as { inviteId?: string } | null)?.inviteId)
.filter((inviteId): inviteId is string => Boolean(inviteId));
const pendingInviteIds = new Set<string>();
if (inviteIds.length) {
const invites = await this.prisma.familyInvite.findMany({
where: { id: { in: inviteIds }, status: 'PENDING' }
});
invites.forEach((invite) => pendingInviteIds.add(invite.id));
}
const staleIds: string[] = [];
const filtered = notifications.filter((item) => {
if (item.type !== 'family_invite') return true;
const inviteId = (item.payload as { inviteId?: string } | null)?.inviteId;
if (!inviteId || !pendingInviteIds.has(inviteId)) {
staleIds.push(item.id);
return false;
}
return true;
});
if (staleIds.length) {
await this.prisma.notification.deleteMany({
where: { id: { in: staleIds }, userId }
});
}
return { notifications: filtered.map((item) => this.toResponse(item)) };
}
async unreadCount(userId: string) {
const count = await this.prisma.notification.count({
where: { userId, isRead: false }
});
return { count };
}
async markRead(userId: string, notificationId: string) {
return this.delete(userId, notificationId);
}
async markAllRead(userId: string) {
return this.deleteAll(userId);
}
async delete(userId: string, notificationId: string) {
const existing = await this.prisma.notification.findFirst({
where: { id: notificationId, userId }
});
if (!existing) {
throw new NotFoundException('Уведомление не найдено');
}
await this.prisma.notification.delete({ where: { id: notificationId } });
return { count: 1 };
}
async deleteAll(userId: string) {
const result = await this.prisma.notification.deleteMany({ where: { userId } });
return { count: result.count };
}
async dismissFamilyInvite(userId: string, inviteId: string) {
const items = await this.prisma.notification.findMany({
where: { userId, type: 'family_invite' }
});
const ids = items
.filter((item) => {
const payload = item.payload as { inviteId?: string } | null;
return payload?.inviteId === inviteId;
})
.map((item) => item.id);
if (!ids.length) {
return { count: 0 };
}
await this.prisma.notification.deleteMany({
where: { id: { in: ids }, userId }
});
return { count: ids.length };
}
private toResponse(notification: {
id: string;
userId: string;
type: string;
title: string;
message: string;
payload: unknown;
isRead: boolean;
createdAt: Date;
}) {
return {
id: notification.id,
userId: notification.userId,
type: notification.type,
title: notification.title,
message: notification.message,
payloadJson: notification.payload ? JSON.stringify(notification.payload) : '',
isRead: notification.isRead,
createdAt: notification.createdAt.toISOString()
};
}
}