add telegram bot
This commit is contained in:
parent
35df6780ec
commit
5b6d8cccb7
@ -93,7 +93,7 @@ model User {
|
|||||||
followings Follow[] @relation(name: "followings")
|
followings Follow[] @relation(name: "followings")
|
||||||
notifications Notification[]
|
notifications Notification[]
|
||||||
notificationSettings NotificationSettings?
|
notificationSettings NotificationSettings?
|
||||||
telegramId String? @default("telegram_id")
|
telegramId String? @unique @map("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")
|
||||||
|
|
||||||
|
|||||||
@ -3,13 +3,14 @@ import { ApolloDriverConfig } from '@nestjs/apollo'
|
|||||||
import { ConfigService } from '@nestjs/config'
|
import { ConfigService } from '@nestjs/config'
|
||||||
import { Request, Response } from 'express'
|
import { Request, Response } from 'express'
|
||||||
import * as path from 'node:path'
|
import * as path from 'node:path'
|
||||||
|
import { ProcessEnv } from '../../shared/types/env'
|
||||||
|
|
||||||
type ContextType = {
|
type ContextType = {
|
||||||
req: Request
|
req: Request
|
||||||
res: Response
|
res: Response
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getGraphQLConfig(configService: ConfigService): ApolloDriverConfig {
|
export function getGraphQLConfig(configService: ConfigService<ProcessEnv>): ApolloDriverConfig {
|
||||||
return {
|
return {
|
||||||
playground: isDev(configService),
|
playground: isDev(configService),
|
||||||
path: configService.getOrThrow('GRAPHQL_PREFIX'),
|
path: configService.getOrThrow('GRAPHQL_PREFIX'),
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import { TypeLiveKitOptions } from '@/src/module/libs/livekit/type/livekit.type'
|
import { TypeLiveKitOptions } from '@/src/module/libs/livekit/type/livekit.type'
|
||||||
import { ConfigService } from '@nestjs/config'
|
import { ConfigService } from '@nestjs/config'
|
||||||
|
import { ProcessEnv } from '../../shared/types/env'
|
||||||
|
|
||||||
export function getLiveKitConfig(configService: ConfigService): TypeLiveKitOptions {
|
export function getLiveKitConfig(configService: ConfigService<ProcessEnv>): TypeLiveKitOptions {
|
||||||
return {
|
return {
|
||||||
apiSecret: configService.getOrThrow('LIVEKIT_API_SECRET'),
|
apiSecret: configService.getOrThrow('LIVEKIT_API_SECRET'),
|
||||||
apiKey: configService.getOrThrow('LIVEKIT_API_KEY'),
|
apiKey: configService.getOrThrow('LIVEKIT_API_KEY'),
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import { MailerOptions } from '@nestjs-modules/mailer'
|
import type { ProcessEnv } from '../../shared/types/env';
|
||||||
import { ConfigService } from '@nestjs/config'
|
import type { ConfigService } from '@nestjs/config';
|
||||||
|
import type { MailerOptions } from '@nestjs-modules/mailer';
|
||||||
|
|
||||||
export function getMailConfig(configService: ConfigService): MailerOptions {
|
export function getMailConfig(configService: ConfigService<ProcessEnv>): MailerOptions {
|
||||||
return {
|
return {
|
||||||
transport: {
|
transport: {
|
||||||
host: configService.getOrThrow<string>('MAIL_HOST'),
|
host: configService.getOrThrow<string>('MAIL_HOST'),
|
||||||
@ -15,5 +16,5 @@ export function getMailConfig(configService: ConfigService): MailerOptions {
|
|||||||
defaults: {
|
defaults: {
|
||||||
from: `"TeaStream" ${configService.getOrThrow<string>('MAIL_LOGIN')}`,
|
from: `"TeaStream" ${configService.getOrThrow<string>('MAIL_LOGIN')}`,
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
9
backend/src/core/config/telegraf.config.ts
Normal file
9
backend/src/core/config/telegraf.config.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { ConfigService } from '@nestjs/config'
|
||||||
|
import { TelegrafModuleOptions } from 'nestjs-telegraf'
|
||||||
|
import { ProcessEnv } from '../../shared/types/env';
|
||||||
|
|
||||||
|
export function getTelegrafOptions(configService: ConfigService<ProcessEnv>): TelegrafModuleOptions {
|
||||||
|
return {
|
||||||
|
token: configService.getOrThrow('TELEGRAM_BOT_TOKEN'),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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 { TelegramModule } from '@/src/module/libs/telegram/telegram.module'
|
||||||
import { NotificationModule } from '@/src/module/notification/notification.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'
|
||||||
@ -49,6 +50,7 @@ import { RedisModule } from './redis/redis.module'
|
|||||||
useFactory: getLiveKitConfig,
|
useFactory: getLiveKitConfig,
|
||||||
inject: [ConfigService],
|
inject: [ConfigService],
|
||||||
}),
|
}),
|
||||||
|
TelegramModule,
|
||||||
AccountModule,
|
AccountModule,
|
||||||
SessionModule,
|
SessionModule,
|
||||||
VerificationModule,
|
VerificationModule,
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
import { Injectable } from '@nestjs/common'
|
import { Injectable } from '@nestjs/common'
|
||||||
import { ConfigService } from '@nestjs/config'
|
import { ConfigService } from '@nestjs/config'
|
||||||
import Redis from 'ioredis'
|
import Redis from 'ioredis'
|
||||||
|
import { ProcessEnv } from '../../shared/types/env';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RedisService extends Redis {
|
export class RedisService extends Redis {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly configService: ConfigService,
|
private readonly configService: ConfigService<ProcessEnv>,
|
||||||
) {
|
) {
|
||||||
super(configService.getOrThrow('REDIS_URI'))
|
super(configService.getOrThrow('REDIS_URI'))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,21 +16,21 @@ async function bootstrap() {
|
|||||||
const config = app.get(ConfigService)
|
const config = app.get(ConfigService)
|
||||||
const redis = app.get(RedisService)
|
const redis = app.get(RedisService)
|
||||||
|
|
||||||
app.use(cookieParser(config.getOrThrow<string>('COOKIE_SECRET')))
|
app.use(cookieParser(config.getOrThrow('COOKIE_SECRET')))
|
||||||
app.use(config.getOrThrow<string>('GRAPHQL_PREFIX'), graphqlUploadExpress())
|
app.use(config.getOrThrow('GRAPHQL_PREFIX'), graphqlUploadExpress())
|
||||||
|
|
||||||
app.useGlobalPipes(new ValidationPipe({
|
app.useGlobalPipes(new ValidationPipe({
|
||||||
transform: true,
|
transform: true,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
app.use(session({
|
app.use(session({
|
||||||
secret: config.getOrThrow<string>('SESSION_SECRET'),
|
secret: config.getOrThrow('SESSION_SECRET'),
|
||||||
name: config.getOrThrow<string>('SESSION_NAME'),
|
name: config.getOrThrow('SESSION_NAME'),
|
||||||
resave: false,
|
resave: false,
|
||||||
saveUninitialized: false,
|
saveUninitialized: false,
|
||||||
cookie: {
|
cookie: {
|
||||||
domain: config.getOrThrow<string>('SESSION_DOMAIN'),
|
domain: config.getOrThrow('SESSION_DOMAIN'),
|
||||||
maxAge: ms(config.getOrThrow<StringValue>('SESSION_MAX_AGE')),
|
maxAge: ms(config.getOrThrow('SESSION_MAX_AGE')),
|
||||||
httpOnly: parseBoolean(config.getOrThrow('SESSION_HTTP_ONLY')),
|
httpOnly: parseBoolean(config.getOrThrow('SESSION_HTTP_ONLY')),
|
||||||
secure: parseBoolean(config.getOrThrow('SESSION_SECURE')),
|
secure: parseBoolean(config.getOrThrow('SESSION_SECURE')),
|
||||||
sameSite: 'lax',
|
sameSite: 'lax',
|
||||||
@ -42,7 +42,7 @@ async function bootstrap() {
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
app.enableCors({
|
app.enableCors({
|
||||||
origin: config.getOrThrow<string>('ALLOWED_ORIGIN'),
|
origin: config.getOrThrow('ALLOWED_ORIGIN'),
|
||||||
credentials: true,
|
credentials: true,
|
||||||
exposedHeaders: ['set-cookie'],
|
exposedHeaders: ['set-cookie'],
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { PrismaService } from '@/src/core/prisma/prisma.service'
|
import { PrismaService } from '@/src/core/prisma/prisma.service'
|
||||||
import { DeactivateAccountInput } from '@/src/module/auth/deactivate/inputs/deactivate-account.input'
|
import { DeactivateAccountInput } from '@/src/module/auth/deactivate/inputs/deactivate-account.input'
|
||||||
import { MailService } from '@/src/module/libs/mail/mail.service'
|
import { MailService } from '@/src/module/libs/mail/mail.service'
|
||||||
import { SessionInfo } from '@/src/shared/types/session-metadata.types'
|
import { TelegramService } from '@/src/module/libs/telegram/telegram.service';
|
||||||
import { generateToken } from '@/src/shared/util/generate-token.util'
|
import { generateToken } from '@/src/shared/util/generate-token.util'
|
||||||
import { getSessionMetadata } from '@/src/shared/util/session-metadata.util'
|
import { getSessionMetadata } from '@/src/shared/util/session-metadata.util'
|
||||||
import { destroySession } from '@/src/shared/util/session.util'
|
import { destroySession } from '@/src/shared/util/session.util'
|
||||||
@ -10,13 +10,15 @@ import { ConfigService } from '@nestjs/config'
|
|||||||
import { TokenType, User } from '@prisma/generated'
|
import { TokenType, User } from '@prisma/generated'
|
||||||
import { verify } from 'argon2'
|
import { verify } from 'argon2'
|
||||||
import { Request } from 'express'
|
import { Request } from 'express'
|
||||||
|
import { ProcessEnv } from '../../../shared/types/env'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DeactivateService {
|
export class DeactivateService {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly prismaService: PrismaService,
|
private readonly prismaService: PrismaService,
|
||||||
private readonly configService: ConfigService,
|
private readonly configService: ConfigService<ProcessEnv>,
|
||||||
private readonly mailService: MailService,
|
private readonly mailService: MailService,
|
||||||
|
private readonly telegramService: TelegramService
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,6 +91,9 @@ export class DeactivateService {
|
|||||||
const metadata = getSessionMetadata(req, userAgent)
|
const metadata = getSessionMetadata(req, userAgent)
|
||||||
await this.mailService.sendDeactivateToken(user.email, deactivateToken.token, metadata)
|
await this.mailService.sendDeactivateToken(user.email, deactivateToken.token, metadata)
|
||||||
|
|
||||||
|
if (deactivateToken.user?.notificationSettings?.telegramNotifications && deactivateToken.user?.telegramId) {
|
||||||
|
await this.telegramService.sendDeactivateToken(deactivateToken.user.telegramId, deactivateToken.token, metadata)
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common'
|
||||||
import { PasswordRecoveryService } from './password-recovery.service';
|
import { PasswordRecoveryService } from './password-recovery.service'
|
||||||
import { PasswordRecoveryResolver } from './password-recovery.resolver';
|
import { PasswordRecoveryResolver } from './password-recovery.resolver'
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers: [PasswordRecoveryResolver, PasswordRecoveryService],
|
providers: [PasswordRecoveryResolver, PasswordRecoveryService],
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { PrismaService } from '@/src/core/prisma/prisma.service'
|
|||||||
import { NewPasswordInput } from '@/src/module/auth/password-recovery/inputs/new-password.input'
|
import { NewPasswordInput } from '@/src/module/auth/password-recovery/inputs/new-password.input'
|
||||||
import { ResetPasswordInput } from '@/src/module/auth/password-recovery/inputs/reset-password.input'
|
import { ResetPasswordInput } from '@/src/module/auth/password-recovery/inputs/reset-password.input'
|
||||||
import { MailService } from '@/src/module/libs/mail/mail.service'
|
import { MailService } from '@/src/module/libs/mail/mail.service'
|
||||||
|
import { TelegramService } from '@/src/module/libs/telegram/telegram.service';
|
||||||
import { generateToken } from '@/src/shared/util/generate-token.util'
|
import { generateToken } from '@/src/shared/util/generate-token.util'
|
||||||
import { getSessionMetadata } from '@/src/shared/util/session-metadata.util'
|
import { getSessionMetadata } from '@/src/shared/util/session-metadata.util'
|
||||||
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common'
|
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common'
|
||||||
@ -14,6 +15,7 @@ export class PasswordRecoveryService {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly prismaService: PrismaService,
|
private readonly prismaService: PrismaService,
|
||||||
private readonly mailService: MailService,
|
private readonly mailService: MailService,
|
||||||
|
private readonly telegramService: TelegramService
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -21,6 +23,7 @@ export class PasswordRecoveryService {
|
|||||||
const { email } = input
|
const { email } = input
|
||||||
const user = await this.prismaService.user.findFirst({
|
const user = await this.prismaService.user.findFirst({
|
||||||
where: { email },
|
where: { email },
|
||||||
|
include: { notificationSettings: true },
|
||||||
})
|
})
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new NotFoundException('Пользователь с такой почтой не найден')
|
throw new NotFoundException('Пользователь с такой почтой не найден')
|
||||||
@ -30,6 +33,10 @@ export class PasswordRecoveryService {
|
|||||||
const metadata = getSessionMetadata(req, userAgent)
|
const metadata = getSessionMetadata(req, userAgent)
|
||||||
await this.mailService.sendPasswordResetToken(user.email, resetToken.token, metadata)
|
await this.mailService.sendPasswordResetToken(user.email, resetToken.token, metadata)
|
||||||
|
|
||||||
|
if (resetToken.user?.notificationSettings?.telegramNotifications && resetToken?.user.telegramId) {
|
||||||
|
await this.telegramService.sendPasswordResetToken(resetToken.user.telegramId, resetToken.token, metadata)
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,13 +16,14 @@ import { verify } from 'argon2'
|
|||||||
import { Request } from 'express'
|
import { Request } from 'express'
|
||||||
import { SessionData } from 'express-session'
|
import { SessionData } from 'express-session'
|
||||||
import { TOTP } from 'otpauth'
|
import { TOTP } from 'otpauth'
|
||||||
|
import { ProcessEnv } from '../../../shared/types/env'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SessionService {
|
export class SessionService {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly prismaService: PrismaService,
|
private readonly prismaService: PrismaService,
|
||||||
private readonly redisService: RedisService,
|
private readonly redisService: RedisService,
|
||||||
private readonly configService: ConfigService,
|
private readonly configService: ConfigService<ProcessEnv>,
|
||||||
private readonly verificationService: VerificationService,
|
private readonly verificationService: VerificationService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { PrismaService } from '@/src/core/prisma/prisma.service'
|
import { PrismaService } from '@/src/core/prisma/prisma.service'
|
||||||
import { MailService } from '@/src/module/libs/mail/mail.service'
|
import { MailService } from '@/src/module/libs/mail/mail.service'
|
||||||
import { StorageService } from '@/src/module/libs/storage/storage.service'
|
import { StorageService } from '@/src/module/libs/storage/storage.service'
|
||||||
|
import { TelegramService } from '@/src/module/libs/telegram/telegram.service'
|
||||||
import { Injectable } from '@nestjs/common'
|
import { Injectable } from '@nestjs/common'
|
||||||
import { Cron, CronExpression } from '@nestjs/schedule'
|
import { Cron, CronExpression } from '@nestjs/schedule'
|
||||||
|
|
||||||
@ -10,6 +11,7 @@ export class CronService {
|
|||||||
private readonly prismaService: PrismaService,
|
private readonly prismaService: PrismaService,
|
||||||
private readonly mailService: MailService,
|
private readonly mailService: MailService,
|
||||||
private readonly storageService: StorageService,
|
private readonly storageService: StorageService,
|
||||||
|
private readonly telegramService: TelegramService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,11 +27,18 @@ export class CronService {
|
|||||||
lte: sevenDayAgo,
|
lte: sevenDayAgo,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
include: {
|
||||||
|
notificationSettings: true,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
for (const user of deactivatedAccounts) {
|
for (const user of deactivatedAccounts) {
|
||||||
console.log('Deactivate user', user.name, user.email)
|
console.log('Deactivate user', user.name, user.email)
|
||||||
await this.mailService.sendAccountDeletion(user.email)
|
await this.mailService.sendAccountDeletion(user.email)
|
||||||
|
if (user?.telegramId) {
|
||||||
|
await this.telegramService.sendAccountDeletionToken(user?.telegramId)
|
||||||
|
}
|
||||||
|
|
||||||
if (user.avatar) {
|
if (user.avatar) {
|
||||||
await this.storageService.remove(user.avatar)
|
await this.storageService.remove(user.avatar)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { PrismaService } from '@/src/core/prisma/prisma.service'
|
import { PrismaService } from '@/src/core/prisma/prisma.service'
|
||||||
|
import { TelegramService } from '@/src/module/libs/telegram/telegram.service';
|
||||||
import { NotificationService } from '@/src/module/notification/notification.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'
|
||||||
@ -8,6 +9,7 @@ export class FollowService {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly prismaService: PrismaService,
|
private readonly prismaService: PrismaService,
|
||||||
private readonly notificationService: NotificationService,
|
private readonly notificationService: NotificationService,
|
||||||
|
private readonly telegramService: TelegramService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,6 +70,9 @@ export class FollowService {
|
|||||||
if (follow.following.notificationSettings?.siteNotifications) {
|
if (follow.following.notificationSettings?.siteNotifications) {
|
||||||
await this.notificationService.createNewFollowing(follow.following.id, follow.follower)
|
await this.notificationService.createNewFollowing(follow.following.id, follow.follower)
|
||||||
}
|
}
|
||||||
|
if (follow.following.notificationSettings?.telegramNotifications && follow.following.telegramId) {
|
||||||
|
await this.telegramService.sendNewFollowing(follow.following.telegramId, follow.follower)
|
||||||
|
}
|
||||||
return follow
|
return follow
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { DeactivateTemplate } from '@/src/module/libs/mail/templates/deactivate.
|
|||||||
import PasswordRecoveryTemplate from '@/src/module/libs/mail/templates/password-recovery.template'
|
import PasswordRecoveryTemplate from '@/src/module/libs/mail/templates/password-recovery.template'
|
||||||
import { SessionInfo } from '@/src/shared/types/session-metadata.types'
|
import { SessionInfo } from '@/src/shared/types/session-metadata.types'
|
||||||
import { Token } from '@prisma/generated'
|
import { Token } from '@prisma/generated'
|
||||||
|
import { ProcessEnv } from '../../../shared/types/env';
|
||||||
import VerificationTemplate from './templates/verification.template'
|
import VerificationTemplate from './templates/verification.template'
|
||||||
import { MailerService } from '@nestjs-modules/mailer'
|
import { MailerService } from '@nestjs-modules/mailer'
|
||||||
import { Injectable } from '@nestjs/common'
|
import { Injectable } from '@nestjs/common'
|
||||||
@ -12,7 +13,7 @@ import { render } from '@react-email/components'
|
|||||||
@Injectable()
|
@Injectable()
|
||||||
export class MailService {
|
export class MailService {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly configService: ConfigService,
|
private readonly configService: ConfigService<ProcessEnv>,
|
||||||
private readonly mailerService: MailerService,
|
private readonly mailerService: MailerService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import {
|
|||||||
} from '@aws-sdk/client-s3'
|
} from '@aws-sdk/client-s3'
|
||||||
import { BadRequestException, Injectable } from '@nestjs/common'
|
import { BadRequestException, Injectable } from '@nestjs/common'
|
||||||
import { ConfigService } from '@nestjs/config'
|
import { ConfigService } from '@nestjs/config'
|
||||||
|
import { ProcessEnv } from '../../../shared/types/env';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class StorageService {
|
export class StorageService {
|
||||||
@ -14,7 +15,7 @@ export class StorageService {
|
|||||||
private readonly bucket: string
|
private readonly bucket: string
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly configService: ConfigService,
|
private readonly configService: ConfigService<ProcessEnv>,
|
||||||
) {
|
) {
|
||||||
this.client = new S3Client({
|
this.client = new S3Client({
|
||||||
endpoint: this.configService.getOrThrow('S3_ENDPOINT'),
|
endpoint: this.configService.getOrThrow('S3_ENDPOINT'),
|
||||||
|
|||||||
17
backend/src/module/libs/telegram/telegram.button.ts
Normal file
17
backend/src/module/libs/telegram/telegram.button.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { Markup } from 'telegraf'
|
||||||
|
|
||||||
|
export const BUTTONS = {
|
||||||
|
authSuccess: Markup.inlineKeyboard([
|
||||||
|
[
|
||||||
|
Markup.button.callback('📜 Мои подписки', 'follows'),
|
||||||
|
Markup.button.callback('👤 Просмотреть профиль', 'me'),
|
||||||
|
],
|
||||||
|
[Markup.button.url('🌐 На сайт', 'https://teastream.ru')],
|
||||||
|
]),
|
||||||
|
profile: Markup.inlineKeyboard([
|
||||||
|
Markup.button.url(
|
||||||
|
'⚙️ Настройки аккаунта',
|
||||||
|
'https://teastream.ru/dashboard/settings',
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
}
|
||||||
74
backend/src/module/libs/telegram/telegram.message.ts
Normal file
74
backend/src/module/libs/telegram/telegram.message.ts
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import { SessionInfo } from '@/src/shared/types/session-metadata.types'
|
||||||
|
import type { User } from '@prisma/generated'
|
||||||
|
|
||||||
|
export const MESSAGES = {
|
||||||
|
welcome:
|
||||||
|
'<b>👋 Добро пожаловать в TeaStream Bot!</b>\n\n'
|
||||||
|
+ 'Чтобы получать уведомления и улучшить ваш опыт использования платформы, давайте свяжем ваш Telegram аккаунт с TeaStream.\n\n'
|
||||||
|
+ 'Нажмите на кнопку ниже и перейдите в раздел <b>Уведомления</b>, чтобы завершить настройку.',
|
||||||
|
authSuccess: '🎉 Вы успешно авторизовались и Telegram аккаунт связан с TeaStream!\n\n',
|
||||||
|
invalidToken: '❌ Недействительный или просроченный токен.',
|
||||||
|
profile: (user: User, followersCount: number) => '<b>👤 Профиль пользователя:</b>\n\n'
|
||||||
|
+ `👤 Имя пользователя: <b>${user.name}</b>\n`
|
||||||
|
+ `📧 Email: <b>${user.email}</b>\n`
|
||||||
|
+ `👥 Количество подписчиков: <b>${followersCount}</b>\n`
|
||||||
|
+ `📝 О себе: <b>${user.bio ?? 'Не указано'}</b>\n\n`
|
||||||
|
+ '🔧 Нажмите на кнопку ниже, чтобы перейти к настройкам профиля.',
|
||||||
|
follows: (user: User) =>
|
||||||
|
`📺 <a href="https://teastream.ru/${user.name}">${user.name}</a>`,
|
||||||
|
resetPassword: (token: string, metadata: SessionInfo) =>
|
||||||
|
`<b>🔒 Сброс пароля</b>\n\n`
|
||||||
|
+ `Вы запросили сброс пароля для вашей учетной записи на платформе <b>TeaStream</b>.\n\n`
|
||||||
|
+ `Чтобы создать новый пароль, пожалуйста, перейдите по следующей ссылке:\n\n`
|
||||||
|
+ `<b><a href="https://teastream.ru/account/recovery/${token}">Сбросить пароль</a></b>\n\n`
|
||||||
|
+ `📅 <b>Дата запроса:</b> ${new Date().toLocaleDateString()} в ${new Date().toLocaleTimeString()}\n\n`
|
||||||
|
+ `🖥️ <b>Информация о запросе:</b>\n\n`
|
||||||
|
+ `🌍 <b>Расположение:</b> ${metadata.location.country}, ${metadata.location.city}\n`
|
||||||
|
+ `📱 <b>Операционная система:</b> ${metadata.device.os}\n`
|
||||||
|
+ `🌐 <b>Браузер:</b> ${metadata.device.browser}\n`
|
||||||
|
+ `💻 <b>IP-адрес:</b> ${metadata.ip}\n\n`
|
||||||
|
+ `Если вы не делали этот запрос, просто проигнорируйте это сообщение.\n\n`
|
||||||
|
+ `Спасибо за использование <b>TeaStream</b>! 🚀`,
|
||||||
|
deactivate: (token: string, metadata: SessionInfo) =>
|
||||||
|
`<b>⚠️ Запрос на деактивацию аккаунта</b>\n\n`
|
||||||
|
+ `Вы инициировали процесс деактивации вашего аккаунта на платформе <b>Teastream</b>.\n\n`
|
||||||
|
+ `Для завершения операции, пожалуйста, подтвердите свой запрос, введя следующий код подтверждения:\n\n`
|
||||||
|
+ `<b>Код подтверждения: ${token}</b>\n\n`
|
||||||
|
+ `📅 <b>Дата запроса:</b> ${new Date().toLocaleDateString()} в ${new Date().toLocaleTimeString()}\n\n`
|
||||||
|
+ `🖥️ <b>Информация о запросе:</b>\n\n`
|
||||||
|
+ `• 🌍 <b>Расположение:</b> ${metadata.location.country}, ${metadata.location.city}\n`
|
||||||
|
+ `• 📱 <b>Операционная система:</b> ${metadata.device.os}\n`
|
||||||
|
+ `• 🌐 <b>Браузер:</b> ${metadata.device.browser}\n`
|
||||||
|
+ `• 💻 <b>IP-адрес:</b> ${metadata.ip}\n\n`
|
||||||
|
+ `<b>Что произойдет после деактивации?</b>\n\n`
|
||||||
|
+ `1. Вы автоматически выйдете из системы и потеряете доступ к аккаунту.\n`
|
||||||
|
+ `2. Если вы не отмените деактивацию в течение 7 дней, ваш аккаунт будет <b>безвозвратно удален</b> со всей вашей информацией, данными и подписками.\n\n`
|
||||||
|
+ `<b>⏳ Обратите внимание:</b> Если в течение 7 дней вы передумаете, вы можете обратиться в нашу поддержку для восстановления доступа к вашему аккаунту до момента его полного удаления.\n\n`
|
||||||
|
+ `После удаления аккаунта восстановить его будет невозможно, и все данные будут потеряны без возможности восстановления.\n\n`
|
||||||
|
+ `Если вы передумали, просто проигнорируйте это сообщение. Ваш аккаунт останется активным.\n\n`
|
||||||
|
+ `Спасибо, что пользуетесь <b>TeaStream</b>! Мы всегда рады видеть вас на нашей платформе и надеемся, что вы останетесь с нами. 🚀\n\n`
|
||||||
|
+ `С уважением,\n`
|
||||||
|
+ `Команда TeaStream`,
|
||||||
|
accountDeleted:
|
||||||
|
`<b>⚠️ Ваш аккаунт был полностью удалён.</b>\n\n`
|
||||||
|
+ `Ваш аккаунт был полностью стерт из базы данных Teastream. Все ваши данные и информация были удалены безвозвратно. ❌\n\n`
|
||||||
|
+ `🔒 Вы больше не будете получать уведомления в Telegram и на почту.\n\n`
|
||||||
|
+ `Если вы захотите вернуться на платформу, вы можете зарегистрироваться по следующей ссылке:\n`
|
||||||
|
+ `<b><a href="https://teastream.ru/account/create">Зарегистрироваться на Teastream</a></b>\n\n`
|
||||||
|
+ `Спасибо, что были с нами! Мы всегда будем рады видеть вас на платформе. 🚀\n\n`
|
||||||
|
+ `С уважением,\n`
|
||||||
|
+ `Команда TeaStream`,
|
||||||
|
streamStart: (channel: User) =>
|
||||||
|
`<b>📡 На канале ${channel.displayName} началась трансляция!</b>\n\n`
|
||||||
|
+ `Смотрите здесь: <a href="https://teastream.ru/${channel.name}">Перейти к трансляции</a>`,
|
||||||
|
newFollowing: (follower: User, followersCount: number) =>
|
||||||
|
`<b>У вас новый подписчик!</b>\n\nЭто пользователь <a href="https://teastream.ru/${follower.name}">${follower.displayName}</a>\n\nИтоговое количество подписчиков на вашем канале: ${followersCount}`,
|
||||||
|
enableTwoFactor:
|
||||||
|
`🔐 Обеспечьте свою безопасность!\n\n`
|
||||||
|
+ `Включите двухфакторную аутентификацию в <a href="https://teastream.ru/dashboard/settings">настройках аккаунта</a>.`,
|
||||||
|
verifyChannel:
|
||||||
|
`<b>🎉 Поздравляем! Ваш канал верифицирован</b>\n\n`
|
||||||
|
+ `Мы рады сообщить, что ваш канал теперь верифицирован, и вы получили официальный значок.\n\n`
|
||||||
|
+ `Значок верификации подтверждает подлинность вашего канала и улучшает доверие зрителей.\n\n`
|
||||||
|
+ `Спасибо, что вы с нами и продолжаете развивать свой канал вместе с TeaStream!`,
|
||||||
|
}
|
||||||
19
backend/src/module/libs/telegram/telegram.module.ts
Normal file
19
backend/src/module/libs/telegram/telegram.module.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { getTelegrafOptions } from '@/src/core/config/telegraf.config'
|
||||||
|
import { Global, Module } from '@nestjs/common'
|
||||||
|
import { ConfigModule, ConfigService } from '@nestjs/config'
|
||||||
|
import { TelegrafModule } from 'nestjs-telegraf'
|
||||||
|
import { TelegramService } from './telegram.service'
|
||||||
|
|
||||||
|
@Global()
|
||||||
|
@Module({
|
||||||
|
imports: [
|
||||||
|
TelegrafModule.forRootAsync({
|
||||||
|
imports: [ConfigModule],
|
||||||
|
inject: [ConfigService],
|
||||||
|
useFactory: getTelegrafOptions,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
providers: [TelegramService],
|
||||||
|
exports: [TelegramService],
|
||||||
|
})
|
||||||
|
export class TelegramModule {}
|
||||||
159
backend/src/module/libs/telegram/telegram.service.ts
Normal file
159
backend/src/module/libs/telegram/telegram.service.ts
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
import { SessionInfo } from '@/src/shared/types/session-metadata.types'
|
||||||
|
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common'
|
||||||
|
import { ConfigService } from '@nestjs/config'
|
||||||
|
import {
|
||||||
|
Action,
|
||||||
|
Command, Ctx, Start, Update,
|
||||||
|
} from 'nestjs-telegraf'
|
||||||
|
import { Context, Telegraf } from 'telegraf'
|
||||||
|
|
||||||
|
import { PrismaService } from '@/src/core/prisma/prisma.service'
|
||||||
|
import { BUTTONS } from '@/src/module/libs/telegram/telegram.button'
|
||||||
|
import { MESSAGES } from '@/src/module/libs/telegram/telegram.message'
|
||||||
|
import { TokenType, User } from '@prisma/generated'
|
||||||
|
|
||||||
|
import { ProcessEnv } from '../../../shared/types/env'
|
||||||
|
|
||||||
|
@Update()
|
||||||
|
@Injectable()
|
||||||
|
export class TelegramService extends Telegraf {
|
||||||
|
private readonly _token: string
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly prismaService: PrismaService,
|
||||||
|
private readonly configService: ConfigService<ProcessEnv>,
|
||||||
|
) {
|
||||||
|
super(configService.getOrThrow('TELEGRAM_BOT_TOKEN'))
|
||||||
|
this._token = configService.getOrThrow('TELEGRAM_BOT_TOKEN')
|
||||||
|
}
|
||||||
|
|
||||||
|
@Start()
|
||||||
|
public async onStart(@Ctx() ctx: Context) {
|
||||||
|
const chatId = ctx.chat?.id.toString()
|
||||||
|
// @ts-ignore
|
||||||
|
const token = ctx.message.text.split(' ')[1] as string
|
||||||
|
|
||||||
|
if (token) {
|
||||||
|
const authToken = await this.prismaService.token.findUnique({
|
||||||
|
where: {
|
||||||
|
token,
|
||||||
|
type: TokenType.TELEGRAM_AUTH,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!authToken?.userId) {
|
||||||
|
await ctx.reply('Токен не найден')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasExpired = new Date(authToken.expiresIn) < new Date()
|
||||||
|
if (hasExpired) {
|
||||||
|
await ctx.reply(MESSAGES.invalidToken)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.connectTelegram(authToken.userId, chatId!)
|
||||||
|
await this.prismaService.token.delete({
|
||||||
|
where: { id: authToken.id },
|
||||||
|
})
|
||||||
|
|
||||||
|
await ctx.replyWithHTML(MESSAGES.authSuccess, BUTTONS.authSuccess)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = await this.findUserByChatId(chatId!)
|
||||||
|
if (user) {
|
||||||
|
return await this.onMe(ctx)
|
||||||
|
}
|
||||||
|
await ctx.replyWithHTML(MESSAGES.welcome, BUTTONS.profile)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command('me')
|
||||||
|
@Action('me')
|
||||||
|
public async onMe(@Ctx() ctx: Context) {
|
||||||
|
const chatId = ctx.chat?.id.toString()
|
||||||
|
if (typeof chatId === 'undefined') {
|
||||||
|
throw new NotFoundException('Пользователь не найден')
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = await this.findUserByChatId(chatId)
|
||||||
|
if (!user) {
|
||||||
|
throw new NotFoundException('Пользователь не найден')
|
||||||
|
}
|
||||||
|
|
||||||
|
const followersCount = await this.prismaService.follow.count({
|
||||||
|
where: { followingId: user.id },
|
||||||
|
})
|
||||||
|
|
||||||
|
await ctx.replyWithHTML(MESSAGES.profile(user, followersCount), BUTTONS.profile)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command('follows')
|
||||||
|
@Action('follows')
|
||||||
|
public async onFollow(@Ctx() ctx: Context) {
|
||||||
|
const chatId = ctx.chat?.id
|
||||||
|
if (typeof chatId === 'undefined') {
|
||||||
|
throw new NotFoundException('Пользователь не найден')
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = await this.findUserByChatId(chatId.toString())
|
||||||
|
if (!user) {
|
||||||
|
throw new NotFoundException('Пользователь не найден')
|
||||||
|
}
|
||||||
|
|
||||||
|
const follows = await this.prismaService.follow.findMany({
|
||||||
|
where: { followerId: user.id },
|
||||||
|
include: { following: true },
|
||||||
|
})
|
||||||
|
|
||||||
|
if (follows.length > 0) {
|
||||||
|
const followList = follows.map(follow => MESSAGES.follows(follow.following)).join('\n')
|
||||||
|
const message = `<b>Каналы, на которые Вы подписаны</b>\n\n${followList}`
|
||||||
|
await ctx.replyWithHTML(message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await ctx.replyWithHTML('❌ <b>У Вас нет подписок</b>')
|
||||||
|
}
|
||||||
|
|
||||||
|
public async sendPasswordResetToken(chatId: string, token: string, metadata: SessionInfo) {
|
||||||
|
await this.telegram.sendMessage(chatId, MESSAGES.resetPassword(token, metadata), { parse_mode: 'HTML' })
|
||||||
|
}
|
||||||
|
|
||||||
|
public async sendDeactivateToken(chatId: string, token: string, metadata: SessionInfo) {
|
||||||
|
await this.telegram.sendMessage(chatId, MESSAGES.deactivate(token, metadata), { parse_mode: 'HTML' })
|
||||||
|
}
|
||||||
|
|
||||||
|
public async sendAccountDeletionToken(chatId: string) {
|
||||||
|
await this.telegram.sendMessage(chatId, MESSAGES.accountDeleted, { parse_mode: 'HTML' })
|
||||||
|
}
|
||||||
|
|
||||||
|
public async sendStreamStart(chatId: string, channel: User) {
|
||||||
|
await this.telegram.sendMessage(chatId, MESSAGES.streamStart(channel), { parse_mode: 'HTML' })
|
||||||
|
}
|
||||||
|
|
||||||
|
public async sendNewFollowing(chatId: string, follower: User) {
|
||||||
|
const user = await this.findUserByChatId(chatId)
|
||||||
|
if (!user) {
|
||||||
|
throw new NotFoundException('Пользователь не найден')
|
||||||
|
}
|
||||||
|
await this.telegram.sendMessage(chatId, MESSAGES.newFollowing(follower, user.followings.length), { parse_mode: 'HTML' })
|
||||||
|
}
|
||||||
|
|
||||||
|
private async connectTelegram(userId: string, chatId: string) {
|
||||||
|
return this.prismaService.user.update({
|
||||||
|
where: { id: userId },
|
||||||
|
data: { telegramId: chatId },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private async findUserByChatId(chatId: string) {
|
||||||
|
return this.prismaService.user.findUnique({
|
||||||
|
where: { telegramId: chatId },
|
||||||
|
include: {
|
||||||
|
followings: true,
|
||||||
|
followers: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -60,7 +60,7 @@ export class NotificationService {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
notificationSetting,
|
notificationSetting,
|
||||||
token: telegramAuthToken.token,
|
telegramAuthToken: telegramAuthToken.token,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,13 +9,14 @@ import { ConfigService } from '@nestjs/config'
|
|||||||
import * as Upload from 'graphql-upload/Upload'
|
import * as Upload from 'graphql-upload/Upload'
|
||||||
import { AccessToken } from 'livekit-server-sdk'
|
import { AccessToken } from 'livekit-server-sdk'
|
||||||
import sharp from 'sharp'
|
import sharp from 'sharp'
|
||||||
|
import { ProcessEnv } from '../../shared/types/env';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class StreamService {
|
export class StreamService {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly prismaService: PrismaService,
|
private readonly prismaService: PrismaService,
|
||||||
private readonly storageService: StorageService,
|
private readonly storageService: StorageService,
|
||||||
private readonly configService: ConfigService,
|
private readonly configService: ConfigService<ProcessEnv>,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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 { TelegramService } from '@/src/module/libs/telegram/telegram.service';
|
||||||
import { NotificationService } from '@/src/module/notification/notification.service'
|
import { NotificationService } from '@/src/module/notification/notification.service'
|
||||||
import { Injectable } from '@nestjs/common'
|
import { Injectable } from '@nestjs/common'
|
||||||
|
|
||||||
@ -9,6 +10,7 @@ export class WebhookService {
|
|||||||
private prismaService: PrismaService,
|
private prismaService: PrismaService,
|
||||||
private liveKitService: LiveKitService,
|
private liveKitService: LiveKitService,
|
||||||
private readonly notificationService: NotificationService,
|
private readonly notificationService: NotificationService,
|
||||||
|
private readonly telegramService: TelegramService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,6 +43,9 @@ export class WebhookService {
|
|||||||
if (follower.notificationSettings?.siteNotifications) {
|
if (follower.notificationSettings?.siteNotifications) {
|
||||||
await this.notificationService.createStreamStart(follower.id, stream.user!)
|
await this.notificationService.createStreamStart(follower.id, stream.user!)
|
||||||
}
|
}
|
||||||
|
if (follower.notificationSettings?.telegramNotifications && follower.telegramId) {
|
||||||
|
await this.telegramService.sendStreamStart(follower.telegramId, stream.user!)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
50
backend/src/shared/types/env.d.ts
vendored
Normal file
50
backend/src/shared/types/env.d.ts
vendored
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import { StringValue } from '../util/ms.util'
|
||||||
|
|
||||||
|
export interface ProcessEnv {
|
||||||
|
NODE_ENV: 'development' | 'production'
|
||||||
|
|
||||||
|
APPLICATION_PORT: number
|
||||||
|
APPLICATION_URL: string
|
||||||
|
ALLOWED_ORIGIN: string
|
||||||
|
|
||||||
|
COOKIE_SECRET: string
|
||||||
|
SESSION_SECRET: string
|
||||||
|
SESSION_NAME: string
|
||||||
|
SESSION_DOMAIN: string
|
||||||
|
SESSION_MAX_AGE: StringValue
|
||||||
|
SESSION_HTTP_ONLY: boolean
|
||||||
|
SESSION_SECURE: boolean
|
||||||
|
SESSION_FOLDER: string
|
||||||
|
|
||||||
|
GRAPHQL_PREFIX: string
|
||||||
|
|
||||||
|
POSTGRES_USER: string
|
||||||
|
POSTGRES_PASSWORD: string
|
||||||
|
POSTGRES_HOST: string
|
||||||
|
POSTGRES_PORT: number
|
||||||
|
POSTGRES_DATABASE: string
|
||||||
|
POSTGRES_URI: string
|
||||||
|
|
||||||
|
REDIS_USER: string
|
||||||
|
REDIS_PASSWORD: string
|
||||||
|
REDIS_HOST: string
|
||||||
|
REDIS_PORT: number
|
||||||
|
REDIS_URI: string
|
||||||
|
|
||||||
|
MAIL_HOST: string
|
||||||
|
MAIL_PORT: number
|
||||||
|
MAIL_LOGIN: string
|
||||||
|
MAIL_PASSWORD: string
|
||||||
|
|
||||||
|
S3_ENDPOINT: string
|
||||||
|
S3_REGION: string
|
||||||
|
S3_ACCESS_KEY_ID: string
|
||||||
|
S3_SECRET_KEY_ID: string
|
||||||
|
S3_BUCKET_NAME: string
|
||||||
|
|
||||||
|
LIVEKIT_URL: string
|
||||||
|
LIVEKIT_API_KEY: string
|
||||||
|
LIVEKIT_API_SECRET: string
|
||||||
|
|
||||||
|
TELEGRAM_BOT_TOKEN: string
|
||||||
|
}
|
||||||
@ -32,7 +32,11 @@ export async function generateToken(prismaService: PrismaService, user: User, ty
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
user: true,
|
user: {
|
||||||
|
include: {
|
||||||
|
notificationSettings: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
import { ConfigService } from '@nestjs/config'
|
import { ConfigService } from '@nestjs/config'
|
||||||
import * as dotenv from 'dotenv'
|
import * as dotenv from 'dotenv'
|
||||||
import * as process from 'node:process'
|
import * as process from 'node:process'
|
||||||
|
import { ProcessEnv } from '../types/env';
|
||||||
|
|
||||||
dotenv.config()
|
dotenv.config()
|
||||||
|
|
||||||
export function isDev(configService: ConfigService) {
|
export function isDev(configService: ConfigService<ProcessEnv>) {
|
||||||
return configService.getOrThrow('NODE_ENV') === 'development'
|
return configService.getOrThrow('NODE_ENV') === 'development'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { InternalServerErrorException } from '@nestjs/common'
|
|||||||
import { ConfigService } from '@nestjs/config'
|
import { ConfigService } from '@nestjs/config'
|
||||||
import { User } from '@prisma/generated'
|
import { User } from '@prisma/generated'
|
||||||
import { Request } from 'express'
|
import { Request } from 'express'
|
||||||
|
import { ProcessEnv } from '../types/env'
|
||||||
|
|
||||||
export function saveSession(req: Request, user: User, metadata: SessionInfo) {
|
export function saveSession(req: Request, user: User, metadata: SessionInfo) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
@ -20,7 +21,7 @@ export function saveSession(req: Request, user: User, metadata: SessionInfo) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function destroySession(req: Request, configService: ConfigService) {
|
export function destroySession(req: Request, configService: ConfigService<ProcessEnv>) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
req.session.destroy((error) => {
|
req.session.destroy((error) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user