Sync static image slots from the live website catalog.
Refresh now imports keys from the storefront and deletes unused slots plus their files. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
1c7678ce67
commit
5e5bfc4aa3
@@ -184,6 +184,126 @@ export class MediaService {
|
||||
return { message: 'Media deleted' };
|
||||
}
|
||||
|
||||
/** Delete media that is no longer referenced by any business record. */
|
||||
async deleteUnused(businessId: bigint, mediaIds: bigint[]): Promise<number> {
|
||||
if (!mediaIds.length) return 0;
|
||||
|
||||
const uniqueIds = [...new Set(mediaIds.map((id) => id.toString()))].map(
|
||||
(id) => BigInt(id),
|
||||
);
|
||||
const stillLinked = new Set<string>();
|
||||
|
||||
const addId = (id: bigint | null | undefined) => {
|
||||
if (id != null) stillLinked.add(id.toString());
|
||||
};
|
||||
|
||||
const attachments = await this.prisma.mediaAttachment.findMany({
|
||||
where: { businessId, mediaId: { in: uniqueIds } },
|
||||
select: { mediaId: true },
|
||||
});
|
||||
for (const row of attachments) addId(row.mediaId);
|
||||
|
||||
const [
|
||||
portfolios,
|
||||
products,
|
||||
blogs,
|
||||
videos,
|
||||
instructions,
|
||||
brands,
|
||||
userProducts,
|
||||
sliders,
|
||||
staticItems,
|
||||
business,
|
||||
] = await Promise.all([
|
||||
this.prisma.portfolios.findMany({
|
||||
where: { business_id: businessId, featured_media_id: { in: uniqueIds } },
|
||||
select: { featured_media_id: true },
|
||||
}),
|
||||
this.prisma.product.findMany({
|
||||
where: { businessId, featuredMediaId: { in: uniqueIds } },
|
||||
select: { featuredMediaId: true },
|
||||
}),
|
||||
this.prisma.blogs.findMany({
|
||||
where: { business_id: businessId, featured_media_id: { in: uniqueIds } },
|
||||
select: { featured_media_id: true },
|
||||
}),
|
||||
this.prisma.videos.findMany({
|
||||
where: { business_id: businessId, featured_media_id: { in: uniqueIds } },
|
||||
select: { featured_media_id: true },
|
||||
}),
|
||||
this.prisma.instructions.findMany({
|
||||
where: { business_id: businessId, featured_media_id: { in: uniqueIds } },
|
||||
select: { featured_media_id: true },
|
||||
}),
|
||||
this.prisma.brand.findMany({
|
||||
where: { businessId, imageMediaId: { in: uniqueIds } },
|
||||
select: { imageMediaId: true },
|
||||
}),
|
||||
this.prisma.userProduct.findMany({
|
||||
where: { businessId, featuredMediaId: { in: uniqueIds } },
|
||||
select: { featuredMediaId: true },
|
||||
}),
|
||||
this.prisma.website_slider_slides.findMany({
|
||||
where: {
|
||||
image_media_id: { in: uniqueIds },
|
||||
website_sliders: { business_id: businessId },
|
||||
},
|
||||
select: { image_media_id: true },
|
||||
}),
|
||||
this.prisma.website_image_slot_items.findMany({
|
||||
where: {
|
||||
image_media_id: { in: uniqueIds },
|
||||
website_image_slots: { business_id: businessId },
|
||||
},
|
||||
select: { image_media_id: true },
|
||||
}),
|
||||
this.prisma.business.findFirst({
|
||||
where: {
|
||||
id: businessId,
|
||||
OR: [
|
||||
{ logoMediaId: { in: uniqueIds } },
|
||||
{ faviconMediaId: { in: uniqueIds } },
|
||||
],
|
||||
},
|
||||
select: { logoMediaId: true, faviconMediaId: true },
|
||||
}),
|
||||
]);
|
||||
|
||||
for (const row of portfolios) addId(row.featured_media_id);
|
||||
for (const row of products) addId(row.featuredMediaId);
|
||||
for (const row of blogs) addId(row.featured_media_id);
|
||||
for (const row of videos) addId(row.featured_media_id);
|
||||
for (const row of instructions) addId(row.featured_media_id);
|
||||
for (const row of brands) addId(row.imageMediaId);
|
||||
for (const row of userProducts) addId(row.featuredMediaId);
|
||||
for (const row of sliders) addId(row.image_media_id);
|
||||
for (const row of staticItems) addId(row.image_media_id);
|
||||
addId(business?.logoMediaId);
|
||||
addId(business?.faviconMediaId);
|
||||
|
||||
const deletableIds = uniqueIds.filter((id) => !stillLinked.has(id.toString()));
|
||||
if (!deletableIds.length) return 0;
|
||||
|
||||
const mediaRows = await this.prisma.media.findMany({
|
||||
where: { businessId, id: { in: deletableIds } },
|
||||
select: { id: true, storagePath: true, storageDisk: true },
|
||||
});
|
||||
|
||||
await this.prisma.media.deleteMany({
|
||||
where: { businessId, id: { in: mediaRows.map((row) => row.id) } },
|
||||
});
|
||||
|
||||
for (const row of mediaRows) {
|
||||
try {
|
||||
await this.storage.delete(row.storagePath, row.storageDisk);
|
||||
} catch {
|
||||
// DB row removed; orphaned object can be cleaned later
|
||||
}
|
||||
}
|
||||
|
||||
return mediaRows.length;
|
||||
}
|
||||
|
||||
private async uploadOne(
|
||||
businessId: bigint,
|
||||
file: Express.Multer.File,
|
||||
|
||||
Reference in New Issue
Block a user