Add blog post admin CRUD API.

Expose JWT-protected /blog-posts endpoints for draft creation, listing, update, and delete.
This commit is contained in:
2026-09-15 20:22:49 +02:00
parent 92ccbec545
commit d38def2302
7 changed files with 295 additions and 0 deletions
@@ -0,0 +1,73 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import type { PaginatedResponse } from '../../../types/PaginatedResponse';
import type { ListBlogPostsQueryDto } from '../dto/ListBlogPostsQueryDto';
import { UpdateBlogPostDto } from '../dto/UpdateBlogPostDto';
import { BlogPost } from '../entities/BlogPost';
@Injectable()
export class BlogPostsService {
constructor(
@InjectRepository(BlogPost)
private readonly blogPostRepo: Repository<BlogPost>
) {}
async findAll({ page = 1, limit = 20 }: ListBlogPostsQueryDto): Promise<PaginatedResponse<BlogPost>> {
const [items, total] = await this.blogPostRepo.findAndCount({
order: { createdAt: 'DESC' },
skip: (page - 1) * limit,
take: limit
});
return { items, total, page, limit };
}
async createDraft(): Promise<BlogPost> {
const entity = this.blogPostRepo.create({
title: '',
contentHtml: '',
isDraft: true
});
await this.blogPostRepo.insert(entity);
return this.findOne(entity.id);
}
async findOne(id: string): Promise<BlogPost> {
const entity = await this.blogPostRepo.findOne({ where: { id } });
if (!entity) {
throw new NotFoundException();
}
return entity;
}
async update(id: string, { title, contentHtml, isDraft }: UpdateBlogPostDto): Promise<BlogPost> {
const exists = await this.blogPostRepo.exists({ where: { id } });
if (!exists) {
throw new NotFoundException();
}
await this.blogPostRepo.update(id, {
title: title.trim(),
contentHtml,
isDraft
});
return this.findOne(id);
}
async remove(id: string): Promise<void> {
const exists = await this.blogPostRepo.exists({ where: { id } });
if (!exists) {
throw new NotFoundException();
}
await this.blogPostRepo.delete(id);
}
}