news/backend/src/collections/collections.controller.ts
2025-06-24 21:50:09 +02:00

169 lines
3.9 KiB
TypeScript

import {
Controller,
Get,
Post,
Body,
Param,
UseGuards,
Request,
Query,
Inject,
} from '@nestjs/common';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Cache } from 'cache-manager';
import { PrismaService } from '../prisma/prisma.service';
import { JwtAuthGuard } from '../auth';
import { CreateCollectionDto, AddArticleDto, CreateQuickNoteDto } from './dto';
interface RequestWithUser extends Request {
user: {
id: string;
username: string;
};
}
@Controller('api/collections')
@UseGuards(JwtAuthGuard)
export class CollectionsController {
constructor(
private readonly prisma: PrismaService,
@Inject(CACHE_MANAGER) private cacheManager: Cache,
) {}
@Get()
async getAllCollections(
@Request() req: RequestWithUser,
@Query('limit') limit?: number,
@Query('cursor') cursor?: string,
) {
const cacheKey = `collections:${req.user.id}:${limit}:${cursor}`;
const cached = await this.cacheManager.get(cacheKey);
if (cached) {
return cached;
}
const take = limit ? Number(limit) : 20;
const collections = await this.prisma.collection.findMany({
where: {
userId: req.user.id,
},
take: take + 1,
skip: cursor ? 1 : 0,
cursor: cursor ? { id: cursor } : undefined,
orderBy: [{ updatedAt: 'desc' }, { id: 'desc' }],
include: {
articles: true,
quickNotes: true,
notes: true,
},
});
let nextCursor: string | null = null;
if (collections.length > take) {
const nextItem = collections.pop()!;
nextCursor = nextItem.id;
}
const result = {
collections,
nextCursor,
};
await this.cacheManager.set(cacheKey, result, 300); // Cache for 5 minutes
return result;
}
@Post()
async createCollection(
@Body() data: CreateCollectionDto,
@Request() req: RequestWithUser,
) {
const collection = await this.prisma.collection.create({
data: {
...data,
userId: req.user.id,
},
include: {
articles: true,
quickNotes: true,
notes: true,
},
});
// Invalidate user's collections cache
const cachePattern = `collections:${req.user.id}:*`;
await this.cacheManager.del(cachePattern);
return collection;
}
@Post(':id/add-article')
async addArticleToCollection(
@Param('id') id: string,
@Body() articleData: AddArticleDto,
@Request() req: RequestWithUser,
) {
const existingArticle = await this.prisma.article.findUnique({
where: { url: articleData.url },
});
if (existingArticle) {
await this.prisma.collection.update({
where: { id },
data: {
articles: {
connect: { id: existingArticle.id },
},
},
});
// Invalidate cache for this collection
const cachePattern = `collections:${req.user.id}:*`;
await this.cacheManager.del(cachePattern);
return existingArticle;
}
const article = await this.prisma.article.create({
data: {
...articleData,
collections: {
connect: { id },
},
},
});
// Invalidate cache for this collection
const cachePattern = `collections:${req.user.id}:*`;
await this.cacheManager.del(cachePattern);
return article;
}
@Post(':id/quick-notes')
async addQuickNoteToCollection(
@Param('id') id: string,
@Body() quickNoteData: CreateQuickNoteDto,
@Request() req: RequestWithUser,
) {
const quickNote = await this.prisma.quickNote.create({
data: {
...quickNoteData,
shared: quickNoteData.shared ?? false,
collection: {
connect: { id },
},
user: {
connect: { id: req.user.id },
},
},
});
// Invalidate cache for this collection
const cachePattern = `collections:${req.user.id}:*`;
await this.cacheManager.del(cachePattern);
return quickNote;
}
}