fix(medusa): Clean response data usage for admin and store fields/expand (#3323)
* fix(medusa): Clean response data usage for admin and store fields/expand * cleanup * Create mighty-ads-fold.md * fix integration * fix integration * refactor transform query and cleanup * fix missing re naming * Update packages/medusa/src/api/middlewares/transform-query.ts --------- Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
1 parent
0a02b70e59
commit
cbbf3ca054
22 files changed
+287
-96
No files matched your search
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/medusa": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix(medusa): Clean response data usage for admin and store fields/expand
|
||||||
@@ -1615,6 +1615,16 @@ describe("/admin/orders", () => {
|
|||||||
id: "test-billing-address",
|
id: "test-billing-address",
|
||||||
first_name: "lebron",
|
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),
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -177,6 +177,17 @@ describe("/store/carts", () => {
|
|||||||
"customer",
|
"customer",
|
||||||
"payments",
|
"payments",
|
||||||
"region",
|
"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",
|
"customer",
|
||||||
"payments",
|
"payments",
|
||||||
"region",
|
"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",
|
"status",
|
||||||
// selected relations
|
// selected relations
|
||||||
"billing_address",
|
"billing_address",
|
||||||
|
// default
|
||||||
|
"shipping_total",
|
||||||
|
"discount_total",
|
||||||
|
"tax_total",
|
||||||
|
"refunded_total",
|
||||||
|
"total",
|
||||||
|
"subtotal",
|
||||||
|
"paid_total",
|
||||||
|
"refundable_amount",
|
||||||
|
"gift_card_total",
|
||||||
|
"gift_card_tax_total",
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export { getRequestedBatchJob } from "./batch-job/get-requested-batch-job"
|
|||||||
export { doesConditionBelongToDiscount } from "./discount/does-condition-belong-to-discount"
|
export { doesConditionBelongToDiscount } from "./discount/does-condition-belong-to-discount"
|
||||||
export { transformIncludesOptions } from "./transform-includes-options"
|
export { transformIncludesOptions } from "./transform-includes-options"
|
||||||
export { transformBody } from "./transform-body"
|
export { transformBody } from "./transform-body"
|
||||||
export { transformQuery } from "./transform-query"
|
export { transformQuery, transformStoreQuery } from "./transform-query"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
authenticate,
|
authenticate,
|
||||||
|
|||||||
@@ -13,11 +13,11 @@ export function transformIncludesOptions(
|
|||||||
expectedIncludesFields: string[] = []
|
expectedIncludesFields: string[] = []
|
||||||
) {
|
) {
|
||||||
return (req: Request, res: Response, next: NextFunction): void => {
|
return (req: Request, res: Response, next: NextFunction): void => {
|
||||||
if (!allowedIncludesFields.length || !req.query["fields"]) {
|
if (!allowedIncludesFields.length || !req.query.fields) {
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
|
|
||||||
const fields = (req.query["fields"] as string).split(",") ?? []
|
const fields = (req.query.fields as string).split(",") ?? []
|
||||||
|
|
||||||
for (const includesField of allowedIncludesFields) {
|
for (const includesField of allowedIncludesFields) {
|
||||||
const fieldIndex = fields.indexOf(includesField as keyof Order) ?? -1
|
const fieldIndex = fields.indexOf(includesField as keyof Order) ?? -1
|
||||||
@@ -40,16 +40,16 @@ export function transformIncludesOptions(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
req["includes"] = req["includes"] ?? {}
|
req.includes = req.includes ?? {}
|
||||||
req["includes"][includesField] = true
|
req.includes[includesField] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.query["fields"]) {
|
if (req.query.fields) {
|
||||||
if (fields.length) {
|
if (fields.length) {
|
||||||
req.query["fields"] = fields.join(",")
|
req.query.fields = fields.join(",")
|
||||||
} else {
|
} else {
|
||||||
delete req.query["fields"]
|
delete req.query.fields
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,9 +12,56 @@ import { FindConfig, QueryConfig, RequestQueryFields } from "../../types/common"
|
|||||||
import { omit } from "lodash"
|
import { omit } from "lodash"
|
||||||
import { removeUndefinedProperties } from "../../utils"
|
import { removeUndefinedProperties } from "../../utils"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Middleware that transform the query input for the admin end points
|
||||||
|
* @param plainToClass
|
||||||
|
* @param queryConfig
|
||||||
|
* @param config
|
||||||
|
*/
|
||||||
export function transformQuery<
|
export function transformQuery<
|
||||||
T extends RequestQueryFields,
|
T extends RequestQueryFields,
|
||||||
TEntity extends BaseEntity
|
TEntity extends BaseEntity
|
||||||
|
>(
|
||||||
|
plainToClass: ClassConstructor<T>,
|
||||||
|
queryConfig?: Omit<
|
||||||
|
QueryConfig<TEntity>,
|
||||||
|
"allowedRelations" | "allowedFields"
|
||||||
|
>,
|
||||||
|
config: ValidatorOptions = {}
|
||||||
|
): (req: Request, res: Response, next: NextFunction) => Promise<void> {
|
||||||
|
return async (req: Request, res: Response, next: NextFunction) => {
|
||||||
|
try {
|
||||||
|
normalizeQuery()(req, res, () => void 0)
|
||||||
|
const validated: T = await validator<T, Record<string, unknown>>(
|
||||||
|
plainToClass,
|
||||||
|
req.query,
|
||||||
|
config
|
||||||
|
)
|
||||||
|
req.validatedQuery = validated
|
||||||
|
req.filterableFields = getFilterableFields(validated)
|
||||||
|
req.allowedProperties = getAllowedProperties(
|
||||||
|
validated,
|
||||||
|
req.includes ?? {},
|
||||||
|
queryConfig
|
||||||
|
)
|
||||||
|
attachListOrRetrieveConfig<TEntity>(req, queryConfig)
|
||||||
|
|
||||||
|
next()
|
||||||
|
} catch (e) {
|
||||||
|
next(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Middleware that transform the query input for the store endpoints
|
||||||
|
* @param plainToClass
|
||||||
|
* @param queryConfig
|
||||||
|
* @param config
|
||||||
|
*/
|
||||||
|
export function transformStoreQuery<
|
||||||
|
T extends RequestQueryFields,
|
||||||
|
TEntity extends BaseEntity
|
||||||
>(
|
>(
|
||||||
plainToClass: ClassConstructor<T>,
|
plainToClass: ClassConstructor<T>,
|
||||||
queryConfig?: QueryConfig<TEntity>,
|
queryConfig?: QueryConfig<TEntity>,
|
||||||
@@ -29,47 +76,13 @@ export function transformQuery<
|
|||||||
config
|
config
|
||||||
)
|
)
|
||||||
req.validatedQuery = validated
|
req.validatedQuery = validated
|
||||||
|
req.filterableFields = getFilterableFields(validated)
|
||||||
req.filterableFields = omit(validated, [
|
req.allowedProperties = getStoreAllowedProperties(
|
||||||
"limit",
|
validated,
|
||||||
"offset",
|
req.includes ?? {},
|
||||||
"expand",
|
queryConfig
|
||||||
"fields",
|
)
|
||||||
"order",
|
attachListOrRetrieveConfig<TEntity>(req, queryConfig)
|
||||||
])
|
|
||||||
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[]
|
|
||||||
}
|
|
||||||
|
|
||||||
const includesFields = Object.keys(req["includes"] ?? {})
|
|
||||||
if (includesFields.length) {
|
|
||||||
req.allowedProperties = req.allowedProperties ?? []
|
|
||||||
req.allowedProperties.push(...includesFields)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (queryConfig?.isList) {
|
|
||||||
req.listConfig = prepareListQuery(
|
|
||||||
validated,
|
|
||||||
queryConfig
|
|
||||||
) as FindConfig<unknown>
|
|
||||||
} else {
|
|
||||||
req.retrieveConfig = prepareRetrieveQuery(
|
|
||||||
validated,
|
|
||||||
queryConfig
|
|
||||||
) as FindConfig<unknown>
|
|
||||||
}
|
|
||||||
|
|
||||||
next()
|
next()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -77,3 +90,97 @@ export function transformQuery<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Omit the non filterable config from the validated object
|
||||||
|
* @param obj
|
||||||
|
*/
|
||||||
|
function getFilterableFields<T extends RequestQueryFields>(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<TEntity extends BaseEntity>(
|
||||||
|
req: Request,
|
||||||
|
queryConfig?: QueryConfig<TEntity>
|
||||||
|
) {
|
||||||
|
const validated = req.validatedQuery
|
||||||
|
if (queryConfig?.isList) {
|
||||||
|
req.listConfig = prepareListQuery(
|
||||||
|
validated,
|
||||||
|
queryConfig
|
||||||
|
) as FindConfig<unknown>
|
||||||
|
} else {
|
||||||
|
req.retrieveConfig = prepareRetrieveQuery(
|
||||||
|
validated,
|
||||||
|
queryConfig
|
||||||
|
) as FindConfig<unknown>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 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<TEntity extends BaseEntity>(
|
||||||
|
validated: RequestQueryFields,
|
||||||
|
includesOptions: Record<string, boolean>,
|
||||||
|
queryConfig?: QueryConfig<TEntity>
|
||||||
|
): string[] {
|
||||||
|
const allowed: string[] = []
|
||||||
|
allowed.push(
|
||||||
|
...(validated.fields
|
||||||
|
? validated.fields.split(",")
|
||||||
|
: queryConfig?.allowedFields || []),
|
||||||
|
...(validated.expand
|
||||||
|
? validated.expand.split(",")
|
||||||
|
: queryConfig?.allowedRelations || [])
|
||||||
|
)
|
||||||
|
|
||||||
|
const includeKeys = Object.keys(includesOptions)
|
||||||
|
if (includeKeys) {
|
||||||
|
allowed.push(...includeKeys)
|
||||||
|
}
|
||||||
|
|
||||||
|
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 getAllowedProperties<TEntity extends BaseEntity>(
|
||||||
|
validated: RequestQueryFields,
|
||||||
|
includesOptions: Record<string, boolean>,
|
||||||
|
queryConfig?: QueryConfig<TEntity>
|
||||||
|
): string[] {
|
||||||
|
const allowed: string[] = []
|
||||||
|
allowed.push(
|
||||||
|
...(validated.fields?.split(",") ?? []),
|
||||||
|
...(validated.expand?.split(",") ?? [])
|
||||||
|
)
|
||||||
|
|
||||||
|
const includeKeys = Object.keys(includesOptions)
|
||||||
|
if (includeKeys) {
|
||||||
|
allowed.push(...includeKeys)
|
||||||
|
}
|
||||||
|
|
||||||
|
return allowed
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
import { OrderService } from "../../../../services"
|
import { OrderService } from "../../../../services"
|
||||||
import { FindParams } from "../../../../types/common"
|
import { FindParams } from "../../../../types/common"
|
||||||
|
import { cleanResponseData } from "../../../../utils/clean-response-data"
|
||||||
|
import { Order } from "../../../../models"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @oas [get] /admin/orders/{id}
|
* @oas [get] /admin/orders/{id}
|
||||||
@@ -60,9 +62,15 @@ export default async (req, res) => {
|
|||||||
|
|
||||||
const orderService: OrderService = req.scope.resolve("orderService")
|
const orderService: OrderService = req.scope.resolve("orderService")
|
||||||
|
|
||||||
const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, {
|
let order: Partial<Order> = await orderService.retrieveWithTotals(
|
||||||
includes: req.includes,
|
id,
|
||||||
})
|
req.retrieveConfig,
|
||||||
|
{
|
||||||
|
includes: req.includes,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
order = cleanResponseData(order, req.allowedProperties)
|
||||||
|
|
||||||
res.json({ order: order })
|
res.json({ order: order })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import { IsNumber, IsOptional, IsString } from "class-validator"
|
import { IsNumber, IsOptional, IsString } from "class-validator"
|
||||||
|
|
||||||
import { AdminListOrdersSelector } from "../../../../types/orders"
|
import { AdminListOrdersSelector } from "../../../../types/orders"
|
||||||
import { Order } from "../../../../models"
|
|
||||||
import { OrderService } from "../../../../services"
|
import { OrderService } from "../../../../services"
|
||||||
import { Type } from "class-transformer"
|
import { Type } from "class-transformer"
|
||||||
import { pick } from "lodash"
|
import { cleanResponseData } from "../../../../utils/clean-response-data"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @oas [get] /admin/orders
|
* @oas [get] /admin/orders
|
||||||
@@ -200,19 +199,14 @@ import { pick } from "lodash"
|
|||||||
export default async (req, res) => {
|
export default async (req, res) => {
|
||||||
const orderService: OrderService = req.scope.resolve("orderService")
|
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(
|
const [orders, count] = await orderService.listAndCount(
|
||||||
req.filterableFields,
|
req.filterableFields,
|
||||||
req.listConfig
|
req.listConfig
|
||||||
)
|
)
|
||||||
|
|
||||||
let data: Partial<Order>[] = orders
|
const data = cleanResponseData(orders, req.allowedProperties)
|
||||||
|
|
||||||
const fields = [...select, ...relations]
|
|
||||||
if (fields.length) {
|
|
||||||
data = orders.map((o) => pick(o, fields))
|
|
||||||
}
|
|
||||||
|
|
||||||
res.json({ orders: data, count, offset: skip, limit: take })
|
res.json({ orders: data, count, offset: skip, limit: take })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import "reflect-metadata"
|
import "reflect-metadata"
|
||||||
import { RequestHandler, Router } from "express"
|
import { Router } from "express"
|
||||||
|
|
||||||
import { Cart, Order, Swap } from "../../../../"
|
import { Cart, Order, Swap } from "../../../../"
|
||||||
import { FindParams } from "../../../../types/common"
|
import { FindParams } from "../../../../types/common"
|
||||||
import middlewares, {
|
import middlewares, {
|
||||||
transformBody,
|
transformBody,
|
||||||
transformQuery,
|
transformStoreQuery,
|
||||||
} from "../../../middlewares"
|
} from "../../../middlewares"
|
||||||
import { StorePostCartsCartReq } from "./update-cart"
|
import { StorePostCartsCartReq } from "./update-cart"
|
||||||
import { StorePostCartReq } from "./create-cart"
|
import { StorePostCartReq } from "./create-cart"
|
||||||
@@ -33,7 +33,7 @@ export default (app, container) => {
|
|||||||
|
|
||||||
route.get(
|
route.get(
|
||||||
"/:id",
|
"/:id",
|
||||||
transformQuery(FindParams, {
|
transformStoreQuery(FindParams, {
|
||||||
defaultRelations: defaultStoreCartRelations,
|
defaultRelations: defaultStoreCartRelations,
|
||||||
defaultFields: defaultStoreCartFields,
|
defaultFields: defaultStoreCartFields,
|
||||||
isList: false,
|
isList: false,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Router } from "express"
|
import { Router } from "express"
|
||||||
import { PaginatedResponse } from "../../../../types/common"
|
import { PaginatedResponse } from "../../../../types/common"
|
||||||
import { ProductCollection } from "../../../../"
|
import { ProductCollection } from "../../../../"
|
||||||
import middlewares, { transformQuery } from "../../../middlewares"
|
import middlewares, { transformStoreQuery } from "../../../middlewares"
|
||||||
import { StoreGetCollectionsParams } from "./list-collections"
|
import { StoreGetCollectionsParams } from "./list-collections"
|
||||||
|
|
||||||
const route = Router()
|
const route = Router()
|
||||||
@@ -11,7 +11,7 @@ export default (app) => {
|
|||||||
|
|
||||||
route.get(
|
route.get(
|
||||||
"/",
|
"/",
|
||||||
transformQuery(StoreGetCollectionsParams, {
|
transformStoreQuery(StoreGetCollectionsParams, {
|
||||||
allowedFields,
|
allowedFields,
|
||||||
isList: true,
|
isList: true,
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Router } from "express"
|
import { Router } from "express"
|
||||||
import { Customer, Order } from "../../../.."
|
import { Customer, Order } from "../../../.."
|
||||||
import { PaginatedResponse } from "../../../../types/common"
|
import { PaginatedResponse } from "../../../../types/common"
|
||||||
import middlewares, { transformQuery } from "../../../middlewares"
|
import middlewares, { transformStoreQuery } from "../../../middlewares"
|
||||||
import {
|
import {
|
||||||
defaultStoreOrdersFields,
|
defaultStoreOrdersFields,
|
||||||
defaultStoreOrdersRelations,
|
defaultStoreOrdersRelations,
|
||||||
@@ -41,7 +41,7 @@ export default (app, container) => {
|
|||||||
|
|
||||||
route.get(
|
route.get(
|
||||||
"/me/orders",
|
"/me/orders",
|
||||||
transformQuery(StoreGetCustomersCustomerOrdersParams, {
|
transformStoreQuery(StoreGetCustomersCustomerOrdersParams, {
|
||||||
defaultFields: defaultStoreOrdersFields,
|
defaultFields: defaultStoreOrdersFields,
|
||||||
defaultRelations: defaultStoreOrdersRelations,
|
defaultRelations: defaultStoreOrdersRelations,
|
||||||
isList: true,
|
isList: true,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
} from "../../../../types/order-edit"
|
} from "../../../../types/order-edit"
|
||||||
import middlewares, {
|
import middlewares, {
|
||||||
transformBody,
|
transformBody,
|
||||||
transformQuery,
|
transformStoreQuery,
|
||||||
} from "../../../middlewares"
|
} from "../../../middlewares"
|
||||||
import { StorePostOrderEditsOrderEditDecline } from "./decline-order-edit"
|
import { StorePostOrderEditsOrderEditDecline } from "./decline-order-edit"
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ export default (app) => {
|
|||||||
|
|
||||||
route.get(
|
route.get(
|
||||||
"/:id",
|
"/:id",
|
||||||
transformQuery(FindParams, {
|
transformStoreQuery(FindParams, {
|
||||||
defaultRelations: defaultStoreOrderEditRelations,
|
defaultRelations: defaultStoreOrderEditRelations,
|
||||||
defaultFields: defaultStoreOrderEditFields,
|
defaultFields: defaultStoreOrderEditFields,
|
||||||
allowedFields: defaultStoreOrderEditFields,
|
allowedFields: defaultStoreOrderEditFields,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import "reflect-metadata"
|
|||||||
import { Order } from "../../../.."
|
import { Order } from "../../../.."
|
||||||
import middlewares, {
|
import middlewares, {
|
||||||
transformBody,
|
transformBody,
|
||||||
transformQuery,
|
transformStoreQuery,
|
||||||
} from "../../../middlewares"
|
} from "../../../middlewares"
|
||||||
import requireCustomerAuthentication from "../../../middlewares/require-customer-authentication"
|
import requireCustomerAuthentication from "../../../middlewares/require-customer-authentication"
|
||||||
import { StorePostCustomersCustomerOrderClaimReq } from "./request-order"
|
import { StorePostCustomersCustomerOrderClaimReq } from "./request-order"
|
||||||
@@ -21,7 +21,7 @@ export default (app) => {
|
|||||||
*/
|
*/
|
||||||
route.get(
|
route.get(
|
||||||
"/",
|
"/",
|
||||||
transformQuery(StoreGetOrdersParams, {
|
transformStoreQuery(StoreGetOrdersParams, {
|
||||||
defaultFields: defaultStoreOrdersFields,
|
defaultFields: defaultStoreOrdersFields,
|
||||||
defaultRelations: defaultStoreOrdersRelations,
|
defaultRelations: defaultStoreOrdersRelations,
|
||||||
allowedFields: allowedStoreOrdersFields,
|
allowedFields: allowedStoreOrdersFields,
|
||||||
@@ -36,7 +36,7 @@ export default (app) => {
|
|||||||
*/
|
*/
|
||||||
route.get(
|
route.get(
|
||||||
"/:id",
|
"/:id",
|
||||||
transformQuery(StoreGetOrderParams, {
|
transformStoreQuery(StoreGetOrderParams, {
|
||||||
defaultFields: defaultStoreOrdersFields,
|
defaultFields: defaultStoreOrdersFields,
|
||||||
defaultRelations: defaultStoreOrdersRelations,
|
defaultRelations: defaultStoreOrdersRelations,
|
||||||
allowedFields: allowedStoreOrdersFields,
|
allowedFields: allowedStoreOrdersFields,
|
||||||
|
|||||||
@@ -100,7 +100,9 @@ export default async (req, res) => {
|
|||||||
|
|
||||||
const order = orders[0]
|
const order = orders[0]
|
||||||
|
|
||||||
res.json({ order: cleanResponseData(order, req.allowedProperties || []) })
|
res.json({
|
||||||
|
order: cleanResponseData(order, req.allowedProperties || []),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ShippingAddressPayload {
|
export class ShippingAddressPayload {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Router } from "express"
|
|||||||
import "reflect-metadata"
|
import "reflect-metadata"
|
||||||
import middlewares, {
|
import middlewares, {
|
||||||
transformBody,
|
transformBody,
|
||||||
transformQuery,
|
transformStoreQuery,
|
||||||
} from "../../../middlewares"
|
} from "../../../middlewares"
|
||||||
|
|
||||||
import { PaymentCollection, PaymentSession } from "../../../../models"
|
import { PaymentCollection, PaymentSession } from "../../../../models"
|
||||||
@@ -18,7 +18,7 @@ export default (app, container) => {
|
|||||||
|
|
||||||
route.get(
|
route.get(
|
||||||
"/:id",
|
"/:id",
|
||||||
transformQuery(StoreGetPaymentCollectionsParams, {
|
transformStoreQuery(StoreGetPaymentCollectionsParams, {
|
||||||
defaultFields: defaultPaymentCollectionFields,
|
defaultFields: defaultPaymentCollectionFields,
|
||||||
defaultRelations: defaultPaymentCollectionRelations,
|
defaultRelations: defaultPaymentCollectionRelations,
|
||||||
isList: false,
|
isList: false,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Router } from "express"
|
import { Router } from "express"
|
||||||
import middlewares, { transformQuery } from "../../../middlewares"
|
import middlewares, { transformStoreQuery } from "../../../middlewares"
|
||||||
import { ProductCategory } from "../../../../models"
|
import { ProductCategory } from "../../../../models"
|
||||||
import { PaginatedResponse } from "../../../../types/common"
|
import { PaginatedResponse } from "../../../../types/common"
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ export default (app) => {
|
|||||||
|
|
||||||
route.get(
|
route.get(
|
||||||
"/",
|
"/",
|
||||||
transformQuery(StoreGetProductCategoriesParams, {
|
transformStoreQuery(StoreGetProductCategoriesParams, {
|
||||||
defaultFields: defaultStoreProductCategoryFields,
|
defaultFields: defaultStoreProductCategoryFields,
|
||||||
allowedFields: allowedStoreProductCategoryFields,
|
allowedFields: allowedStoreProductCategoryFields,
|
||||||
defaultRelations: defaultStoreProductCategoryRelations,
|
defaultRelations: defaultStoreProductCategoryRelations,
|
||||||
@@ -29,7 +29,7 @@ export default (app) => {
|
|||||||
|
|
||||||
route.get(
|
route.get(
|
||||||
"/:id",
|
"/:id",
|
||||||
transformQuery(StoreGetProductCategoryParams, {
|
transformStoreQuery(StoreGetProductCategoryParams, {
|
||||||
defaultFields: defaultStoreProductCategoryFields,
|
defaultFields: defaultStoreProductCategoryFields,
|
||||||
allowedFields: allowedStoreProductCategoryFields,
|
allowedFields: allowedStoreProductCategoryFields,
|
||||||
defaultRelations: defaultStoreProductCategoryRelations,
|
defaultRelations: defaultStoreProductCategoryRelations,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Router } from "express"
|
import { Router } from "express"
|
||||||
import { ProductTag } from "../../../../models"
|
import { ProductTag } from "../../../../models"
|
||||||
import { PaginatedResponse } from "../../../../types/common"
|
import { PaginatedResponse } from "../../../../types/common"
|
||||||
import middlewares, { transformQuery } from "../../../middlewares"
|
import middlewares, { transformStoreQuery } from "../../../middlewares"
|
||||||
import { StoreGetProductTagsParams } from "./list-product-tags"
|
import { StoreGetProductTagsParams } from "./list-product-tags"
|
||||||
|
|
||||||
const route = Router()
|
const route = Router()
|
||||||
@@ -11,7 +11,7 @@ export default (app: Router) => {
|
|||||||
|
|
||||||
route.get(
|
route.get(
|
||||||
"/",
|
"/",
|
||||||
transformQuery(StoreGetProductTagsParams, {
|
transformStoreQuery(StoreGetProductTagsParams, {
|
||||||
defaultFields: defaultStoreProductTagFields,
|
defaultFields: defaultStoreProductTagFields,
|
||||||
defaultRelations: defaultStoreProductTagRelations,
|
defaultRelations: defaultStoreProductTagRelations,
|
||||||
allowedFields: allowedStoreProductTagFields,
|
allowedFields: allowedStoreProductTagFields,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Router } from "express"
|
import { Router } from "express"
|
||||||
import { ProductType } from "../../../.."
|
import { ProductType } from "../../../.."
|
||||||
import { PaginatedResponse } from "../../../../types/common"
|
import { PaginatedResponse } from "../../../../types/common"
|
||||||
import middlewares, { transformQuery } from "../../../middlewares"
|
import middlewares, { transformStoreQuery } from "../../../middlewares"
|
||||||
import "reflect-metadata"
|
import "reflect-metadata"
|
||||||
import { StoreGetProductTypesParams } from "./list-product-types"
|
import { StoreGetProductTypesParams } from "./list-product-types"
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ export default (app) => {
|
|||||||
|
|
||||||
route.get(
|
route.get(
|
||||||
"/",
|
"/",
|
||||||
transformQuery(StoreGetProductTypesParams, {
|
transformStoreQuery(StoreGetProductTypesParams, {
|
||||||
defaultFields: defaultStoreProductTypeFields,
|
defaultFields: defaultStoreProductTypeFields,
|
||||||
defaultRelations: defaultStoreProductTypeRelations,
|
defaultRelations: defaultStoreProductTypeRelations,
|
||||||
allowedFields: allowedStoreProductTypeFields,
|
allowedFields: allowedStoreProductTypeFields,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { RequestHandler, Router } from "express"
|
import { Router } from "express"
|
||||||
import "reflect-metadata"
|
import "reflect-metadata"
|
||||||
|
|
||||||
import { Product } from "../../../.."
|
import { Product } from "../../../.."
|
||||||
import middlewares, { transformQuery } from "../../../middlewares"
|
import middlewares, { transformStoreQuery } from "../../../middlewares"
|
||||||
import { PaginatedResponse } from "../../../../types/common"
|
import { PaginatedResponse } from "../../../../types/common"
|
||||||
import { extendRequestParams } from "../../../middlewares/publishable-api-key/extend-request-params"
|
import { extendRequestParams } from "../../../middlewares/publishable-api-key/extend-request-params"
|
||||||
import { validateProductSalesChannelAssociation } from "../../../middlewares/publishable-api-key/validate-product-sales-channel-association"
|
import { validateProductSalesChannelAssociation } from "../../../middlewares/publishable-api-key/validate-product-sales-channel-association"
|
||||||
@@ -19,7 +19,7 @@ export default (app) => {
|
|||||||
|
|
||||||
route.get(
|
route.get(
|
||||||
"/",
|
"/",
|
||||||
transformQuery(StoreGetProductsParams, {
|
transformStoreQuery(StoreGetProductsParams, {
|
||||||
defaultRelations: defaultStoreProductsRelations,
|
defaultRelations: defaultStoreProductsRelations,
|
||||||
defaultFields: defaultStoreProductsFields,
|
defaultFields: defaultStoreProductsFields,
|
||||||
allowedFields: allowedStoreProductsFields,
|
allowedFields: allowedStoreProductsFields,
|
||||||
@@ -31,7 +31,7 @@ export default (app) => {
|
|||||||
|
|
||||||
route.get(
|
route.get(
|
||||||
"/:id",
|
"/:id",
|
||||||
transformQuery(StoreGetProductsProductParams, {
|
transformStoreQuery(StoreGetProductsProductParams, {
|
||||||
defaultRelations: defaultStoreProductsRelations,
|
defaultRelations: defaultStoreProductsRelations,
|
||||||
defaultFields: defaultStoreProductsFields,
|
defaultFields: defaultStoreProductsFields,
|
||||||
allowedFields: allowedStoreProductsFields,
|
allowedFields: allowedStoreProductsFields,
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ declare global {
|
|||||||
retrieveConfig: FindConfig<unknown>
|
retrieveConfig: FindConfig<unknown>
|
||||||
filterableFields: Record<string, unknown>
|
filterableFields: Record<string, unknown>
|
||||||
allowedProperties: string[]
|
allowedProperties: string[]
|
||||||
|
includes?: Record<string, boolean>
|
||||||
errors: string[]
|
errors: string[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,53 @@
|
|||||||
import { pick } from "lodash"
|
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 EXCLUDED_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 `allowedProperties`.
|
||||||
|
* You can read more in the transformQuery middleware utility methods.
|
||||||
*
|
*
|
||||||
* @param data - record or an array of records in the response
|
* @param data - record or an array of records in the response
|
||||||
* @param fields - record props allowed in the response
|
* @param fields - record props allowed in the response
|
||||||
*/
|
*/
|
||||||
function cleanResponseData<T>(data: T, fields: string[]) {
|
function cleanResponseData<T extends unknown | unknown[]>(
|
||||||
|
data: T,
|
||||||
|
fields: string[]
|
||||||
|
): T extends [] ? Partial<T>[] : Partial<T> {
|
||||||
if (!fields.length) {
|
if (!fields.length) {
|
||||||
return data
|
return data as T extends [] ? Partial<T>[] : Partial<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Array.isArray(data)) {
|
const isDataArray = Array.isArray(data)
|
||||||
return data.map((record) => pick(record, fields))
|
const fieldsSet = new Set([...fields, ...EXCLUDED_FIELDS])
|
||||||
}
|
|
||||||
|
|
||||||
return pick(data, fields)
|
fields = [...fieldsSet]
|
||||||
|
|
||||||
|
let arrayData: Partial<T>[] = isDataArray ? data : [data]
|
||||||
|
arrayData = arrayData.map((record) => pick(record, fields))
|
||||||
|
|
||||||
|
return (isDataArray ? arrayData : arrayData[0]) as T extends []
|
||||||
|
? Partial<T>[]
|
||||||
|
: Partial<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
export { cleanResponseData }
|
export { cleanResponseData }
|
||||||
@@ -32,6 +32,5 @@
|
|||||||
"build": "tsc --build",
|
"build": "tsc --build",
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
"test:unit": "jest"
|
"test:unit": "jest"
|
||||||
},
|
}
|
||||||
"peerDependencies": {}
|
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user