Fix e-payment settings payload, cart race, and media/content helpers.

Stop returning passwordSet (forbidNonWhitelisted), upsert carts safely, and harden related media/product/workshop flows.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-08-25 16:41:00 +03:30
co-authored by Cursor
parent ad6f9dcf1d
commit 20cc0bbd78
12 changed files with 220 additions and 42 deletions
+53 -3
View File
@@ -456,7 +456,13 @@ export class UserProductsService {
const existing = await this.prisma.userProduct.findFirst({
where: { id: productId, businessId, userId: actor.id },
select: { id: true, title: true, slug: true, metadata: true },
select: {
id: true,
title: true,
slug: true,
metadata: true,
featuredMediaId: true,
},
});
if (!existing) {
@@ -475,6 +481,7 @@ export class UserProductsService {
title: string;
slug: string;
metadata: unknown;
featuredMediaId: bigint | null;
},
) {
const titleFa = dto.titleFa.trim();
@@ -525,6 +532,12 @@ export class UserProductsService {
);
}
const previousGalleryIds = await this.mediaService.galleryMediaIds(
businessId,
MediaEntityType.user_product,
productId,
);
const updated = await this.prisma.$transaction(async (tx) => {
const product = await tx.userProduct.update({
where: { id: productId },
@@ -594,6 +607,20 @@ export class UserProductsService {
select: { id: true, name: true, nameFa: true },
});
const dropped: bigint[] = [];
if (galleryMediaIds !== null) {
dropped.push(
...this.mediaService.idsNotIn(previousGalleryIds, galleryMediaIds),
);
}
if (
existing.featuredMediaId != null &&
existing.featuredMediaId !== featuredMediaId
) {
dropped.push(existing.featuredMediaId);
}
await this.mediaService.deleteUnused(businessId, dropped);
return {
message: 'User product updated successfully',
product: this.serializeAdminListItem(updated, category ?? undefined),
@@ -619,14 +646,28 @@ export class UserProductsService {
const product = await this.prisma.userProduct.findFirst({
where: { id: productId, businessId, userId: actor.id },
select: { id: true },
select: { id: true, featuredMediaId: true },
});
if (!product) {
throw new NotFoundException('User product not found');
}
const mediaIds = await this.mediaService.allLinkedMediaIds(
businessId,
MediaEntityType.user_product,
productId,
product.featuredMediaId,
);
await this.prisma.$transaction(async (tx) => {
await tx.mediaAttachment.deleteMany({
where: {
businessId,
entityType: MediaEntityType.user_product,
entityId: productId,
},
});
await tx.categoryAssignment.deleteMany({
where: {
businessId,
@@ -637,6 +678,8 @@ export class UserProductsService {
await tx.userProduct.delete({ where: { id: productId } });
});
await this.mediaService.deleteUnused(businessId, mediaIds);
return { message: 'User product deleted successfully' };
}
@@ -784,7 +827,14 @@ export class UserProductsService {
const existing = await this.prisma.userProduct.findFirst({
where: { id: productId, businessId },
select: { id: true, title: true, slug: true, metadata: true, userId: true },
select: {
id: true,
title: true,
slug: true,
metadata: true,
userId: true,
featuredMediaId: true,
},
});
if (!existing) {