This commit is contained in:
@@ -198,6 +198,7 @@ async function startServer() {
|
||||
imageStorage: createLocalImageStorage(imageStorageRoot),
|
||||
imageDerivativeJobRepository,
|
||||
inventoryImageRepository,
|
||||
sellerSettingsRepository,
|
||||
}),
|
||||
listingService: createListingService({
|
||||
listingRepository,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { moveImageInOrder } from '../domain/image-order.js';
|
||||
import { and, eq, inArray } from 'drizzle-orm';
|
||||
import { createApplicationError } from '../../../shared/errors/application-error.js';
|
||||
|
||||
import {
|
||||
imageDerivativeJobs,
|
||||
@@ -24,6 +25,24 @@ export function createInventoryImageRepository(db) {
|
||||
return createdImage;
|
||||
},
|
||||
|
||||
async createForSellerWithLimit(image, sellerId, maxImages) {
|
||||
return db.transaction(async (tx) => {
|
||||
const [ownedItem] = await tx.select({ id: inventoryItems.id })
|
||||
.from(inventoryItems)
|
||||
.innerJoin(products, eq(products.id, inventoryItems.productId))
|
||||
.where(and(eq(inventoryItems.id, image.inventoryItemId), eq(products.sellerId, sellerId)))
|
||||
.for('update', { of: inventoryItems });
|
||||
if (!ownedItem) return null;
|
||||
const existing = await tx.select({ id: inventoryImages.id }).from(inventoryImages)
|
||||
.where(eq(inventoryImages.inventoryItemId, image.inventoryItemId));
|
||||
if (existing.length >= maxImages) {
|
||||
throw createApplicationError('IMAGE_COUNT_LIMIT_REACHED', 'Maximum images per item reached.', 409);
|
||||
}
|
||||
const [createdImage] = await tx.insert(inventoryImages).values(image).returning();
|
||||
return createdImage;
|
||||
});
|
||||
},
|
||||
|
||||
async countByInventoryItemId(inventoryItemId) {
|
||||
const rows = await db
|
||||
.select({ id: inventoryImages.id })
|
||||
|
||||
@@ -2,13 +2,20 @@ import { validateImageMove } from '../domain/image-order.js';
|
||||
import { createApplicationError } from '../../../shared/errors/application-error.js';
|
||||
import { normalizeImageAltText, validateImageSortOrder, validateImageSignature, validateInventoryImageMetadata } from '../domain/inventory-image.js';
|
||||
|
||||
export function createInventoryImageService({ inventoryImageRepository, imageDerivativeJobRepository, imageStorage, imageInspector }) {
|
||||
export function createInventoryImageService({ inventoryImageRepository, imageDerivativeJobRepository, imageStorage, imageInspector, sellerSettingsRepository }) {
|
||||
return {
|
||||
async create(input) {
|
||||
validateInventoryImageMetadata(input);
|
||||
const image = await inventoryImageRepository.createForSeller(
|
||||
const settingsRecord = await sellerSettingsRepository?.findBySellerId(input.sellerId);
|
||||
const maxImages = settingsRecord?.settings?.inventory?.maxImagesPerItem ?? 10;
|
||||
if (!Number.isInteger(maxImages) || maxImages < 1 || maxImages > 100) {
|
||||
throw createApplicationError('IMAGE_COUNT_LIMIT_INVALID', 'Image count limit is invalid.', 500);
|
||||
}
|
||||
const createImage = inventoryImageRepository.createForSellerWithLimit ?? inventoryImageRepository.createForSeller;
|
||||
const image = await createImage.call(inventoryImageRepository,
|
||||
{ ...input, processingStatus: 'PENDING' },
|
||||
input.sellerId,
|
||||
maxImages,
|
||||
);
|
||||
|
||||
if (!image) {
|
||||
@@ -99,4 +106,4 @@ async function requireOwnedImage(imagePromise) {
|
||||
const image = await imagePromise;
|
||||
if (!image) throw imageNotFoundError();
|
||||
return image;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user