From 318257924f29697bd051bb6d71451f117fff0584 Mon Sep 17 00:00:00 2001 From: adrien2p Date: Thu, 23 Feb 2023 15:21:30 +0100 Subject: [PATCH 1/8] fix(medusa): Clean response data usage for admin and store fields/expand --- .../src/api/middlewares/transform-query.ts | 90 +++++++++++++++---- .../src/api/routes/admin/orders/get-order.ts | 14 ++- .../api/routes/admin/orders/list-orders.ts | 12 +-- .../src/api/routes/store/orders/get-order.ts | 2 +- .../api/routes/store/orders/lookup-order.ts | 4 +- .../api/routes/store/products/get-product.ts | 2 +- .../routes/store/products/list-products.ts | 5 +- packages/medusa/src/types/global.ts | 3 +- .../medusa/src/utils/clean-response-data.ts | 46 ++++++++-- 9 files changed, 139 insertions(+), 39 deletions(-) diff --git a/packages/medusa/src/api/middlewares/transform-query.ts b/packages/medusa/src/api/middlewares/transform-query.ts index 6d3f93c9fe846..17a7b9b7b9645 100644 --- a/packages/medusa/src/api/middlewares/transform-query.ts +++ b/packages/medusa/src/api/middlewares/transform-query.ts @@ -39,24 +39,22 @@ export function transformQuery< ]) req.filterableFields = removeUndefinedProperties(req.filterableFields) - if ( - (queryConfig?.defaultFields || validated.fields) && - (queryConfig?.defaultRelations || validated.expand) - ) { - req.allowedProperties = [ - ...(validated.fields - ? validated.fields.split(",") - : queryConfig?.allowedFields || [])!, - ...(validated.expand - ? validated.expand.split(",") - : queryConfig?.allowedRelations || [])!, - ] as unknown as string[] - } + req.storeAllowedProperties = getStoreAllowedProperties( + validated, + Object.keys(req["includes"] ?? {}), + queryConfig + ) + + req.adminAllowedProperties = getAdminAllowedProperties( + validated, + Object.keys(req["includes"] ?? {}), + queryConfig + ) const includesFields = Object.keys(req["includes"] ?? {}) if (includesFields.length) { - req.allowedProperties = req.allowedProperties ?? [] - req.allowedProperties.push(...includesFields) + req.storeAllowedProperties = req.storeAllowedProperties ?? [] + req.storeAllowedProperties.push(...includesFields) } if (queryConfig?.isList) { @@ -77,3 +75,65 @@ export function transformQuery< } } } + +/** + * Build the store allowed props based on the custom fields query params, the defaults and the includes options. + * This can be used later with `cleanResponseData` in order to clean up the returned objects to the client. + * @param queryConfig + * @param validated + * @param includesOptions + */ +function getStoreAllowedProperties( + validated: RequestQueryFields, + includesOptions: string[], + queryConfig?: QueryConfig +): string[] { + const allowed: string[] = [] + if ( + (queryConfig?.defaultFields || validated.fields) && + (queryConfig?.defaultRelations || validated.expand) + ) { + allowed.push( + ...(validated.fields + ? validated.fields.split(",") + : queryConfig?.allowedFields || []), + ...(validated.expand + ? validated.expand.split(",") + : queryConfig?.allowedRelations || []) + ) + } + + if (includesOptions.length) { + allowed.push(...includesOptions) + } + + return allowed +} + +/** + * Build the admin allowed props based on the custom fields query params, the defaults and the includes options. + * Since admin can access everything, it is only in order to return what the user asked for through fields and expand query params. + * This can be used later with `cleanResponseData` in order to clean up the returned objects to the client. + * @param queryConfig + * @param validated + * @param includesOptions + */ +function getAdminAllowedProperties( + validated: RequestQueryFields, + includesOptions: string[], + queryConfig?: QueryConfig +): string[] { + const allowed: string[] = [] + if (validated.fields || validated.expand) { + allowed.push( + ...(validated.fields?.split(",") ?? []), + ...(validated.expand?.split(",") ?? []) + ) + } + + if (includesOptions.length) { + allowed.push(...includesOptions) + } + + return allowed +} diff --git a/packages/medusa/src/api/routes/admin/orders/get-order.ts b/packages/medusa/src/api/routes/admin/orders/get-order.ts index a9ce48c01ba63..b30a923197397 100644 --- a/packages/medusa/src/api/routes/admin/orders/get-order.ts +++ b/packages/medusa/src/api/routes/admin/orders/get-order.ts @@ -1,5 +1,7 @@ import { OrderService } from "../../../../services" import { FindParams } from "../../../../types/common" +import { cleanResponseData } from "../../../../utils/clean-response-data" +import { Order } from "../../../../models" /** * @oas [get] /admin/orders/{id} @@ -60,9 +62,15 @@ export default async (req, res) => { const orderService: OrderService = req.scope.resolve("orderService") - const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { - includes: req.includes, - }) + let order: Partial = await orderService.retrieveWithTotals( + id, + req.retrieveConfig, + { + includes: req.includes, + } + ) + + order = cleanResponseData(order, req.adminAllowedProperties) res.json({ order: order }) } diff --git a/packages/medusa/src/api/routes/admin/orders/list-orders.ts b/packages/medusa/src/api/routes/admin/orders/list-orders.ts index 9363257f4fe0e..6ddc9dfb8df56 100644 --- a/packages/medusa/src/api/routes/admin/orders/list-orders.ts +++ b/packages/medusa/src/api/routes/admin/orders/list-orders.ts @@ -1,10 +1,9 @@ import { IsNumber, IsOptional, IsString } from "class-validator" import { AdminListOrdersSelector } from "../../../../types/orders" -import { Order } from "../../../../models" import { OrderService } from "../../../../services" import { Type } from "class-transformer" -import { pick } from "lodash" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [get] /admin/orders @@ -200,19 +199,14 @@ import { pick } from "lodash" export default async (req, res) => { const orderService: OrderService = req.scope.resolve("orderService") - const { skip, take, select, relations } = req.listConfig + const { skip, take } = req.listConfig const [orders, count] = await orderService.listAndCount( req.filterableFields, req.listConfig ) - let data: Partial[] = orders - - const fields = [...select, ...relations] - if (fields.length) { - data = orders.map((o) => pick(o, fields)) - } + const data = cleanResponseData(orders, req.adminAllowedProperties) res.json({ orders: data, count, offset: skip, limit: take }) } diff --git a/packages/medusa/src/api/routes/store/orders/get-order.ts b/packages/medusa/src/api/routes/store/orders/get-order.ts index fb99dcfef0487..399d283111cc0 100644 --- a/packages/medusa/src/api/routes/store/orders/get-order.ts +++ b/packages/medusa/src/api/routes/store/orders/get-order.ts @@ -54,7 +54,7 @@ export default async (req, res) => { const order = await orderService.retrieveWithTotals(id, req.retrieveConfig) res.json({ - order: cleanResponseData(order, req.allowedProperties || []), + order: cleanResponseData(order, req.storeAllowedProperties || []), }) } diff --git a/packages/medusa/src/api/routes/store/orders/lookup-order.ts b/packages/medusa/src/api/routes/store/orders/lookup-order.ts index 807fddbd0ac04..743919149027c 100644 --- a/packages/medusa/src/api/routes/store/orders/lookup-order.ts +++ b/packages/medusa/src/api/routes/store/orders/lookup-order.ts @@ -100,7 +100,9 @@ export default async (req, res) => { const order = orders[0] - res.json({ order: cleanResponseData(order, req.allowedProperties || []) }) + res.json({ + order: cleanResponseData(order, req.storeAllowedProperties || []), + }) } export class ShippingAddressPayload { diff --git a/packages/medusa/src/api/routes/store/products/get-product.ts b/packages/medusa/src/api/routes/store/products/get-product.ts index c6c31410d3423..ff3c5e16413fd 100644 --- a/packages/medusa/src/api/routes/store/products/get-product.ts +++ b/packages/medusa/src/api/routes/store/products/get-product.ts @@ -118,7 +118,7 @@ export default async (req, res) => { ) res.json({ - product: cleanResponseData(product, req.allowedProperties || []), + product: cleanResponseData(product, req.storeAllowedProperties || []), }) } diff --git a/packages/medusa/src/api/routes/store/products/list-products.ts b/packages/medusa/src/api/routes/store/products/list-products.ts index 0bf67d06039a9..568c77f4d7962 100644 --- a/packages/medusa/src/api/routes/store/products/list-products.ts +++ b/packages/medusa/src/api/routes/store/products/list-products.ts @@ -253,7 +253,10 @@ export default async (req, res) => { ]) res.json({ - products: cleanResponseData(computedProducts, req.allowedProperties || []), + products: cleanResponseData( + computedProducts, + req.storeAllowedProperties || [] + ), count, offset: validated.offset, limit: validated.limit, diff --git a/packages/medusa/src/types/global.ts b/packages/medusa/src/types/global.ts index eee037ac01aee..49bca8562f9d1 100644 --- a/packages/medusa/src/types/global.ts +++ b/packages/medusa/src/types/global.ts @@ -16,7 +16,8 @@ declare global { listConfig: FindConfig retrieveConfig: FindConfig filterableFields: Record - allowedProperties: string[] + storeAllowedProperties: string[] + adminAllowedProperties: string[] errors: string[] } } diff --git a/packages/medusa/src/utils/clean-response-data.ts b/packages/medusa/src/utils/clean-response-data.ts index cca1002f7f698..33497b2518cca 100644 --- a/packages/medusa/src/utils/clean-response-data.ts +++ b/packages/medusa/src/utils/clean-response-data.ts @@ -1,21 +1,53 @@ import { pick } from "lodash" +// TODO: once the legacy totals decoration will be removed. +// We will be able to only compute the totals if one of the total fields is present +// and therefore avoid totals computation if the user don't want them to appear in the response +// and therefore the below const will be removed +const EXLCUDED_FIELDS = [ + "shipping_total", + "discount_total", + "tax_total", + "refunded_total", + "total", + "subtotal", + "paid_total", + "refundable_amount", + "gift_card_total", + "gift_card_tax_total", + "item_tax_total", + "shipping_tax_total", + "refundable", + "original_total", + "original_tax_total", +] + /** - * Filter response data to contain props specified in the fields array. + * Filter response data to contain props specified in the `storeAllowedProperties` or `adminAllowedProperties`. + * You can read more in the transformQuery middleware utility methods. * * @param data - record or an array of records in the response * @param fields - record props allowed in the response */ -function cleanResponseData(data: T, fields: string[]) { +function cleanResponseData( + data: T, + fields: string[] +): T extends [] ? Partial[] : Partial { if (!fields.length) { - return data + return data as T extends [] ? Partial[] : Partial } - if (Array.isArray(data)) { - return data.map((record) => pick(record, fields)) - } + const isDataArray = Array.isArray(data) + const fieldsSet = new Set([...fields, ...EXLCUDED_FIELDS]) + + fields = [...fieldsSet] + + let arrayData: Partial[] = isDataArray ? data : [data] + arrayData = arrayData.map((record) => pick(record, fields)) - return pick(data, fields) + return (isDataArray ? arrayData : arrayData[0]) as T extends [] + ? Partial[] + : Partial } export { cleanResponseData } From e57e23d3880cfd077054d78e377829ad07b14863 Mon Sep 17 00:00:00 2001 From: adrien2p Date: Thu, 23 Feb 2023 15:27:39 +0100 Subject: [PATCH 2/8] cleanup --- .../middlewares/transform-includes-options.ts | 14 +++++------ .../src/api/middlewares/transform-query.ts | 24 ++++++++----------- packages/medusa/src/types/global.ts | 1 + 3 files changed, 18 insertions(+), 21 deletions(-) diff --git a/packages/medusa/src/api/middlewares/transform-includes-options.ts b/packages/medusa/src/api/middlewares/transform-includes-options.ts index da10b2dbaedca..0e4593b41eee9 100644 --- a/packages/medusa/src/api/middlewares/transform-includes-options.ts +++ b/packages/medusa/src/api/middlewares/transform-includes-options.ts @@ -13,11 +13,11 @@ export function transformIncludesOptions( expectedIncludesFields: string[] = [] ) { return (req: Request, res: Response, next: NextFunction): void => { - if (!allowedIncludesFields.length || !req.query["fields"]) { + if (!allowedIncludesFields.length || !req.query.fields) { return next() } - const fields = (req.query["fields"] as string).split(",") ?? [] + const fields = (req.query.fields as string).split(",") ?? [] for (const includesField of allowedIncludesFields) { const fieldIndex = fields.indexOf(includesField as keyof Order) ?? -1 @@ -40,16 +40,16 @@ export function transformIncludesOptions( ) } - req["includes"] = req["includes"] ?? {} - req["includes"][includesField] = true + req.includes = req.includes ?? {} + req.includes[includesField] = true } } - if (req.query["fields"]) { + if (req.query.fields) { if (fields.length) { - req.query["fields"] = fields.join(",") + req.query.fields = fields.join(",") } else { - delete req.query["fields"] + delete req.query.fields } } diff --git a/packages/medusa/src/api/middlewares/transform-query.ts b/packages/medusa/src/api/middlewares/transform-query.ts index 17a7b9b7b9645..7ed5428b28d85 100644 --- a/packages/medusa/src/api/middlewares/transform-query.ts +++ b/packages/medusa/src/api/middlewares/transform-query.ts @@ -41,22 +41,16 @@ export function transformQuery< req.storeAllowedProperties = getStoreAllowedProperties( validated, - Object.keys(req["includes"] ?? {}), + req.includes ?? {}, queryConfig ) req.adminAllowedProperties = getAdminAllowedProperties( validated, - Object.keys(req["includes"] ?? {}), + req.includes ?? {}, queryConfig ) - const includesFields = Object.keys(req["includes"] ?? {}) - if (includesFields.length) { - req.storeAllowedProperties = req.storeAllowedProperties ?? [] - req.storeAllowedProperties.push(...includesFields) - } - if (queryConfig?.isList) { req.listConfig = prepareListQuery( validated, @@ -85,7 +79,7 @@ export function transformQuery< */ function getStoreAllowedProperties( validated: RequestQueryFields, - includesOptions: string[], + includesOptions: Record, queryConfig?: QueryConfig ): string[] { const allowed: string[] = [] @@ -103,8 +97,9 @@ function getStoreAllowedProperties( ) } - if (includesOptions.length) { - allowed.push(...includesOptions) + const includeKeys = Object.keys(includesOptions) + if (includeKeys) { + allowed.push(...includeKeys) } return allowed @@ -120,7 +115,7 @@ function getStoreAllowedProperties( */ function getAdminAllowedProperties( validated: RequestQueryFields, - includesOptions: string[], + includesOptions: Record, queryConfig?: QueryConfig ): string[] { const allowed: string[] = [] @@ -131,8 +126,9 @@ function getAdminAllowedProperties( ) } - if (includesOptions.length) { - allowed.push(...includesOptions) + const includeKeys = Object.keys(includesOptions) + if (includeKeys) { + allowed.push(...includeKeys) } return allowed diff --git a/packages/medusa/src/types/global.ts b/packages/medusa/src/types/global.ts index 49bca8562f9d1..707f0c1335e1a 100644 --- a/packages/medusa/src/types/global.ts +++ b/packages/medusa/src/types/global.ts @@ -18,6 +18,7 @@ declare global { filterableFields: Record storeAllowedProperties: string[] adminAllowedProperties: string[] + includes?: Record errors: string[] } } From 6d463c008d8d3651ce5fe1b3ffef73ed3ca488f3 Mon Sep 17 00:00:00 2001 From: Adrien de Peretti Date: Thu, 23 Feb 2023 15:33:01 +0100 Subject: [PATCH 3/8] Create mighty-ads-fold.md --- .changeset/mighty-ads-fold.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/mighty-ads-fold.md diff --git a/.changeset/mighty-ads-fold.md b/.changeset/mighty-ads-fold.md new file mode 100644 index 0000000000000..20e34e3175516 --- /dev/null +++ b/.changeset/mighty-ads-fold.md @@ -0,0 +1,5 @@ +--- +"@medusajs/medusa": patch +--- + +fix(medusa): Clean response data usage for admin and store fields/expand From d0267ba6a32b2d00996c02a966c77c279d8af626 Mon Sep 17 00:00:00 2001 From: adrien2p Date: Thu, 23 Feb 2023 15:54:26 +0100 Subject: [PATCH 4/8] fix integration --- integration-tests/api/__tests__/admin/order/order.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/integration-tests/api/__tests__/admin/order/order.js b/integration-tests/api/__tests__/admin/order/order.js index f1782e89fd5eb..eb1f100e4a413 100644 --- a/integration-tests/api/__tests__/admin/order/order.js +++ b/integration-tests/api/__tests__/admin/order/order.js @@ -1615,6 +1615,16 @@ describe("/admin/orders", () => { id: "test-billing-address", first_name: "lebron", }), + shipping_total: expect.any(Number), + discount_total: expect.any(Number), + tax_total: expect.any(Number), + refunded_total: expect.any(Number), + total: expect.any(Number), + subtotal: expect.any(Number), + paid_total: expect.any(Number), + refundable_amount: expect.any(Number), + gift_card_total: expect.any(Number), + gift_card_tax_total: expect.any(Number), }, ]) ) From 4bca0dfe687db56cffb077a1f44ffb343790cb36 Mon Sep 17 00:00:00 2001 From: adrien2p Date: Thu, 23 Feb 2023 16:30:39 +0100 Subject: [PATCH 5/8] fix integration --- .../api/__tests__/store/orders.js | 33 +++++++++++++++++++ .../medusa/src/utils/clean-response-data.ts | 4 +-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/integration-tests/api/__tests__/store/orders.js b/integration-tests/api/__tests__/store/orders.js index 9e5373006a0b1..0238ad0c5f76d 100644 --- a/integration-tests/api/__tests__/store/orders.js +++ b/integration-tests/api/__tests__/store/orders.js @@ -177,6 +177,17 @@ describe("/store/carts", () => { "customer", "payments", "region", + // default + "shipping_total", + "discount_total", + "tax_total", + "refunded_total", + "total", + "subtotal", + "paid_total", + "refundable_amount", + "gift_card_total", + "gift_card_tax_total", ]) }) @@ -197,6 +208,17 @@ describe("/store/carts", () => { "customer", "payments", "region", + // default + "shipping_total", + "discount_total", + "tax_total", + "refunded_total", + "total", + "subtotal", + "paid_total", + "refundable_amount", + "gift_card_total", + "gift_card_tax_total", ]) }) @@ -212,6 +234,17 @@ describe("/store/carts", () => { "status", // selected relations "billing_address", + // default + "shipping_total", + "discount_total", + "tax_total", + "refunded_total", + "total", + "subtotal", + "paid_total", + "refundable_amount", + "gift_card_total", + "gift_card_tax_total", ]) }) diff --git a/packages/medusa/src/utils/clean-response-data.ts b/packages/medusa/src/utils/clean-response-data.ts index 33497b2518cca..9c73f4d33c95c 100644 --- a/packages/medusa/src/utils/clean-response-data.ts +++ b/packages/medusa/src/utils/clean-response-data.ts @@ -4,7 +4,7 @@ import { pick } from "lodash" // We will be able to only compute the totals if one of the total fields is present // and therefore avoid totals computation if the user don't want them to appear in the response // and therefore the below const will be removed -const EXLCUDED_FIELDS = [ +const EXCLUDED_FIELDS = [ "shipping_total", "discount_total", "tax_total", @@ -38,7 +38,7 @@ function cleanResponseData( } const isDataArray = Array.isArray(data) - const fieldsSet = new Set([...fields, ...EXLCUDED_FIELDS]) + const fieldsSet = new Set([...fields, ...EXCLUDED_FIELDS]) fields = [...fieldsSet] From d4be34e2fda6b48c2145ae1c8f82ae08974e0e84 Mon Sep 17 00:00:00 2001 From: adrien2p Date: Mon, 27 Feb 2023 13:42:14 +0100 Subject: [PATCH 6/8] refactor transform query and cleanup --- packages/medusa/src/api/middlewares/index.ts | 2 +- .../src/api/middlewares/transform-query.ts | 141 ++++++++++++------ .../src/api/routes/admin/orders/get-order.ts | 2 +- .../api/routes/admin/orders/list-orders.ts | 2 +- .../src/api/routes/store/carts/index.ts | 6 +- .../src/api/routes/store/collections/index.ts | 4 +- .../src/api/routes/store/customers/index.ts | 4 +- .../src/api/routes/store/order-edits/index.ts | 4 +- .../src/api/routes/store/orders/index.ts | 6 +- .../routes/store/payment-collections/index.ts | 4 +- .../routes/store/product-categories/index.ts | 6 +- .../api/routes/store/product-tags/index.ts | 4 +- .../api/routes/store/product-types/index.ts | 4 +- .../src/api/routes/store/products/index.ts | 8 +- packages/medusa/src/types/global.ts | 3 +- .../medusa/src/utils/clean-response-data.ts | 2 +- 16 files changed, 126 insertions(+), 76 deletions(-) diff --git a/packages/medusa/src/api/middlewares/index.ts b/packages/medusa/src/api/middlewares/index.ts index 68aa757c54674..654ae3e8b4fcb 100644 --- a/packages/medusa/src/api/middlewares/index.ts +++ b/packages/medusa/src/api/middlewares/index.ts @@ -9,7 +9,7 @@ export { getRequestedBatchJob } from "./batch-job/get-requested-batch-job" export { doesConditionBelongToDiscount } from "./discount/does-condition-belong-to-discount" export { transformIncludesOptions } from "./transform-includes-options" export { transformBody } from "./transform-body" -export { transformQuery } from "./transform-query" +export { transformQuery, transformStoreQuery } from "./transform-query" export default { authenticate, diff --git a/packages/medusa/src/api/middlewares/transform-query.ts b/packages/medusa/src/api/middlewares/transform-query.ts index 7ed5428b28d85..6230314c83f7c 100644 --- a/packages/medusa/src/api/middlewares/transform-query.ts +++ b/packages/medusa/src/api/middlewares/transform-query.ts @@ -12,12 +12,21 @@ import { FindConfig, QueryConfig, RequestQueryFields } from "../../types/common" import { omit } from "lodash" import { removeUndefinedProperties } from "../../utils" +/** + * Middleware that transform the query input for the admin end points + * @param plainToClass + * @param queryConfig + * @param config + */ export function transformQuery< T extends RequestQueryFields, TEntity extends BaseEntity >( plainToClass: ClassConstructor, - queryConfig?: QueryConfig, + queryConfig?: Omit< + QueryConfig, + "allowedRelations" | "allowedFields" + >, config: ValidatorOptions = {} ): (req: Request, res: Response, next: NextFunction) => Promise { return async (req: Request, res: Response, next: NextFunction) => { @@ -29,39 +38,51 @@ export function transformQuery< config ) req.validatedQuery = validated - - req.filterableFields = omit(validated, [ - "limit", - "offset", - "expand", - "fields", - "order", - ]) - req.filterableFields = removeUndefinedProperties(req.filterableFields) - - req.storeAllowedProperties = getStoreAllowedProperties( + req.filterableFields = getFilterableFields(validated) + req.allowedProperties = getAllowedProperties( validated, req.includes ?? {}, queryConfig ) + attachListOrRetrieveConfig(req, queryConfig) - req.adminAllowedProperties = getAdminAllowedProperties( + next() + } catch (e) { + next(e) + } + } +} + +/** + * Middleware that transform the query input for the admin end points + * @param plainToClass + * @param queryConfig + * @param config + */ +export function transformStoreQuery< + T extends RequestQueryFields, + TEntity extends BaseEntity +>( + plainToClass: ClassConstructor, + queryConfig?: QueryConfig, + config: ValidatorOptions = {} +): (req: Request, res: Response, next: NextFunction) => Promise { + return async (req: Request, res: Response, next: NextFunction) => { + try { + normalizeQuery()(req, res, () => void 0) + const validated: T = await validator>( + plainToClass, + req.query, + config + ) + req.validatedQuery = validated + req.filterableFields = getFilterableFields(validated) + req.allowedProperties = getStoreAllowedProperties( validated, req.includes ?? {}, queryConfig ) - - if (queryConfig?.isList) { - req.listConfig = prepareListQuery( - validated, - queryConfig - ) as FindConfig - } else { - req.retrieveConfig = prepareRetrieveQuery( - validated, - queryConfig - ) as FindConfig - } + attachListOrRetrieveConfig(req, queryConfig) next() } catch (e) { @@ -70,6 +91,43 @@ export function transformQuery< } } +/** + * Omit the non filterable config from the validated object + * @param obj + */ +function getFilterableFields(obj: T): T { + const result = omit(obj, [ + "limit", + "offset", + "expand", + "fields", + "order", + ]) as T + return removeUndefinedProperties(result) +} + +/** + * build and attach the `retrieveConfig` or `listConfig` + * @param req + * @param queryConfig + */ +function attachListOrRetrieveConfig( + req: Request, + queryConfig?: QueryConfig +) { + const validated = req.validatedQuery + if (queryConfig?.isList) { + req.listConfig = prepareListQuery( + validated, + queryConfig + ) as FindConfig + } else { + req.retrieveConfig = prepareRetrieveQuery( + validated, + queryConfig + ) as FindConfig + } +} /** * Build the store allowed props based on the custom fields query params, the defaults and the includes options. * This can be used later with `cleanResponseData` in order to clean up the returned objects to the client. @@ -83,19 +141,14 @@ function getStoreAllowedProperties( queryConfig?: QueryConfig ): string[] { const allowed: string[] = [] - if ( - (queryConfig?.defaultFields || validated.fields) && - (queryConfig?.defaultRelations || validated.expand) - ) { - allowed.push( - ...(validated.fields - ? validated.fields.split(",") - : queryConfig?.allowedFields || []), - ...(validated.expand - ? validated.expand.split(",") - : queryConfig?.allowedRelations || []) - ) - } + allowed.push( + ...(validated.fields + ? validated.fields.split(",") + : queryConfig?.allowedFields || []), + ...(validated.expand + ? validated.expand.split(",") + : queryConfig?.allowedRelations || []) + ) const includeKeys = Object.keys(includesOptions) if (includeKeys) { @@ -113,18 +166,16 @@ function getStoreAllowedProperties( * @param validated * @param includesOptions */ -function getAdminAllowedProperties( +function getAllowedProperties( validated: RequestQueryFields, includesOptions: Record, queryConfig?: QueryConfig ): string[] { const allowed: string[] = [] - if (validated.fields || validated.expand) { - allowed.push( - ...(validated.fields?.split(",") ?? []), - ...(validated.expand?.split(",") ?? []) - ) - } + allowed.push( + ...(validated.fields?.split(",") ?? []), + ...(validated.expand?.split(",") ?? []) + ) const includeKeys = Object.keys(includesOptions) if (includeKeys) { diff --git a/packages/medusa/src/api/routes/admin/orders/get-order.ts b/packages/medusa/src/api/routes/admin/orders/get-order.ts index b30a923197397..2b815f535a976 100644 --- a/packages/medusa/src/api/routes/admin/orders/get-order.ts +++ b/packages/medusa/src/api/routes/admin/orders/get-order.ts @@ -70,7 +70,7 @@ export default async (req, res) => { } ) - order = cleanResponseData(order, req.adminAllowedProperties) + order = cleanResponseData(order, req.allowedProperties) res.json({ order: order }) } diff --git a/packages/medusa/src/api/routes/admin/orders/list-orders.ts b/packages/medusa/src/api/routes/admin/orders/list-orders.ts index 6ddc9dfb8df56..1abc6abb73075 100644 --- a/packages/medusa/src/api/routes/admin/orders/list-orders.ts +++ b/packages/medusa/src/api/routes/admin/orders/list-orders.ts @@ -206,7 +206,7 @@ export default async (req, res) => { req.listConfig ) - const data = cleanResponseData(orders, req.adminAllowedProperties) + const data = cleanResponseData(orders, req.allowedProperties) res.json({ orders: data, count, offset: skip, limit: take }) } diff --git a/packages/medusa/src/api/routes/store/carts/index.ts b/packages/medusa/src/api/routes/store/carts/index.ts index b812105920496..228bd222b5ae1 100644 --- a/packages/medusa/src/api/routes/store/carts/index.ts +++ b/packages/medusa/src/api/routes/store/carts/index.ts @@ -1,11 +1,11 @@ import "reflect-metadata" -import { RequestHandler, Router } from "express" +import { Router } from "express" import { Cart, Order, Swap } from "../../../../" import { FindParams } from "../../../../types/common" import middlewares, { transformBody, - transformQuery, + transformStoreQuery, } from "../../../middlewares" import { StorePostCartsCartReq } from "./update-cart" import { StorePostCartReq } from "./create-cart" @@ -33,7 +33,7 @@ export default (app, container) => { route.get( "/:id", - transformQuery(FindParams, { + transformStoreQuery(FindParams, { defaultRelations: defaultStoreCartRelations, defaultFields: defaultStoreCartFields, isList: false, diff --git a/packages/medusa/src/api/routes/store/collections/index.ts b/packages/medusa/src/api/routes/store/collections/index.ts index 2d85a73050ab4..e5ec450efbc93 100644 --- a/packages/medusa/src/api/routes/store/collections/index.ts +++ b/packages/medusa/src/api/routes/store/collections/index.ts @@ -1,7 +1,7 @@ import { Router } from "express" import { PaginatedResponse } from "../../../../types/common" import { ProductCollection } from "../../../../" -import middlewares, { transformQuery } from "../../../middlewares" +import middlewares, { transformStoreQuery } from "../../../middlewares" import { StoreGetCollectionsParams } from "./list-collections" const route = Router() @@ -11,7 +11,7 @@ export default (app) => { route.get( "/", - transformQuery(StoreGetCollectionsParams, { + transformStoreQuery(StoreGetCollectionsParams, { allowedFields, isList: true, }), diff --git a/packages/medusa/src/api/routes/store/customers/index.ts b/packages/medusa/src/api/routes/store/customers/index.ts index 0d597f97b4477..df14786dd73ea 100644 --- a/packages/medusa/src/api/routes/store/customers/index.ts +++ b/packages/medusa/src/api/routes/store/customers/index.ts @@ -1,7 +1,7 @@ import { Router } from "express" import { Customer, Order } from "../../../.." import { PaginatedResponse } from "../../../../types/common" -import middlewares, { transformQuery } from "../../../middlewares" +import middlewares, { transformStoreQuery } from "../../../middlewares" import { defaultStoreOrdersFields, defaultStoreOrdersRelations, @@ -41,7 +41,7 @@ export default (app, container) => { route.get( "/me/orders", - transformQuery(StoreGetCustomersCustomerOrdersParams, { + transformStoreQuery(StoreGetCustomersCustomerOrdersParams, { defaultFields: defaultStoreOrdersFields, defaultRelations: defaultStoreOrdersRelations, isList: true, diff --git a/packages/medusa/src/api/routes/store/order-edits/index.ts b/packages/medusa/src/api/routes/store/order-edits/index.ts index cd822cd414dea..e6e8de1b5d035 100644 --- a/packages/medusa/src/api/routes/store/order-edits/index.ts +++ b/packages/medusa/src/api/routes/store/order-edits/index.ts @@ -7,7 +7,7 @@ import { } from "../../../../types/order-edit" import middlewares, { transformBody, - transformQuery, + transformStoreQuery, } from "../../../middlewares" import { StorePostOrderEditsOrderEditDecline } from "./decline-order-edit" @@ -18,7 +18,7 @@ export default (app) => { route.get( "/:id", - transformQuery(FindParams, { + transformStoreQuery(FindParams, { defaultRelations: defaultStoreOrderEditRelations, defaultFields: defaultStoreOrderEditFields, allowedFields: defaultStoreOrderEditFields, diff --git a/packages/medusa/src/api/routes/store/orders/index.ts b/packages/medusa/src/api/routes/store/orders/index.ts index 2607ebe297f3f..10f3d85da8e57 100644 --- a/packages/medusa/src/api/routes/store/orders/index.ts +++ b/packages/medusa/src/api/routes/store/orders/index.ts @@ -3,7 +3,7 @@ import "reflect-metadata" import { Order } from "../../../.." import middlewares, { transformBody, - transformQuery, + transformStoreQuery, } from "../../../middlewares" import requireCustomerAuthentication from "../../../middlewares/require-customer-authentication" import { StorePostCustomersCustomerOrderClaimReq } from "./request-order" @@ -21,7 +21,7 @@ export default (app) => { */ route.get( "/", - transformQuery(StoreGetOrdersParams, { + transformStoreQuery(StoreGetOrdersParams, { defaultFields: defaultStoreOrdersFields, defaultRelations: defaultStoreOrdersRelations, allowedFields: allowedStoreOrdersFields, @@ -36,7 +36,7 @@ export default (app) => { */ route.get( "/:id", - transformQuery(StoreGetOrderParams, { + transformStoreQuery(StoreGetOrderParams, { defaultFields: defaultStoreOrdersFields, defaultRelations: defaultStoreOrdersRelations, allowedFields: allowedStoreOrdersFields, diff --git a/packages/medusa/src/api/routes/store/payment-collections/index.ts b/packages/medusa/src/api/routes/store/payment-collections/index.ts index 5a3b14665c0a1..aa0d9d97b97b5 100644 --- a/packages/medusa/src/api/routes/store/payment-collections/index.ts +++ b/packages/medusa/src/api/routes/store/payment-collections/index.ts @@ -2,7 +2,7 @@ import { Router } from "express" import "reflect-metadata" import middlewares, { transformBody, - transformQuery, + transformStoreQuery, } from "../../../middlewares" import { PaymentCollection, PaymentSession } from "../../../../models" @@ -18,7 +18,7 @@ export default (app, container) => { route.get( "/:id", - transformQuery(StoreGetPaymentCollectionsParams, { + transformStoreQuery(StoreGetPaymentCollectionsParams, { defaultFields: defaultPaymentCollectionFields, defaultRelations: defaultPaymentCollectionRelations, isList: false, diff --git a/packages/medusa/src/api/routes/store/product-categories/index.ts b/packages/medusa/src/api/routes/store/product-categories/index.ts index 31d6344afbbd9..54435a8090c12 100644 --- a/packages/medusa/src/api/routes/store/product-categories/index.ts +++ b/packages/medusa/src/api/routes/store/product-categories/index.ts @@ -1,5 +1,5 @@ import { Router } from "express" -import middlewares, { transformQuery } from "../../../middlewares" +import middlewares, { transformStoreQuery } from "../../../middlewares" import { ProductCategory } from "../../../../models" import { PaginatedResponse } from "../../../../types/common" @@ -18,7 +18,7 @@ export default (app) => { route.get( "/", - transformQuery(StoreGetProductCategoriesParams, { + transformStoreQuery(StoreGetProductCategoriesParams, { defaultFields: defaultStoreProductCategoryFields, allowedFields: allowedStoreProductCategoryFields, defaultRelations: defaultStoreProductCategoryRelations, @@ -29,7 +29,7 @@ export default (app) => { route.get( "/:id", - transformQuery(StoreGetProductCategoryParams, { + transformStoreQuery(StoreGetProductCategoryParams, { defaultFields: defaultStoreProductCategoryFields, allowedFields: allowedStoreProductCategoryFields, defaultRelations: defaultStoreProductCategoryRelations, diff --git a/packages/medusa/src/api/routes/store/product-tags/index.ts b/packages/medusa/src/api/routes/store/product-tags/index.ts index ea9c0a5ef9c5d..fcdb1765cec40 100644 --- a/packages/medusa/src/api/routes/store/product-tags/index.ts +++ b/packages/medusa/src/api/routes/store/product-tags/index.ts @@ -1,7 +1,7 @@ import { Router } from "express" import { ProductTag } from "../../../../models" import { PaginatedResponse } from "../../../../types/common" -import middlewares, { transformQuery } from "../../../middlewares" +import middlewares, { transformStoreQuery } from "../../../middlewares" import { StoreGetProductTagsParams } from "./list-product-tags" const route = Router() @@ -11,7 +11,7 @@ export default (app: Router) => { route.get( "/", - transformQuery(StoreGetProductTagsParams, { + transformStoreQuery(StoreGetProductTagsParams, { defaultFields: defaultStoreProductTagFields, defaultRelations: defaultStoreProductTagRelations, allowedFields: allowedStoreProductTagFields, diff --git a/packages/medusa/src/api/routes/store/product-types/index.ts b/packages/medusa/src/api/routes/store/product-types/index.ts index 8aade5ef0bf55..6b30b20a0374b 100644 --- a/packages/medusa/src/api/routes/store/product-types/index.ts +++ b/packages/medusa/src/api/routes/store/product-types/index.ts @@ -1,7 +1,7 @@ import { Router } from "express" import { ProductType } from "../../../.." import { PaginatedResponse } from "../../../../types/common" -import middlewares, { transformQuery } from "../../../middlewares" +import middlewares, { transformStoreQuery } from "../../../middlewares" import "reflect-metadata" import { StoreGetProductTypesParams } from "./list-product-types" @@ -12,7 +12,7 @@ export default (app) => { route.get( "/", - transformQuery(StoreGetProductTypesParams, { + transformStoreQuery(StoreGetProductTypesParams, { defaultFields: defaultStoreProductTypeFields, defaultRelations: defaultStoreProductTypeRelations, allowedFields: allowedStoreProductTypeFields, diff --git a/packages/medusa/src/api/routes/store/products/index.ts b/packages/medusa/src/api/routes/store/products/index.ts index 8e3d264f0491c..afcdf9153062c 100644 --- a/packages/medusa/src/api/routes/store/products/index.ts +++ b/packages/medusa/src/api/routes/store/products/index.ts @@ -1,8 +1,8 @@ -import { RequestHandler, Router } from "express" +import { Router } from "express" import "reflect-metadata" import { Product } from "../../../.." -import middlewares, { transformQuery } from "../../../middlewares" +import middlewares, { transformStoreQuery } from "../../../middlewares" import { PaginatedResponse } from "../../../../types/common" import { extendRequestParams } from "../../../middlewares/publishable-api-key/extend-request-params" import { validateProductSalesChannelAssociation } from "../../../middlewares/publishable-api-key/validate-product-sales-channel-association" @@ -19,7 +19,7 @@ export default (app) => { route.get( "/", - transformQuery(StoreGetProductsParams, { + transformStoreQuery(StoreGetProductsParams, { defaultRelations: defaultStoreProductsRelations, defaultFields: defaultStoreProductsFields, allowedFields: allowedStoreProductsFields, @@ -31,7 +31,7 @@ export default (app) => { route.get( "/:id", - transformQuery(StoreGetProductsProductParams, { + transformStoreQuery(StoreGetProductsProductParams, { defaultRelations: defaultStoreProductsRelations, defaultFields: defaultStoreProductsFields, allowedFields: allowedStoreProductsFields, diff --git a/packages/medusa/src/types/global.ts b/packages/medusa/src/types/global.ts index d6763a8a99826..54d270cf60fb2 100644 --- a/packages/medusa/src/types/global.ts +++ b/packages/medusa/src/types/global.ts @@ -20,8 +20,7 @@ declare global { listConfig: FindConfig retrieveConfig: FindConfig filterableFields: Record - storeAllowedProperties: string[] - adminAllowedProperties: string[] + allowedProperties: string[] includes?: Record errors: string[] } diff --git a/packages/medusa/src/utils/clean-response-data.ts b/packages/medusa/src/utils/clean-response-data.ts index 9c73f4d33c95c..4f667466a4ea8 100644 --- a/packages/medusa/src/utils/clean-response-data.ts +++ b/packages/medusa/src/utils/clean-response-data.ts @@ -23,7 +23,7 @@ const EXCLUDED_FIELDS = [ ] /** - * Filter response data to contain props specified in the `storeAllowedProperties` or `adminAllowedProperties`. + * Filter response data to contain props specified in the `storeAllowedProperties` or `allowedProperties`. * You can read more in the transformQuery middleware utility methods. * * @param data - record or an array of records in the response From 0de47d11521d94a046ef54f6f7bd3d7b693b8a90 Mon Sep 17 00:00:00 2001 From: adrien2p Date: Mon, 27 Feb 2023 15:55:41 +0100 Subject: [PATCH 7/8] fix missing re naming --- packages/medusa/src/api/routes/store/orders/get-order.ts | 2 +- packages/medusa/src/api/routes/store/orders/lookup-order.ts | 2 +- packages/medusa/src/api/routes/store/products/get-product.ts | 2 +- .../medusa/src/api/routes/store/products/list-products.ts | 5 +---- packages/medusa/src/utils/clean-response-data.ts | 2 +- packages/modules-sdk/package.json | 3 +-- 6 files changed, 6 insertions(+), 10 deletions(-) diff --git a/packages/medusa/src/api/routes/store/orders/get-order.ts b/packages/medusa/src/api/routes/store/orders/get-order.ts index 399d283111cc0..fb99dcfef0487 100644 --- a/packages/medusa/src/api/routes/store/orders/get-order.ts +++ b/packages/medusa/src/api/routes/store/orders/get-order.ts @@ -54,7 +54,7 @@ export default async (req, res) => { const order = await orderService.retrieveWithTotals(id, req.retrieveConfig) res.json({ - order: cleanResponseData(order, req.storeAllowedProperties || []), + order: cleanResponseData(order, req.allowedProperties || []), }) } diff --git a/packages/medusa/src/api/routes/store/orders/lookup-order.ts b/packages/medusa/src/api/routes/store/orders/lookup-order.ts index 743919149027c..7c2b5b03b9037 100644 --- a/packages/medusa/src/api/routes/store/orders/lookup-order.ts +++ b/packages/medusa/src/api/routes/store/orders/lookup-order.ts @@ -101,7 +101,7 @@ export default async (req, res) => { const order = orders[0] res.json({ - order: cleanResponseData(order, req.storeAllowedProperties || []), + order: cleanResponseData(order, req.allowedProperties || []), }) } diff --git a/packages/medusa/src/api/routes/store/products/get-product.ts b/packages/medusa/src/api/routes/store/products/get-product.ts index ff3c5e16413fd..c6c31410d3423 100644 --- a/packages/medusa/src/api/routes/store/products/get-product.ts +++ b/packages/medusa/src/api/routes/store/products/get-product.ts @@ -118,7 +118,7 @@ export default async (req, res) => { ) res.json({ - product: cleanResponseData(product, req.storeAllowedProperties || []), + product: cleanResponseData(product, req.allowedProperties || []), }) } diff --git a/packages/medusa/src/api/routes/store/products/list-products.ts b/packages/medusa/src/api/routes/store/products/list-products.ts index 568c77f4d7962..0bf67d06039a9 100644 --- a/packages/medusa/src/api/routes/store/products/list-products.ts +++ b/packages/medusa/src/api/routes/store/products/list-products.ts @@ -253,10 +253,7 @@ export default async (req, res) => { ]) res.json({ - products: cleanResponseData( - computedProducts, - req.storeAllowedProperties || [] - ), + products: cleanResponseData(computedProducts, req.allowedProperties || []), count, offset: validated.offset, limit: validated.limit, diff --git a/packages/medusa/src/utils/clean-response-data.ts b/packages/medusa/src/utils/clean-response-data.ts index 4f667466a4ea8..44028413efddc 100644 --- a/packages/medusa/src/utils/clean-response-data.ts +++ b/packages/medusa/src/utils/clean-response-data.ts @@ -23,7 +23,7 @@ const EXCLUDED_FIELDS = [ ] /** - * Filter response data to contain props specified in the `storeAllowedProperties` or `allowedProperties`. + * Filter response data to contain props specified in the `allowedProperties`. * You can read more in the transformQuery middleware utility methods. * * @param data - record or an array of records in the response diff --git a/packages/modules-sdk/package.json b/packages/modules-sdk/package.json index da41257d040e2..3fa52def4d31b 100644 --- a/packages/modules-sdk/package.json +++ b/packages/modules-sdk/package.json @@ -32,6 +32,5 @@ "build": "tsc --build", "test": "jest", "test:unit": "jest" - }, - "peerDependencies": {} + } } From 101076d742885776900d4a4e26cadfe29f29369d Mon Sep 17 00:00:00 2001 From: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com> Date: Tue, 28 Feb 2023 09:06:37 +0100 Subject: [PATCH 8/8] Update packages/medusa/src/api/middlewares/transform-query.ts --- packages/medusa/src/api/middlewares/transform-query.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/medusa/src/api/middlewares/transform-query.ts b/packages/medusa/src/api/middlewares/transform-query.ts index 6230314c83f7c..31dccfa9184a2 100644 --- a/packages/medusa/src/api/middlewares/transform-query.ts +++ b/packages/medusa/src/api/middlewares/transform-query.ts @@ -54,7 +54,7 @@ export function transformQuery< } /** - * Middleware that transform the query input for the admin end points + * Middleware that transform the query input for the store endpoints * @param plainToClass * @param queryConfig * @param config