add categories

This commit is contained in:
Sergey Krylov 2025-07-13 10:43:23 +03:00
parent a0e4b57de7
commit 551a73001e
9 changed files with 194 additions and 13 deletions

View File

@ -9,17 +9,19 @@ datasource db {
}
model Stream {
id String @id @default(uuid())
id String @id @default(uuid())
title String
thumbnailUrl String? @map("thumbnail_url")
ingressId String? @unique @map("ingress_id")
serverUrl String? @map("server_url")
key String? @map("key")
isLive Boolean @default(false) @map("is_live")
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")
thumbnailUrl String? @map("thumbnail_url")
ingressId String? @unique @map("ingress_id")
serverUrl String? @map("server_url")
key String? @map("key")
isLive Boolean @default(false) @map("is_live")
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")
category Category? @relation(fields: [categoryId], references: [id], onDelete: Cascade)
categoryId String? @map("category_id")
@@map("stream")
}
@ -60,6 +62,19 @@ model User {
@@map("users")
}
model Category {
id String @id @default(uuid())
title String
slug String @unique
description String?
thumbnailUrl String @map("thumbnail_url")
streams Stream[]
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("categories")
}
model Token {
id String @id @default(uuid())
token String @unique

View File

@ -7,6 +7,7 @@ import { ProfileModule } from '@/src/module/auth/profile/profile.module'
import { SessionModule } from '@/src/module/auth/session/session.module'
import { TotpModule } from '@/src/module/auth/totp/totp.module'
import { VerificationModule } from '@/src/module/auth/verification/verification.module'
import { CategoryModule } from '@/src/module/category/category.module'
import { CronModule } from '@/src/module/cron/cron.module'
import { LiveKitModule } from '@/src/module/libs/livekit/livekit.module'
import { MailModule } from '@/src/module/libs/mail/mail.module'
@ -54,6 +55,7 @@ import { RedisModule } from './redis/redis.module'
StreamModule,
IngressModule,
WebhookModule,
CategoryModule,
],
})
export class CoreModule {}

View File

@ -7,6 +7,17 @@ type AuthModel {
user: UserModel
}
type CategoryModel {
createdAt: DateTime!
description: String
id: ID!
slug: String!
streams: [StreamModel!]!
thumbnailUrl: String!
title: String!
updatedAt: DateTime!
}
input ChangeEmailInput {
email: String!
}
@ -118,9 +129,12 @@ input NewPasswordInput {
}
type Query {
findAllCategories: [CategoryModel!]!
findAllStreams(filters: FilterInput!): [StreamModel!]!
findCategoryBySlug(slug: String!): CategoryModel!
findCurrentSession: SessionModel!
findProfile: UserModel!
findRandomCategories: [CategoryModel!]!
findRandomStreams: [StreamModel!]!
findSessionsByUser: [SessionModel!]!
findSocialLinks: [SocialLinkModel!]!
@ -165,6 +179,8 @@ input SocialLinkOrderInput {
}
type StreamModel {
category: CategoryModel!
categoryId: ID!
createdAt: DateTime!
id: ID!
ingressId: String

View File

@ -0,0 +1,8 @@
import { Module } from '@nestjs/common';
import { CategoryService } from './category.service';
import { CategoryResolver } from './category.resolver';
@Module({
providers: [CategoryResolver, CategoryService],
})
export class CategoryModule {}

View File

@ -0,0 +1,23 @@
import { CategoryModel } from '@/src/module/category/models/category.model'
import { Args, Query, Resolver } from '@nestjs/graphql'
import { CategoryService } from './category.service'
@Resolver('Category')
export class CategoryResolver {
constructor(private readonly categoryService: CategoryService) {}
@Query(() => [CategoryModel], { name: 'findAllCategories' })
public async findAll() {
return this.categoryService.findAll()
}
@Query(() => [CategoryModel], { name: 'findRandomCategories' })
public async findRandom() {
return this.categoryService.findRandom()
}
@Query(() => CategoryModel, { name: 'findCategoryBySlug' })
public async findByhSlug(@Args('slug') slug: string) {
return this.categoryService.findBySlug(slug)
}
}

View File

@ -0,0 +1,71 @@
import { PrismaService } from '@/src/core/prisma/prisma.service'
import { Injectable, NotFoundException } from '@nestjs/common'
@Injectable()
export class CategoryService {
constructor(
private readonly prismaService: PrismaService,
) {
}
public async findAll() {
return this.prismaService.category.findMany({
orderBy: { createdAt: 'desc' },
include: {
streams: {
include: {
user: true,
category: true,
},
},
},
})
}
public async findRandom() {
const total = await this.prismaService.category.count({})
const randomIndexes = new Set<number>()
while (randomIndexes.size < 7) {
const randomIndex = Math.floor(Math.random() * total)
randomIndexes.add(randomIndex)
}
const categories = await this.prismaService.category.findMany({
take: total,
skip: 0,
include: {
streams: {
include: {
user: true,
category: true,
},
},
},
})
return Array.from(randomIndexes).map(index => categories[index])
}
public async findBySlug(slug: string) {
const category = await this.prismaService.category.findUnique({
where: {
slug,
},
include: {
streams: {
include: {
user: true,
category: true,
},
},
},
})
if (!category) {
throw new NotFoundException('Категория не найдена')
}
return category
}
}

View File

@ -0,0 +1,32 @@
import { Field, ID, ObjectType } from '@nestjs/graphql'
import type { Category } from '@/prisma/generated'
import { StreamModel } from '../../stream/models/stream.model'
@ObjectType()
export class CategoryModel implements Category {
@Field(() => ID)
public id: string
@Field(() => String)
public title: string
@Field(() => String)
public slug: string
@Field(() => String, { nullable: true })
public description: string
@Field(() => String)
public thumbnailUrl: string
@Field(() => [StreamModel])
public streams: StreamModel[]
@Field(() => Date)
public createdAt: Date
@Field(() => Date)
public updatedAt: Date
}

View File

@ -1,4 +1,5 @@
import { UserModel } from '@/src/module/auth/account/models/user.model'
import { CategoryModel } from '@/src/module/category/models/category.model';
import { Field, ID, ObjectType } from '@nestjs/graphql'
import { Stream } from '@prisma/generated'
@ -13,6 +14,12 @@ export class StreamModel implements Stream {
@Field(() => UserModel)
user: UserModel
@Field(() => ID)
categoryId: CategoryModel['id']
@Field(() => CategoryModel)
category: CategoryModel
@Field(() => String)
title: string

View File

@ -32,7 +32,7 @@ export class StreamService {
user: { isDeactivated: false },
...whereClause,
},
include: { user: true },
include: { user: true, category: true },
orderBy: {
createdAt: 'desc',
},
@ -62,7 +62,7 @@ export class StreamService {
},
take: total,
skip: 0,
include: { user: true },
include: { user: true, category: true },
})
return Array.from(randomIndexes).map(index => streams[index])
@ -93,7 +93,14 @@ export class StreamService {
const { categoryId, title } = input
return this.prismaService.stream.update({
where: { userId: user.id },
data: { title },
data: {
title,
category: {
connect: {
id: categoryId,
},
},
},
})
}