Validate product and collection handles to be URL safe (#7310)

* fix: allow URL safe characters for product handle

Fixes: CORE-2072
This commit is contained in:
Harminder Virk
2024-05-15 17:50:26 +02:00
committed by GitHub
parent 7c4f4d7388
commit 17486cda99
8 changed files with 146 additions and 10 deletions
@@ -17,9 +17,9 @@ import {
createPsqlIndexStatementHelper,
DALUtils,
generateEntityId,
kebabCase,
ProductUtils,
Searchable,
toHandle,
} from "@medusajs/utils"
import ProductCategory from "./product-category"
import ProductCollection from "./product-collection"
@@ -216,7 +216,7 @@ class Product {
this.collection_id ??= this.collection?.id ?? null
if (!this.handle && this.title) {
this.handle = kebabCase(this.title)
this.handle = toHandle(this.title)
}
}
}
@@ -32,6 +32,8 @@ import {
ProductStatus,
promiseAll,
removeUndefined,
isValidHandle,
toHandle,
} from "@medusajs/utils"
import {
ProductCategoryEventData,
@@ -1165,9 +1167,14 @@ export default class ProductModuleService<
@MedusaContext() sharedContext: Context = {}
): Promise<TProduct[]> {
const normalizedInput = await promiseAll(
data.map(
async (d) => await this.normalizeCreateProductInput(d, sharedContext)
)
data.map(async (d) => {
const normalized = await this.normalizeCreateProductInput(
d,
sharedContext
)
this.validateProductPayload(normalized)
return normalized
})
)
const productData = await this.productService_.upsertWithReplace(
@@ -1223,9 +1230,14 @@ export default class ProductModuleService<
@MedusaContext() sharedContext: Context = {}
): Promise<TProduct[]> {
const normalizedInput = await promiseAll(
data.map(
async (d) => await this.normalizeUpdateProductInput(d, sharedContext)
)
data.map(async (d) => {
const normalized = await this.normalizeUpdateProductInput(
d,
sharedContext
)
this.validateProductPayload(normalized)
return normalized
})
)
const productData = await this.productService_.upsertWithReplace(
@@ -1306,6 +1318,21 @@ export default class ProductModuleService<
return productData
}
/**
* Validates the manually provided handle value of the product
* to be URL-safe
*/
protected validateProductPayload(
productData: UpdateProductInput | ProductTypes.CreateProductDTO
) {
if (productData.handle && !isValidHandle(productData.handle)) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
"Invalid product handle. It must contain URL safe characters"
)
}
}
protected async normalizeCreateProductInput(
product: ProductTypes.CreateProductDTO,
@MedusaContext() sharedContext: Context = {}
@@ -1316,7 +1343,7 @@ export default class ProductModuleService<
)) as ProductTypes.CreateProductDTO
if (!productData.handle && productData.title) {
productData.handle = kebabCase(productData.title)
productData.handle = toHandle(productData.title)
}
if (!productData.status) {