add moodules

This commit is contained in:
2026-04-17 23:42:24 +01:00
parent 532458ecfa
commit a7fbb2c466
54 changed files with 3074 additions and 74 deletions
@@ -0,0 +1,44 @@
import {
Controller,
DefaultValuePipe,
Delete,
Get,
Param,
ParseIntPipe,
ParseUUIDPipe,
Post,
Query,
UseGuards,
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { CurrentDbUser } from '../../shared/decorators/current-db-user.decorator';
import { User } from '@prisma/client';
import { UserProvisioningGuard } from '../users/user-provisioning.guard';
import { BookmarksService } from './bookmarks.service';
@Controller('bookmarks')
export class BookmarksController {
constructor(private readonly bookmarksService: BookmarksService) {}
@UseGuards(AuthGuard('keycloak'), UserProvisioningGuard)
@Get('me')
listMine(
@CurrentDbUser() user: User,
@Query('page', new DefaultValuePipe(1), ParseIntPipe) page: number,
@Query('limit', new DefaultValuePipe(20), ParseIntPipe) limit: number,
) {
return this.bookmarksService.listMine(user, page, limit);
}
@UseGuards(AuthGuard('keycloak'), UserProvisioningGuard)
@Post(':articleId')
add(@CurrentDbUser() user: User, @Param('articleId', ParseUUIDPipe) articleId: string) {
return this.bookmarksService.add(user, articleId);
}
@UseGuards(AuthGuard('keycloak'), UserProvisioningGuard)
@Delete(':articleId')
remove(@CurrentDbUser() user: User, @Param('articleId', ParseUUIDPipe) articleId: string) {
return this.bookmarksService.remove(user, articleId);
}
}
+17
View File
@@ -0,0 +1,17 @@
import { Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport';
import { AuthModule } from '../auth/auth.module';
import { UsersModule } from '../users/users.module';
import { BookmarksController } from './bookmarks.controller';
import { BookmarksService } from './bookmarks.service';
@Module({
imports: [
PassportModule.register({ defaultStrategy: 'keycloak' }),
AuthModule,
UsersModule,
],
controllers: [BookmarksController],
providers: [BookmarksService],
})
export class BookmarksModule {}
+58
View File
@@ -0,0 +1,58 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { ArticleStatus, User } from '@prisma/client';
import { PrismaService } from '../../shared/prisma/prisma.service';
const bookmarkArticleInclude = {
author: {
select: { id: true, displayName: true, avatarKey: true },
},
categories: { include: { category: true } },
tags: { include: { tag: true } },
} as const;
@Injectable()
export class BookmarksService {
constructor(private readonly prisma: PrismaService) {}
async listMine(user: User, page = 1, limit = 20) {
const take = Math.min(Math.max(limit, 1), 100);
const skip = (Math.max(page, 1) - 1) * take;
const where = { userId: user.id };
const [rows, total] = await Promise.all([
this.prisma.bookmark.findMany({
where,
orderBy: { createdAt: 'desc' },
skip,
take,
include: { article: { include: bookmarkArticleInclude } },
}),
this.prisma.bookmark.count({ where }),
]);
return { items: rows, total, page, limit: take };
}
async add(user: User, articleId: string) {
const article = await this.prisma.article.findFirst({
where: { id: articleId, status: ArticleStatus.PUBLISHED },
});
if (!article) throw new NotFoundException('Article not found');
return this.prisma.bookmark.upsert({
where: {
userId_articleId: { userId: user.id, articleId },
},
create: { userId: user.id, articleId },
update: {},
include: { article: { include: bookmarkArticleInclude } },
});
}
async remove(user: User, articleId: string) {
const res = await this.prisma.bookmark.deleteMany({
where: { userId: user.id, articleId },
});
if (res.count === 0) {
throw new NotFoundException('Bookmark not found');
}
return { deleted: true };
}
}