import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { v4 as uuid } from 'uuid'; import { BlogPostEntity } from '../../database/entities/blog-post.entity'; import { ApiError } from '../../common/errors/api-error'; import { AdminBlogPost, CreatePostPayload, UpdatePostPayload } from './dto/blog.dto'; @Injectable() export class AdminBlogService { constructor( @InjectRepository(BlogPostEntity) private readonly posts: Repository, ) {} async listAll(): Promise { const rows = await this.posts.find({ order: { updatedAt: 'DESC' } }); return rows.map((r) => this.toView(r)); } async getById(id: string): Promise { const row = await this.posts.findOne({ where: { id } }); if (!row) throw ApiError.notFound('Post not found'); return this.toView(row); } async create(payload: CreatePostPayload): Promise { const status = payload.status ?? 'draft'; const row = this.posts.create({ id: uuid(), title: payload.title.trim(), bodyMd: payload.bodyMd ?? '', status, publishedAt: status === 'published' ? new Date().toISOString() : null, }); await this.posts.save(row); return this.toView(row); } async update(id: string, payload: UpdatePostPayload): Promise { const row = await this.posts.findOne({ where: { id } }); if (!row) throw ApiError.notFound('Post not found'); if (payload.title !== undefined) row.title = payload.title.trim(); if (payload.bodyMd !== undefined) row.bodyMd = payload.bodyMd; if (payload.status !== undefined) { if (payload.status === 'published') { row.status = 'published'; // Only stamp publishedAt if this post has never been published before; // preserve the original publishedAt for re-publications. if (!row.publishedAt) { row.publishedAt = new Date().toISOString(); } } else if (payload.status === 'draft') { row.status = 'draft'; // preserve publishedAt so a later re-publish keeps the original publication timestamp. } } await this.posts.save(row); return this.toView(row); } async remove(id: string): Promise { const row = await this.posts.findOne({ where: { id } }); if (!row) throw ApiError.notFound('Post not found'); await this.posts.delete({ id }); } private toView(r: BlogPostEntity): AdminBlogPost { return { id: r.id, title: r.title, bodyMd: r.bodyMd ?? '', status: r.status, createdAt: r.createdAt, updatedAt: r.updatedAt, publishedAt: r.publishedAt ?? null, }; } }