add notifications
This commit is contained in:
parent
23caed10b6
commit
35df6780ec
@ -91,6 +91,9 @@ model User {
|
|||||||
chatMessages ChatMessage[]
|
chatMessages ChatMessage[]
|
||||||
followers Follow[] @relation(name: "followers")
|
followers Follow[] @relation(name: "followers")
|
||||||
followings Follow[] @relation(name: "followings")
|
followings Follow[] @relation(name: "followings")
|
||||||
|
notifications Notification[]
|
||||||
|
notificationSettings NotificationSettings?
|
||||||
|
telegramId String? @default("telegram_id")
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
createdAt DateTime @default(now()) @map("created_at")
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
updatedAt DateTime @updatedAt @map("updated_at")
|
||||||
|
|
||||||
@ -123,10 +126,46 @@ model Token {
|
|||||||
@@map("tokens")
|
@@map("tokens")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model Notification {
|
||||||
|
id String @id @default(uuid())
|
||||||
|
text String
|
||||||
|
type NotificationType
|
||||||
|
isRead Boolean @default(false) @map("is_read")
|
||||||
|
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||||
|
userId String? @map("user_id")
|
||||||
|
createdAt DateTime @default(now()) @map("created_at")
|
||||||
|
updatedAt DateTime @updatedAt @map("updated_at")
|
||||||
|
|
||||||
|
@@map("notifications")
|
||||||
|
}
|
||||||
|
|
||||||
|
model NotificationSettings {
|
||||||
|
id String @id @default(uuid())
|
||||||
|
siteNotifications Boolean @default(true) @map("site_notifications")
|
||||||
|
telegramNotifications Boolean @default(true) @map("telegram_notifications")
|
||||||
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||||
|
userId String @unique @map("user_id")
|
||||||
|
createdAt DateTime @default(now()) @map("created_at")
|
||||||
|
updatedAt DateTime @updatedAt @map("updated_at")
|
||||||
|
|
||||||
|
@@map("notification_settings")
|
||||||
|
}
|
||||||
|
|
||||||
|
enum NotificationType {
|
||||||
|
STREAM_START
|
||||||
|
NEW_FOLLOWER
|
||||||
|
NEW_SPONSORSHIP
|
||||||
|
ENABLE_TWO_FACTOR
|
||||||
|
VERIFIED_CHANNEL
|
||||||
|
|
||||||
|
@@map("notification_types")
|
||||||
|
}
|
||||||
|
|
||||||
enum TokenType {
|
enum TokenType {
|
||||||
EMAIL_VERIFY
|
EMAIL_VERIFY
|
||||||
PASSWORD_RESET
|
PASSWORD_RESET
|
||||||
DEACTIVATE_ACCOUNT
|
DEACTIVATE_ACCOUNT
|
||||||
|
TELEGRAM_AUTH
|
||||||
|
|
||||||
@@map("token_types")
|
@@map("token_types")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import { FollowModule } from '@/src/module/follow/follow.module'
|
|||||||
import { LiveKitModule } from '@/src/module/libs/livekit/livekit.module'
|
import { LiveKitModule } from '@/src/module/libs/livekit/livekit.module'
|
||||||
import { MailModule } from '@/src/module/libs/mail/mail.module'
|
import { MailModule } from '@/src/module/libs/mail/mail.module'
|
||||||
import { StorageModule } from '@/src/module/libs/storage/storage.module'
|
import { StorageModule } from '@/src/module/libs/storage/storage.module'
|
||||||
|
import { NotificationModule } from '@/src/module/notification/notification.module'
|
||||||
import { IngressModule } from '@/src/module/stream/ingress/ingress.module'
|
import { IngressModule } from '@/src/module/stream/ingress/ingress.module'
|
||||||
import { StreamModule } from '@/src/module/stream/stream.module'
|
import { StreamModule } from '@/src/module/stream/stream.module'
|
||||||
import { WebhookModule } from '@/src/module/webhook/webhook.module'
|
import { WebhookModule } from '@/src/module/webhook/webhook.module'
|
||||||
@ -62,6 +63,7 @@ import { RedisModule } from './redis/redis.module'
|
|||||||
ChatModule,
|
ChatModule,
|
||||||
FollowModule,
|
FollowModule,
|
||||||
ChannelModule,
|
ChannelModule,
|
||||||
|
NotificationModule,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class CoreModule {}
|
export class CoreModule {}
|
||||||
|
|||||||
@ -28,6 +28,16 @@ input ChangeEmailInput {
|
|||||||
email: String!
|
email: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input ChangeNotificationSettingsInput {
|
||||||
|
siteNotifications: Boolean!
|
||||||
|
telegramNotifications: Boolean!
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChangeNotificationsSettingsResponse {
|
||||||
|
notificationSettings: NotificationSettingsModel!
|
||||||
|
telegramAuthToken: String
|
||||||
|
}
|
||||||
|
|
||||||
input ChangePasswordInput {
|
input ChangePasswordInput {
|
||||||
newPassword: String!
|
newPassword: String!
|
||||||
oldPassword: String!
|
oldPassword: String!
|
||||||
@ -122,6 +132,7 @@ input LoginInput {
|
|||||||
type Mutation {
|
type Mutation {
|
||||||
changeChatSettings(data: ChangeChatSettingsInput!): StreamModel!
|
changeChatSettings(data: ChangeChatSettingsInput!): StreamModel!
|
||||||
changeEmail(data: ChangeEmailInput!): UserModel!
|
changeEmail(data: ChangeEmailInput!): UserModel!
|
||||||
|
changeNotificationSettigs(data: ChangeNotificationSettingsInput!): ChangeNotificationsSettingsResponse!
|
||||||
changePassword(data: ChangePasswordInput!): UserModel!
|
changePassword(data: ChangePasswordInput!): UserModel!
|
||||||
changeProfileAvatar(avatar: Upload!): Boolean!
|
changeProfileAvatar(avatar: Upload!): Boolean!
|
||||||
changeProfileInfo(data: ChangeProfileInfoInput!): UserModel!
|
changeProfileInfo(data: ChangeProfileInfoInput!): UserModel!
|
||||||
@ -157,6 +168,35 @@ input NewPasswordInput {
|
|||||||
token: String!
|
token: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NotificationModel {
|
||||||
|
createdAt: DateTime!
|
||||||
|
id: String!
|
||||||
|
isRead: Boolean!
|
||||||
|
text: String!
|
||||||
|
type: NotificationType!
|
||||||
|
updatedAt: DateTime!
|
||||||
|
user: UserModel!
|
||||||
|
userId: String!
|
||||||
|
}
|
||||||
|
|
||||||
|
type NotificationSettingsModel {
|
||||||
|
createdAt: DateTime!
|
||||||
|
id: String!
|
||||||
|
siteNotifications: Boolean!
|
||||||
|
telegramNotifications: Boolean!
|
||||||
|
updatedAt: DateTime!
|
||||||
|
user: UserModel!
|
||||||
|
userId: String!
|
||||||
|
}
|
||||||
|
|
||||||
|
enum NotificationType {
|
||||||
|
ENABLE_TWO_FACTOR
|
||||||
|
NEW_FOLLOWER
|
||||||
|
NEW_SPONSORSHIP
|
||||||
|
STREAM_START
|
||||||
|
VERIFIED_CHANNEL
|
||||||
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
findAllCategories: [CategoryModel!]!
|
findAllCategories: [CategoryModel!]!
|
||||||
findAllStreams(filters: FilterInput!): [StreamModel!]!
|
findAllStreams(filters: FilterInput!): [StreamModel!]!
|
||||||
@ -167,12 +207,14 @@ type Query {
|
|||||||
findMessagesByStream(streamId: String!): [ChatMessageModel!]!
|
findMessagesByStream(streamId: String!): [ChatMessageModel!]!
|
||||||
findMyFollowers: [FollowModel!]!
|
findMyFollowers: [FollowModel!]!
|
||||||
findMyFollowings: [FollowModel!]!
|
findMyFollowings: [FollowModel!]!
|
||||||
|
findNotificationByUser: [NotificationModel!]!
|
||||||
findProfile: UserModel!
|
findProfile: UserModel!
|
||||||
findRandomCategories: [CategoryModel!]!
|
findRandomCategories: [CategoryModel!]!
|
||||||
findRandomStreams: [StreamModel!]!
|
findRandomStreams: [StreamModel!]!
|
||||||
findRecommendedChannels: [UserModel!]!
|
findRecommendedChannels: [UserModel!]!
|
||||||
findSessionsByUser: [SessionModel!]!
|
findSessionsByUser: [SessionModel!]!
|
||||||
findSocialLinks: [SocialLinkModel!]!
|
findSocialLinks: [SocialLinkModel!]!
|
||||||
|
findUnreadNotificationsCount: Float!
|
||||||
generateTotpSecret: TotpModel!
|
generateTotpSecret: TotpModel!
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,9 +307,12 @@ type UserModel {
|
|||||||
isTotpEnabled: Boolean!
|
isTotpEnabled: Boolean!
|
||||||
isVerified: Boolean!
|
isVerified: Boolean!
|
||||||
name: String!
|
name: String!
|
||||||
|
notification: [NotificationModel!]!
|
||||||
|
notificationSettings: NotificationSettingsModel!
|
||||||
password: String!
|
password: String!
|
||||||
socialLink: [SocialLinkModel!]!
|
socialLink: [SocialLinkModel!]!
|
||||||
stream: StreamModel!
|
stream: StreamModel!
|
||||||
|
telegramId: String
|
||||||
totpSecret: String
|
totpSecret: String
|
||||||
updatedAt: DateTime!
|
updatedAt: DateTime!
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import { SocialLinkModel } from '@/src/module/auth/profile/inputs/models/social-link.model'
|
import { SocialLinkModel } from '@/src/module/auth/profile/inputs/models/social-link.model'
|
||||||
import { FollowModel } from '@/src/module/follow/model/follow.model'
|
import { FollowModel } from '@/src/module/follow/model/follow.model'
|
||||||
|
import { NotificationSettingsModel } from '@/src/module/notification/models/notification-settings.model'
|
||||||
|
import { NotificationModel } from '@/src/module/notification/models/notification.model'
|
||||||
import { StreamModel } from '@/src/module/stream/models/stream.model'
|
import { StreamModel } from '@/src/module/stream/models/stream.model'
|
||||||
import { Field, ID, ObjectType } from '@nestjs/graphql'
|
import { Field, ID, ObjectType } from '@nestjs/graphql'
|
||||||
import { User } from '@prisma/generated'
|
import { User } from '@prisma/generated'
|
||||||
@ -57,6 +59,15 @@ export class UserModel implements User {
|
|||||||
@Field(() => [FollowModel])
|
@Field(() => [FollowModel])
|
||||||
followings: FollowModel[]
|
followings: FollowModel[]
|
||||||
|
|
||||||
|
@Field(() => String, { nullable: true })
|
||||||
|
telegramId: string
|
||||||
|
|
||||||
|
@Field(() => [NotificationModel])
|
||||||
|
notification: NotificationModel[]
|
||||||
|
|
||||||
|
@Field(() => NotificationSettingsModel)
|
||||||
|
notificationSettings: NotificationSettingsModel
|
||||||
|
|
||||||
@Field(() => Date)
|
@Field(() => Date)
|
||||||
createdAt: Date
|
createdAt: Date
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
|
import { NotificationService } from '@/src/module/notification/notification.service'
|
||||||
import { Module } from '@nestjs/common'
|
import { Module } from '@nestjs/common'
|
||||||
import { FollowService } from './follow.service'
|
import { FollowService } from './follow.service'
|
||||||
import { FollowResolver } from './follow.resolver'
|
import { FollowResolver } from './follow.resolver'
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers: [FollowResolver, FollowService],
|
providers: [FollowResolver, FollowService, NotificationService],
|
||||||
})
|
})
|
||||||
export class FollowModule {}
|
export class FollowModule {}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { PrismaService } from '@/src/core/prisma/prisma.service'
|
import { PrismaService } from '@/src/core/prisma/prisma.service'
|
||||||
|
import { NotificationService } from '@/src/module/notification/notification.service'
|
||||||
import { ConflictException, Injectable, NotFoundException } from '@nestjs/common'
|
import { ConflictException, Injectable, NotFoundException } from '@nestjs/common'
|
||||||
import { User } from '@prisma/generated'
|
import { User } from '@prisma/generated'
|
||||||
|
|
||||||
@ -6,6 +7,7 @@ import { User } from '@prisma/generated'
|
|||||||
export class FollowService {
|
export class FollowService {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly prismaService: PrismaService,
|
private readonly prismaService: PrismaService,
|
||||||
|
private readonly notificationService: NotificationService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,16 +50,25 @@ export class FollowService {
|
|||||||
throw new ConflictException('Подписка уже существует')
|
throw new ConflictException('Подписка уже существует')
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.prismaService.follow.create({
|
const follow = await this.prismaService.follow.create({
|
||||||
data: {
|
data: {
|
||||||
followerId: user.id,
|
followerId: user.id,
|
||||||
followingId: channel.id,
|
followingId: channel.id,
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
following: true,
|
following: {
|
||||||
|
include: {
|
||||||
|
notificationSettings: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
follower: true,
|
follower: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (follow.following.notificationSettings?.siteNotifications) {
|
||||||
|
await this.notificationService.createNewFollowing(follow.following.id, follow.follower)
|
||||||
|
}
|
||||||
|
return follow
|
||||||
}
|
}
|
||||||
|
|
||||||
public async unfollow(user: User, channelId: string) {
|
public async unfollow(user: User, channelId: string) {
|
||||||
|
|||||||
@ -0,0 +1,13 @@
|
|||||||
|
import { Field, InputType } from '@nestjs/graphql'
|
||||||
|
import { IsBoolean } from 'class-validator'
|
||||||
|
|
||||||
|
@InputType()
|
||||||
|
export class ChangeNotificationSettingsInput {
|
||||||
|
@Field(() => Boolean)
|
||||||
|
@IsBoolean()
|
||||||
|
public siteNotifications: boolean
|
||||||
|
|
||||||
|
@Field(() => Boolean)
|
||||||
|
@IsBoolean()
|
||||||
|
public telegramNotifications: boolean
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
import { UserModel } from '@/src/module/auth/account/models/user.model'
|
||||||
|
import { Field, ObjectType } from '@nestjs/graphql'
|
||||||
|
|
||||||
|
import type { NotificationSettings } from '@/prisma/generated'
|
||||||
|
|
||||||
|
@ObjectType()
|
||||||
|
export class NotificationSettingsModel implements NotificationSettings {
|
||||||
|
@Field(() => String)
|
||||||
|
public id: string
|
||||||
|
|
||||||
|
@Field(() => Boolean)
|
||||||
|
public siteNotifications: boolean
|
||||||
|
|
||||||
|
@Field(() => Boolean)
|
||||||
|
public telegramNotifications: boolean
|
||||||
|
|
||||||
|
@Field(() => UserModel)
|
||||||
|
public user: UserModel
|
||||||
|
|
||||||
|
@Field(() => String)
|
||||||
|
public userId: string
|
||||||
|
|
||||||
|
@Field(() => Date)
|
||||||
|
public createdAt: Date
|
||||||
|
|
||||||
|
@Field(() => Date)
|
||||||
|
public updatedAt: Date
|
||||||
|
}
|
||||||
|
|
||||||
|
@ObjectType()
|
||||||
|
export class ChangeNotificationsSettingsResponse {
|
||||||
|
@Field(() => NotificationSettingsModel)
|
||||||
|
public notificationSettings: NotificationSettingsModel
|
||||||
|
|
||||||
|
@Field(() => String, { nullable: true })
|
||||||
|
public telegramAuthToken?: string
|
||||||
|
}
|
||||||
36
backend/src/module/notification/models/notification.model.ts
Normal file
36
backend/src/module/notification/models/notification.model.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { Field, ObjectType, registerEnumType } from '@nestjs/graphql'
|
||||||
|
|
||||||
|
import { type Notification, NotificationType } from '@/prisma/generated'
|
||||||
|
|
||||||
|
import { UserModel } from '../../auth/account/models/user.model'
|
||||||
|
|
||||||
|
registerEnumType(NotificationType, {
|
||||||
|
name: 'NotificationType',
|
||||||
|
})
|
||||||
|
|
||||||
|
@ObjectType()
|
||||||
|
export class NotificationModel implements Notification {
|
||||||
|
@Field(() => String)
|
||||||
|
public id: string
|
||||||
|
|
||||||
|
@Field(() => String)
|
||||||
|
public text: string
|
||||||
|
|
||||||
|
@Field(() => NotificationType)
|
||||||
|
public type: NotificationType
|
||||||
|
|
||||||
|
@Field(() => Boolean)
|
||||||
|
public isRead: boolean
|
||||||
|
|
||||||
|
@Field(() => UserModel)
|
||||||
|
public user: UserModel
|
||||||
|
|
||||||
|
@Field(() => String)
|
||||||
|
public userId: string
|
||||||
|
|
||||||
|
@Field(() => Date)
|
||||||
|
public createdAt: Date
|
||||||
|
|
||||||
|
@Field(() => Date)
|
||||||
|
public updatedAt: Date
|
||||||
|
}
|
||||||
8
backend/src/module/notification/notification.module.ts
Normal file
8
backend/src/module/notification/notification.module.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { Module } from '@nestjs/common'
|
||||||
|
import { NotificationService } from './notification.service'
|
||||||
|
import { NotificationResolver } from './notification.resolver'
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
providers: [NotificationResolver, NotificationService],
|
||||||
|
})
|
||||||
|
export class NotificationModule {}
|
||||||
34
backend/src/module/notification/notification.resolver.ts
Normal file
34
backend/src/module/notification/notification.resolver.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { ChangeNotificationSettingsInput } from '@/src/module/notification/inputs/change-notification-settings.input'
|
||||||
|
import { ChangeNotificationsSettingsResponse } from '@/src/module/notification/models/notification-settings.model'
|
||||||
|
import { Authorization } from '@/src/shared/decorators/auth.decorator'
|
||||||
|
import { Authorized } from '@/src/shared/decorators/authorized.decorator'
|
||||||
|
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql'
|
||||||
|
import { User } from '@prisma/generated'
|
||||||
|
import { NotificationService } from './notification.service'
|
||||||
|
import { NotificationModel } from './models/notification.model'
|
||||||
|
|
||||||
|
@Resolver('Notification')
|
||||||
|
export class NotificationResolver {
|
||||||
|
constructor(private readonly notificationService: NotificationService) {}
|
||||||
|
|
||||||
|
@Authorization()
|
||||||
|
@Query(() => Number, { name: 'findUnreadNotificationsCount' })
|
||||||
|
public findUnreadCount(@Authorized() user: User) {
|
||||||
|
return this.notificationService.findUnreadCount(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Authorization()
|
||||||
|
@Query(() => [NotificationModel], { name: 'findNotificationByUser' })
|
||||||
|
public findByUser(@Authorized() user: User) {
|
||||||
|
return this.notificationService.findByUser(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Authorization()
|
||||||
|
@Mutation(() => ChangeNotificationsSettingsResponse, { name: 'changeNotificationSettigs' })
|
||||||
|
public async changeSettings(
|
||||||
|
@Authorized() user: User,
|
||||||
|
@Args('data') input: ChangeNotificationSettingsInput,
|
||||||
|
) {
|
||||||
|
return this.notificationService.changeSettings(user, input)
|
||||||
|
}
|
||||||
|
}
|
||||||
131
backend/src/module/notification/notification.service.ts
Normal file
131
backend/src/module/notification/notification.service.ts
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
import { PrismaService } from '@/src/core/prisma/prisma.service'
|
||||||
|
import { ChangeNotificationSettingsInput } from '@/src/module/notification/inputs/change-notification-settings.input'
|
||||||
|
import { generateToken } from '@/src/shared/util/generate-token.util'
|
||||||
|
import { Injectable } from '@nestjs/common'
|
||||||
|
import { $Enums, User } from '@prisma/generated'
|
||||||
|
import TokenType = $Enums.TokenType
|
||||||
|
import NotificationType = $Enums.NotificationType
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class NotificationService {
|
||||||
|
constructor(
|
||||||
|
private readonly prismaService: PrismaService,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public async findUnreadCount(user: User) {
|
||||||
|
return this.prismaService.notification.count({
|
||||||
|
where: {
|
||||||
|
isRead: false,
|
||||||
|
userId: user.id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public async findByUser(user: User) {
|
||||||
|
await this.prismaService.notification.updateMany({
|
||||||
|
where: {
|
||||||
|
isRead: false,
|
||||||
|
userId: user.id,
|
||||||
|
},
|
||||||
|
data: { isRead: true },
|
||||||
|
})
|
||||||
|
|
||||||
|
return this.prismaService.notification.findMany({
|
||||||
|
where: { userId: user.id },
|
||||||
|
orderBy: { createdAt: 'desc' },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public async changeSettings(user: User, input: ChangeNotificationSettingsInput) {
|
||||||
|
const { siteNotifications, telegramNotifications } = input
|
||||||
|
|
||||||
|
const notificationSetting = await this.prismaService.notificationSettings.upsert({
|
||||||
|
where: { userId: user.id },
|
||||||
|
create: {
|
||||||
|
siteNotifications,
|
||||||
|
telegramNotifications,
|
||||||
|
userId: user.id,
|
||||||
|
},
|
||||||
|
update: { siteNotifications, telegramNotifications },
|
||||||
|
include: { user: true },
|
||||||
|
})
|
||||||
|
|
||||||
|
if (notificationSetting.telegramNotifications && !notificationSetting.user.telegramId) {
|
||||||
|
const telegramAuthToken = await generateToken(
|
||||||
|
this.prismaService,
|
||||||
|
user,
|
||||||
|
TokenType.TELEGRAM_AUTH,
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
notificationSetting,
|
||||||
|
token: telegramAuthToken.token,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!notificationSetting.telegramNotifications && notificationSetting.user.telegramId) {
|
||||||
|
await this.prismaService.user.update({
|
||||||
|
where: { id: user.id },
|
||||||
|
data: { telegramId: null },
|
||||||
|
})
|
||||||
|
|
||||||
|
return { notificationSetting }
|
||||||
|
}
|
||||||
|
|
||||||
|
return { notificationSetting }
|
||||||
|
}
|
||||||
|
|
||||||
|
public async createStreamStart(userId: string, channel: User) {
|
||||||
|
return this.prismaService.notification.create({
|
||||||
|
data: {
|
||||||
|
text: `<b className='font-medium'>Не пропустите!</b>
|
||||||
|
<p>Присоединяйтесь к стриму на канале <a href='/${channel.name}' className='font-semibold'>${channel.displayName}</a>.</p>`,
|
||||||
|
type: NotificationType.STREAM_START,
|
||||||
|
user: {
|
||||||
|
connect: {
|
||||||
|
id: userId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public async createNewFollowing(userId: string, follower: User) {
|
||||||
|
return this.prismaService.notification.create({
|
||||||
|
data: {
|
||||||
|
text: `<b className='font-medium'>У вас новый подписчик!</b>
|
||||||
|
<p>Это пользователь <a href='/${follower.name}' className='font-semibold'>${follower.displayName}</a>.</p>`,
|
||||||
|
type: NotificationType.NEW_FOLLOWER,
|
||||||
|
user: {
|
||||||
|
connect: {
|
||||||
|
id: userId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public async createEnableTwoFactor(userId: string) {
|
||||||
|
return this.prismaService.notification.create({
|
||||||
|
data: {
|
||||||
|
text: `<b className='font-medium'>Обеспечьте свою безопасность!</b>
|
||||||
|
<p>Включите двухфакторную аутентификацию в настройках вашего аккаунта, чтобы повысить уровень защиты.</p>`,
|
||||||
|
type: NotificationType.ENABLE_TWO_FACTOR,
|
||||||
|
userId,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public async createVerifyChannel(userId: string) {
|
||||||
|
return this.prismaService.notification.create({
|
||||||
|
data: {
|
||||||
|
text: `<b className='font-medium'>Поздравляем!</b>
|
||||||
|
<p>Ваш канал верифицирован, и теперь рядом с вашим каналом будет галочка.</p>`,
|
||||||
|
type: NotificationType.VERIFIED_CHANNEL,
|
||||||
|
userId,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { NotificationService } from '@/src/module/notification/notification.service';
|
||||||
import { RawBodyMiddleware } from '@/src/shared/middlewares/raw-body.middleware'
|
import { RawBodyMiddleware } from '@/src/shared/middlewares/raw-body.middleware'
|
||||||
import { MiddlewareConsumer, Module, RequestMethod } from '@nestjs/common'
|
import { MiddlewareConsumer, Module, RequestMethod } from '@nestjs/common'
|
||||||
import { WebhookController } from './webhook.controller'
|
import { WebhookController } from './webhook.controller'
|
||||||
@ -5,7 +6,7 @@ import { WebhookService } from './webhook.service'
|
|||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [WebhookController],
|
controllers: [WebhookController],
|
||||||
providers: [WebhookService],
|
providers: [WebhookService, NotificationService],
|
||||||
})
|
})
|
||||||
export class WebhookModule {
|
export class WebhookModule {
|
||||||
public configure(consumer: MiddlewareConsumer) {
|
public configure(consumer: MiddlewareConsumer) {
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { PrismaService } from '@/src/core/prisma/prisma.service'
|
import { PrismaService } from '@/src/core/prisma/prisma.service'
|
||||||
import { LiveKitService } from '@/src/module/libs/livekit/livekit.service'
|
import { LiveKitService } from '@/src/module/libs/livekit/livekit.service'
|
||||||
|
import { NotificationService } from '@/src/module/notification/notification.service'
|
||||||
import { Injectable } from '@nestjs/common'
|
import { Injectable } from '@nestjs/common'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -7,6 +8,7 @@ export class WebhookService {
|
|||||||
constructor(
|
constructor(
|
||||||
private prismaService: PrismaService,
|
private prismaService: PrismaService,
|
||||||
private liveKitService: LiveKitService,
|
private liveKitService: LiveKitService,
|
||||||
|
private readonly notificationService: NotificationService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -14,17 +16,43 @@ export class WebhookService {
|
|||||||
const event = this.liveKitService.webhook.receive(body, authorization, true)
|
const event = this.liveKitService.webhook.receive(body, authorization, true)
|
||||||
|
|
||||||
if (event.event === 'ingress_started' && event.ingressInfo?.ingressId) {
|
if (event.event === 'ingress_started' && event.ingressInfo?.ingressId) {
|
||||||
await this.prismaService.stream.update({
|
const stream = await this.prismaService.stream.update({
|
||||||
where: { ingressId: event.ingressInfo.ingressId },
|
where: { ingressId: event.ingressInfo.ingressId },
|
||||||
data: { isLive: true },
|
data: { isLive: true },
|
||||||
|
include: { user: true },
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const followers = await this.prismaService.follow.findMany({
|
||||||
|
where: {
|
||||||
|
followingId: stream.user!.id,
|
||||||
|
follower: { isDeactivated: false },
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
follower: {
|
||||||
|
include: {
|
||||||
|
notificationSettings: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
for (const follow of followers) {
|
||||||
|
const follower = follow.follower
|
||||||
|
if (follower.notificationSettings?.siteNotifications) {
|
||||||
|
await this.notificationService.createStreamStart(follower.id, stream.user!)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.event === 'ingress_ended' && event.ingressInfo?.ingressId) {
|
if (event.event === 'ingress_ended' && event.ingressInfo?.ingressId) {
|
||||||
await this.prismaService.stream.update({
|
const stream = await this.prismaService.stream.update({
|
||||||
where: { ingressId: event.ingressInfo.ingressId },
|
where: { ingressId: event.ingressInfo.ingressId },
|
||||||
data: { isLive: false },
|
data: { isLive: false },
|
||||||
})
|
})
|
||||||
|
|
||||||
|
await this.prismaService.chatMessage.deleteMany({
|
||||||
|
where: { streamId: stream.id },
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user