import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, ManyToOne, JoinColumn, ValueTransformer, OneToMany, } from 'typeorm'; class ArrayTransformer implements ValueTransformer { to(value: string[]): string { return JSON.stringify(value ?? []); } from(value: string): string[] { try { return value ? (JSON.parse(value) as string[]) : []; } catch { return []; } } } export enum ArticleStatus { DRAFT = 'draft', PUBLISHED = 'published', ARCHIVED = 'archived', } export enum LiveBlogStatus { DRAFT = 'draft', LIVE = 'live', ENDED = 'ended', ARCHIVED = 'archived', } export enum ImagePosition { TOP = 'top', LEFT = 'left', RIGHT = 'right', NONE = 'none', } export enum ImageSize { SMALL = 'small', MEDIUM = 'medium', LARGE = 'large', } export enum VideoPosition { TOP = 'top', INLINE = 'inline', BOTTOM = 'bottom', NONE = 'none', } export enum UserRole { ADMIN = 'admin', CONTRIBUTOR = 'contributor', USER = 'user', } export enum ReactionType { LIKE = 'like', DISLIKE = 'dislike', } @Entity('authors') export class Author { @PrimaryGeneratedColumn('uuid') id: string; @Column() name: string; @Column({ unique: true }) slug: string; @Column({ nullable: true }) bio: string; @Column({ nullable: true }) avatar: string; @Column({ default: false }) isActive: boolean; @CreateDateColumn() createdAt: Date; @UpdateDateColumn() updatedAt: Date; } @Entity('categories') export class Category { @PrimaryGeneratedColumn('uuid') id: string; @Column() name: string; @Column({ unique: true }) slug: string; @Column({ nullable: true }) description: string; @Column({ nullable: true }) parentId: string; @Column({ default: 0 }) order: number; @CreateDateColumn() createdAt: Date; @UpdateDateColumn() updatedAt: Date; @ManyToOne(() => Category, { onDelete: 'SET NULL' }) @JoinColumn({ name: 'parentId' }) parent: Category; } @Entity('users') export class User { @PrimaryGeneratedColumn('uuid') id: string; @Column({ unique: true }) email: string; @Column({ unique: true }) username: string; @Column() passwordHash: string; @Column({ type: 'text', default: 'user', }) role: UserRole; @Column({ default: true }) isActive: boolean; @CreateDateColumn() createdAt: Date; @UpdateDateColumn() updatedAt: Date; } @Entity('articles') export class Article { @PrimaryGeneratedColumn('uuid') id: string; @Column() title: string; @Column('text') content: string; @Column({ type: 'text', nullable: true }) excerpt: string; @Column({ default: '' }) slug: string; @Column({ default: '' }) featuredImage: string; @Column({ type: 'text', default: 'top', }) imagePosition: ImagePosition; @Column({ type: 'text', default: 'medium', }) imageSize: ImageSize; @Column({ default: '' }) videoUrl: string; @Column({ type: 'text', default: 'inline', }) videoPosition: VideoPosition; @Column({ default: '' }) videoCaption: string; @Column({ type: 'text', default: '[]', transformer: new ArrayTransformer(), }) tags: string[]; @Column({ type: 'text', default: 'draft', }) status: ArticleStatus; @Column({ default: 0 }) views: number; @Column({ nullable: true, unique: true }) strapiId: string; @Column({ nullable: true }) authorId: string; @Column({ nullable: true }) categoryId: string; @Column({ type: 'text', nullable: true }) ogTitle: string; @Column({ type: 'text', nullable: true }) ogDescription: string; @Column({ type: 'text', nullable: true }) ogImage: string; @Column({ type: 'text', nullable: true }) twitterTitle: string; @Column({ type: 'text', nullable: true }) twitterDescription: string; @Column({ type: 'text', nullable: true }) twitterImage: string; @Column({ default: 0 }) facebookShares: number; @Column({ default: 0 }) twitterShares: number; @Column({ default: 0 }) whatsappShares: number; @Column({ default: 0 }) telegramShares: number; @Column({ default: false }) isHero: boolean; @CreateDateColumn() createdAt: Date; @UpdateDateColumn() updatedAt: Date; @ManyToOne(() => Author, { onDelete: 'SET NULL' }) @JoinColumn({ name: 'authorId' }) author: Author; @ManyToOne(() => Category, { onDelete: 'SET NULL' }) @JoinColumn({ name: 'categoryId' }) category: Category; @OneToMany(() => Comment, (comment) => comment.article) comments: Comment[]; @OneToMany(() => Reaction, (reaction) => reaction.article) reactions: Reaction[]; } @Entity('live_blogs') export class LiveBlog { @PrimaryGeneratedColumn('uuid') id: string; @Column() title: string; @Column({ unique: true }) slug: string; @Column({ type: 'text', nullable: true }) description: string; @Column({ type: 'text', default: 'draft', }) status: LiveBlogStatus; @Column({ default: false }) isPinned: boolean; @Column({ nullable: true, unique: true }) strapiId: string; @Column({ nullable: true }) authorId: string; @Column({ nullable: true }) categoryId: string; @Column({ default: '' }) featuredImage: string; @Column({ type: 'text', default: 'top', }) imagePosition: ImagePosition; @Column({ type: 'text', default: 'medium', }) imageSize: ImageSize; @Column({ default: '' }) videoUrl: string; @Column({ type: 'text', default: 'inline', }) videoPosition: VideoPosition; @Column({ default: '' }) videoCaption: string; @Column({ default: 0 }) viewCount: number; @CreateDateColumn() createdAt: Date; @UpdateDateColumn() updatedAt: Date; @ManyToOne(() => Author, { onDelete: 'SET NULL' }) @JoinColumn({ name: 'authorId' }) author: Author; @ManyToOne(() => Category, { onDelete: 'SET NULL' }) @JoinColumn({ name: 'categoryId' }) category: Category; @OneToMany(() => LiveBlogUpdate, (update) => update.liveBlog, { cascade: true, }) updates: LiveBlogUpdate[]; @OneToMany(() => Comment, (comment) => comment.liveBlog) comments: Comment[]; @OneToMany(() => Reaction, (reaction) => reaction.liveBlog) reactions: Reaction[]; } @Entity('live_blog_updates') export class LiveBlogUpdate { @PrimaryGeneratedColumn('uuid') id: string; @Column('text') content: string; @Column({ default: false }) isPinned: boolean; @Column({ nullable: true }) authorId: string; @Column({ type: 'timestamp', nullable: true }) scheduledAt: Date; @Column({ nullable: true }) strapiId: string; @CreateDateColumn() createdAt: Date; @UpdateDateColumn() updatedAt: Date; @ManyToOne(() => Author, { onDelete: 'SET NULL' }) @JoinColumn({ name: 'authorId' }) author: Author; @ManyToOne(() => LiveBlog, { onDelete: 'CASCADE' }) @JoinColumn({ name: 'liveBlogId' }) liveBlog: LiveBlog; } @Entity('comments') export class Comment { @PrimaryGeneratedColumn('uuid') id: string; @Column('text') content: string; @Column({ nullable: true }) articleId: string; @Column({ nullable: true }) liveBlogId: string; @Column({ nullable: true }) parentId: string; @Column() userId: string; @Column({ default: 0 }) likeCount: number; @Column({ default: 0 }) dislikeCount: number; @Column({ default: true }) isVisible: boolean; @CreateDateColumn() createdAt: Date; @UpdateDateColumn() updatedAt: Date; @ManyToOne(() => Article, { onDelete: 'CASCADE' }) @JoinColumn({ name: 'articleId' }) article: Article; @ManyToOne(() => LiveBlog, { onDelete: 'CASCADE' }) @JoinColumn({ name: 'liveBlogId' }) liveBlog: LiveBlog; @ManyToOne(() => Comment, { onDelete: 'CASCADE' }) @JoinColumn({ name: 'parentId' }) parent: Comment; @ManyToOne(() => User, { onDelete: 'CASCADE' }) @JoinColumn({ name: 'userId' }) user: User; @OneToMany(() => Comment, (comment) => comment.parent) replies: Comment[]; } @Entity('reactions') export class Reaction { @PrimaryGeneratedColumn('uuid') id: string; @Column({ type: 'text', }) type: ReactionType; @Column({ nullable: true }) articleId: string; @Column({ nullable: true }) liveBlogId: string; @Column({ nullable: true }) commentId: string; @Column() userId: string; @CreateDateColumn() createdAt: Date; @ManyToOne(() => Article, { onDelete: 'CASCADE' }) @JoinColumn({ name: 'articleId' }) article: Article; @ManyToOne(() => LiveBlog, { onDelete: 'CASCADE' }) @JoinColumn({ name: 'liveBlogId' }) liveBlog: LiveBlog; @ManyToOne(() => Comment, { onDelete: 'CASCADE' }) @JoinColumn({ name: 'commentId' }) comment: Comment; @ManyToOne(() => User, { onDelete: 'CASCADE' }) @JoinColumn({ name: 'userId' }) user: User; }