main
Some checks failed
Backend Deploy 🚀 / build-and-deploy (push) Has been cancelled

This commit is contained in:
Harun CAN
2026-03-28 17:16:56 +03:00
parent c1e081478c
commit a229fc1e64
9 changed files with 747 additions and 214 deletions

View File

@@ -100,18 +100,24 @@ export class ContentController {
@ApiOperation({ summary: 'Get user contents' })
@ApiQuery({ name: 'platform', required: false, enum: SocialPlatform })
@ApiQuery({ name: 'status', required: false, enum: ContentStatus })
@ApiQuery({ name: 'sortBy', required: false })
@ApiQuery({ name: 'sortOrder', required: false })
async getContents(
@CurrentUser('id') userId: string,
@Query('platform') platform?: SocialPlatform,
@Query('status') status?: ContentStatus,
@Query('limit') limit?: number,
@Query('offset') offset?: number,
@Query('sortBy') sortBy?: string,
@Query('sortOrder') sortOrder?: 'asc' | 'desc',
) {
return this.contentService.getByUser(userId || undefined, {
platform,
status,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
sortBy,
sortOrder,
});
}
@@ -171,6 +177,15 @@ export class ContentController {
return this.contentService.delete(id);
}
@Public()
@Post('bulk-delete')
@ApiOperation({ summary: 'Bulk delete content items' })
async bulkDeleteContent(
@Body('ids') ids: string[],
) {
return this.contentService.bulkDelete(ids);
}
// ==================== Variations ====================
@Post(':id/variations')

View File

@@ -81,23 +81,40 @@ export class ContentService {
status?: ContentStatus;
limit?: number;
offset?: number;
sortBy?: string;
sortOrder?: 'asc' | 'desc';
},
) {
return this.prisma.content.findMany({
where: {
...(userId && { userId }),
...(options?.platform && { type: options.platform as any }),
...(options?.status && { status: options.status }),
},
orderBy: { createdAt: 'desc' },
take: options?.limit || 50,
skip: options?.offset || 0,
include: {
masterContent: { select: { id: true, title: true, type: true } },
variants: { select: { id: true, name: true, isWinner: true } },
_count: { select: { variants: true } },
},
});
// Build dynamic orderBy
const sortField = options?.sortBy || 'createdAt';
const sortDir = options?.sortOrder || 'desc';
const validSortFields = ['createdAt', 'updatedAt', 'type', 'status', 'publishedAt'];
const orderBy = validSortFields.includes(sortField)
? { [sortField]: sortDir }
: { createdAt: 'desc' as const };
const where = {
...(userId && { userId }),
...(options?.platform && { type: options.platform as any }),
...(options?.status && { status: options.status }),
};
const [items, total] = await Promise.all([
this.prisma.content.findMany({
where,
orderBy,
take: options?.limit || 100,
skip: options?.offset || 0,
include: {
masterContent: { select: { id: true, title: true, type: true } },
variants: { select: { id: true, name: true, isWinner: true } },
_count: { select: { variants: true } },
},
}),
this.prisma.content.count({ where }),
]);
return { items, total };
}
/**
@@ -139,12 +156,42 @@ export class ContentService {
}
/**
* Delete content
* Delete all related records for given content IDs, then delete the content.
* Uses a transaction to ensure atomicity.
*/
private async cascadeDeleteContents(ids: string[]) {
return this.prisma.$transaction(async (tx) => {
// Delete all dependent relations first
await tx.citation.deleteMany({ where: { contentId: { in: ids } } });
await tx.contentVariant.deleteMany({ where: { contentId: { in: ids } } });
await tx.media.deleteMany({ where: { contentId: { in: ids } } });
await tx.scheduledPost.deleteMany({ where: { contentId: { in: ids } } });
await tx.contentApproval.deleteMany({ where: { contentId: { in: ids } } });
await tx.contentAnalytics.deleteMany({ where: { contentId: { in: ids } } });
await tx.contentSeo.deleteMany({ where: { contentId: { in: ids } } });
await tx.contentPsychology.deleteMany({ where: { contentId: { in: ids } } });
await tx.contentSource.deleteMany({ where: { contentId: { in: ids } } });
// Now delete the content itself
const result = await tx.content.deleteMany({ where: { id: { in: ids } } });
return result.count;
});
}
/**
* Delete content (with cascade)
*/
async delete(id: string) {
return this.prisma.content.delete({
where: { id },
});
const deleted = await this.cascadeDeleteContents([id]);
return { deleted };
}
/**
* Bulk delete content items (with cascade)
*/
async bulkDelete(ids: string[]) {
const deleted = await this.cascadeDeleteContents(ids);
return { deleted };
}
/**