From 1e19db60509e5fefde3b3243414a8f7d15a5213d Mon Sep 17 00:00:00 2001 From: Eric Dobbertin Date: Mon, 16 Sep 2019 13:49:32 -0500 Subject: [PATCH 1/5] fix: return correct values for method fulfillmentTypes Signed-off-by: Eric Dobbertin --- .../plugins/core/graphql/server/no-meteor/xforms/cart.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/imports/plugins/core/graphql/server/no-meteor/xforms/cart.js b/imports/plugins/core/graphql/server/no-meteor/xforms/cart.js index 000f2adf384..2b5e914542b 100644 --- a/imports/plugins/core/graphql/server/no-meteor/xforms/cart.js +++ b/imports/plugins/core/graphql/server/no-meteor/xforms/cart.js @@ -130,8 +130,7 @@ function xformCartFulfillmentGroup(fulfillmentGroup, cart) { displayName: option.method.label || option.method.name, group: option.method.group || null, name: option.method.name, - // For now, this is always shipping. Revisit when adding download, pickup, etc. types - fulfillmentTypes: ["shipping"] + fulfillmentTypes: option.method.fulfillmentTypes }, handlingPrice: { amount: option.handlingPrice || 0, @@ -156,8 +155,7 @@ function xformCartFulfillmentGroup(fulfillmentGroup, cart) { displayName: fulfillmentGroup.shipmentMethod.label || fulfillmentGroup.shipmentMethod.name, group: fulfillmentGroup.shipmentMethod.group || null, name: fulfillmentGroup.shipmentMethod.name, - // For now, this is always shipping. Revisit when adding download, pickup, etc. types - fulfillmentTypes: ["shipping"] + fulfillmentTypes: fulfillmentGroup.shipmentMethod.fulfillmentTypes }, handlingPrice: { amount: fulfillmentGroup.shipmentMethod.handling || 0, From fb8427f09cca1086e0232e9079d12dd764f733be Mon Sep 17 00:00:00 2001 From: Eric Dobbertin Date: Mon, 16 Sep 2019 14:31:34 -0500 Subject: [PATCH 2/5] feat: add accountId to CommonOrders Signed-off-by: Eric Dobbertin --- .../util/xformCartGroupToCommonOrder.js | 3 ++- .../mutations/addOrderFulfillmentGroup.js | 4 +++- .../server/no-meteor/mutations/moveOrderItems.js | 16 ++++++++++++---- .../server/no-meteor/mutations/placeOrder.js | 1 + .../server/no-meteor/mutations/splitOrderItem.js | 3 ++- .../orders/server/no-meteor/simpleSchemas.js | 4 ++++ .../no-meteor/util/addShipmentMethodToGroup.js | 3 +++ .../server/no-meteor/util/addTaxesToGroup.js | 3 +++ .../util/buildOrderFulfillmentGroupFromInput.js | 3 +++ .../no-meteor/util/getSurchargesForGroup.js | 3 +++ .../server/no-meteor/util/updateGroupTotals.js | 5 +++++ .../util/xformOrderGroupToCommonOrder.js | 12 +++++++++++- 12 files changed, 52 insertions(+), 8 deletions(-) diff --git a/imports/plugins/core/cart/server/no-meteor/util/xformCartGroupToCommonOrder.js b/imports/plugins/core/cart/server/no-meteor/util/xformCartGroupToCommonOrder.js index 2f4540d83e5..0dac3d39bbd 100644 --- a/imports/plugins/core/cart/server/no-meteor/util/xformCartGroupToCommonOrder.js +++ b/imports/plugins/core/cart/server/no-meteor/util/xformCartGroupToCommonOrder.js @@ -10,7 +10,7 @@ import ReactionError from "@reactioncommerce/reaction-error"; */ export default async function xformCartGroupToCommonOrder(cart, group, context) { const { collections } = context; - const { currencyCode } = cart; + const { accountId, currencyCode } = cart; let items = group.itemIds.map((itemId) => cart.items.find((item) => item._id === itemId)); items = items.filter((item) => !!item); // remove nulls @@ -131,6 +131,7 @@ export default async function xformCartGroupToCommonOrder(cart, group, context) return { + accountId, billingAddress: null, cartId: cart._id, currencyCode: cart.currencyCode, diff --git a/imports/plugins/core/orders/server/no-meteor/mutations/addOrderFulfillmentGroup.js b/imports/plugins/core/orders/server/no-meteor/mutations/addOrderFulfillmentGroup.js index befac3a4c0d..00e468b3d76 100644 --- a/imports/plugins/core/orders/server/no-meteor/mutations/addOrderFulfillmentGroup.js +++ b/imports/plugins/core/orders/server/no-meteor/mutations/addOrderFulfillmentGroup.js @@ -59,7 +59,7 @@ export default async function addOrderFulfillmentGroup(context, input) { throw new ReactionError("access-denied", "Access Denied"); } - const { billingAddress, cartId, currencyCode } = order; + const { accountId, billingAddress, cartId, currencyCode } = order; // If there are moveItemIds, find and pull them from their current groups let updatedGroups; @@ -94,6 +94,7 @@ export default async function addOrderFulfillmentGroup(context, input) { // Update group shipping, tax, totals, etc. const { groupSurcharges } = await updateGroupTotals(context, { + accountId, billingAddress, cartId, currencyCode, @@ -124,6 +125,7 @@ export default async function addOrderFulfillmentGroup(context, input) { // Now build the new group we are adding const { group: newGroup, groupSurcharges } = await buildOrderFulfillmentGroupFromInput(context, { + accountId, // If we are moving any items from existing groups to this new group, push those into // the newGroup items array. additionalItems: movingItems, diff --git a/imports/plugins/core/orders/server/no-meteor/mutations/moveOrderItems.js b/imports/plugins/core/orders/server/no-meteor/mutations/moveOrderItems.js index ddc7dc11dfc..7ce4cf686ec 100644 --- a/imports/plugins/core/orders/server/no-meteor/mutations/moveOrderItems.js +++ b/imports/plugins/core/orders/server/no-meteor/mutations/moveOrderItems.js @@ -37,7 +37,14 @@ export default async function moveOrderItems(context, input) { toFulfillmentGroupId } = input; - const { accountId, appEvents, collections, isInternalCall, userHasPermission, userId } = context; + const { + accountId: authAccountId, + appEvents, + collections, + isInternalCall, + userHasPermission, + userId + } = context; const { Orders } = collections; // First verify that this order actually exists @@ -49,7 +56,7 @@ export default async function moveOrderItems(context, input) { // plugin, context.isInternalCall can be set to `true` to disable this check. if ( !isInternalCall && - (!accountId || accountId !== order.accountId) && + (!authAccountId || authAccountId !== order.accountId) && !userHasPermission(["orders", "order/fulfillment"], order.shopId) ) { throw new ReactionError("access-denied", "Access Denied"); @@ -57,7 +64,7 @@ export default async function moveOrderItems(context, input) { // Is the account calling this mutation also the account that placed the order? // We need this check in a couple places below, so we'll get it here. - const accountIsOrderer = (order.accountId && accountId === order.accountId); + const accountIsOrderer = (order.accountId && authAccountId === order.accountId); // The orderer may only move items while the order status is still "new" if (accountIsOrderer && !orderStatusesThatOrdererCanMove.includes(order.workflow.status)) { @@ -90,7 +97,7 @@ export default async function moveOrderItems(context, input) { throw new ReactionError("not-found", "Some order items not found"); } - const { billingAddress, cartId, currencyCode } = order; + const { accountId, billingAddress, cartId, currencyCode } = order; // Find and move the items const orderSurcharges = []; @@ -121,6 +128,7 @@ export default async function moveOrderItems(context, input) { // Update group shipping, tax, totals, etc. const { groupSurcharges } = await updateGroupTotals(context, { + accountId, billingAddress, cartId, currencyCode, diff --git a/imports/plugins/core/orders/server/no-meteor/mutations/placeOrder.js b/imports/plugins/core/orders/server/no-meteor/mutations/placeOrder.js index bda498bfbc9..c43e69374cb 100644 --- a/imports/plugins/core/orders/server/no-meteor/mutations/placeOrder.js +++ b/imports/plugins/core/orders/server/no-meteor/mutations/placeOrder.js @@ -208,6 +208,7 @@ export default async function placeOrder(context, input) { let shippingAddressForPayments = null; const finalFulfillmentGroups = await Promise.all(fulfillmentGroups.map(async (inputGroup) => { const { group, groupSurcharges } = await buildOrderFulfillmentGroupFromInput(context, { + accountId, billingAddress, cartId, currencyCode, diff --git a/imports/plugins/core/orders/server/no-meteor/mutations/splitOrderItem.js b/imports/plugins/core/orders/server/no-meteor/mutations/splitOrderItem.js index c4e764ed005..f52822eeb31 100644 --- a/imports/plugins/core/orders/server/no-meteor/mutations/splitOrderItem.js +++ b/imports/plugins/core/orders/server/no-meteor/mutations/splitOrderItem.js @@ -56,7 +56,7 @@ export default async function splitOrderItem(context, input) { throw new ReactionError("access-denied", "Access Denied"); } - const { billingAddress, cartId, currencyCode } = order; + const { accountId, billingAddress, cartId, currencyCode } = order; // Find and split the item let foundItem = false; @@ -107,6 +107,7 @@ export default async function splitOrderItem(context, input) { // Update group shipping, tax, totals, etc. const { groupSurcharges } = await updateGroupTotals(context, { + accountId, billingAddress, cartId, currencyCode, diff --git a/imports/plugins/core/orders/server/no-meteor/simpleSchemas.js b/imports/plugins/core/orders/server/no-meteor/simpleSchemas.js index 682142a8250..2a3e672f00a 100644 --- a/imports/plugins/core/orders/server/no-meteor/simpleSchemas.js +++ b/imports/plugins/core/orders/server/no-meteor/simpleSchemas.js @@ -116,6 +116,10 @@ const CommonOrderTotals = new SimpleSchema({ * caring whether it is for a Cart or an Order. */ export const CommonOrder = new SimpleSchema({ + accountId: { + type: String, + optional: true + }, billingAddress: { type: Address, optional: true diff --git a/imports/plugins/core/orders/server/no-meteor/util/addShipmentMethodToGroup.js b/imports/plugins/core/orders/server/no-meteor/util/addShipmentMethodToGroup.js index ffc4061dbc3..30c93f6facd 100644 --- a/imports/plugins/core/orders/server/no-meteor/util/addShipmentMethodToGroup.js +++ b/imports/plugins/core/orders/server/no-meteor/util/addShipmentMethodToGroup.js @@ -4,6 +4,7 @@ import xformOrderGroupToCommonOrder from "./xformOrderGroupToCommonOrder"; /** * @summary Sets `shipmentMethod` object for a fulfillment group * @param {Object} context An object containing the per-request state + * @param {String} [accountId] ID of account that is placing or already did place the order * @param {Object} [billingAddress] The primary billing address for the order, if known * @param {String|null} [cartId] ID of the cart from which the order is being placed, if applicable * @param {String} currencyCode Currency code for all money values @@ -14,6 +15,7 @@ import xformOrderGroupToCommonOrder from "./xformOrderGroupToCommonOrder"; * @returns {undefined} */ export default async function addShipmentMethodToGroup(context, { + accountId, billingAddress, cartId, currencyCode, @@ -25,6 +27,7 @@ export default async function addShipmentMethodToGroup(context, { const { collections, queries } = context; const commonOrder = await xformOrderGroupToCommonOrder({ + accountId, billingAddress, cartId, collections, diff --git a/imports/plugins/core/orders/server/no-meteor/util/addTaxesToGroup.js b/imports/plugins/core/orders/server/no-meteor/util/addTaxesToGroup.js index 13b060af51a..278d360d53e 100644 --- a/imports/plugins/core/orders/server/no-meteor/util/addTaxesToGroup.js +++ b/imports/plugins/core/orders/server/no-meteor/util/addTaxesToGroup.js @@ -3,6 +3,7 @@ import xformOrderGroupToCommonOrder from "./xformOrderGroupToCommonOrder"; /** * @summary Adds taxes to a fulfillment group * @param {Object} context An object containing the per-request state + * @param {String} [accountId] ID of account that is placing or already did place the order * @param {Object} [billingAddress] The primary billing address for the order, if known * @param {String|null} [cartId] ID of the cart from which the order is being placed, if applicable * @param {String} currencyCode Currency code for all money values @@ -12,6 +13,7 @@ import xformOrderGroupToCommonOrder from "./xformOrderGroupToCommonOrder"; * @returns {Object} An object with `taxTotal` and `taxableAmount` numeric properties */ export default async function addTaxesToGroup(context, { + accountId, billingAddress, cartId, currencyCode, @@ -22,6 +24,7 @@ export default async function addTaxesToGroup(context, { const { collections, mutations } = context; const commonOrder = await xformOrderGroupToCommonOrder({ + accountId, billingAddress, cartId, collections, diff --git a/imports/plugins/core/orders/server/no-meteor/util/buildOrderFulfillmentGroupFromInput.js b/imports/plugins/core/orders/server/no-meteor/util/buildOrderFulfillmentGroupFromInput.js index d7ae52e739c..0638b3c8a4b 100644 --- a/imports/plugins/core/orders/server/no-meteor/util/buildOrderFulfillmentGroupFromInput.js +++ b/imports/plugins/core/orders/server/no-meteor/util/buildOrderFulfillmentGroupFromInput.js @@ -5,6 +5,7 @@ import updateGroupTotals from "./updateGroupTotals"; /** * @summary Builds an order fulfillment group from fulfillment group input. * @param {Object} context an object containing the per-request state + * @param {String} [accountId] ID of account placing the order * @param {Object[]} [additionalItems] Additional already-created order items to push into the group * items array before calculating shipping, tax, surcharges, and totals. * @param {Object} [billingAddress] The primary billing address for the order, if known @@ -16,6 +17,7 @@ import updateGroupTotals from "./updateGroupTotals"; * @returns {Promise} The fulfillment group */ export default async function buildOrderFulfillmentGroupFromInput(context, { + accountId, additionalItems, billingAddress, cartId, @@ -56,6 +58,7 @@ export default async function buildOrderFulfillmentGroupFromInput(context, { taxableAmount, taxTotal } = await updateGroupTotals(context, { + accountId, billingAddress, cartId, currencyCode, diff --git a/imports/plugins/core/orders/server/no-meteor/util/getSurchargesForGroup.js b/imports/plugins/core/orders/server/no-meteor/util/getSurchargesForGroup.js index d0130f02ecd..a4af2f2ee70 100644 --- a/imports/plugins/core/orders/server/no-meteor/util/getSurchargesForGroup.js +++ b/imports/plugins/core/orders/server/no-meteor/util/getSurchargesForGroup.js @@ -3,6 +3,7 @@ import xformOrderGroupToCommonOrder from "./xformOrderGroupToCommonOrder"; /** * @summary Gets surcharge information for a fulfillment group * @param {Object} context An object containing the per-request state + * @param {String} [accountId] ID of account that is placing or already did place the order * @param {Object} [billingAddress] The primary billing address for the order, if known * @param {String|null} [cartId] ID of the cart from which the order is being placed, if applicable * @param {String} currencyCode Currency code for all money values @@ -12,6 +13,7 @@ import xformOrderGroupToCommonOrder from "./xformOrderGroupToCommonOrder"; * @returns {undefined} */ export default async function getSurchargesForGroup(context, { + accountId, billingAddress, cartId, currencyCode, @@ -23,6 +25,7 @@ export default async function getSurchargesForGroup(context, { // Get surcharges to apply to group, if applicable const commonOrder = await xformOrderGroupToCommonOrder({ + accountId, billingAddress, cartId, collections, diff --git a/imports/plugins/core/orders/server/no-meteor/util/updateGroupTotals.js b/imports/plugins/core/orders/server/no-meteor/util/updateGroupTotals.js index b25d2e5216d..8fef47bc696 100644 --- a/imports/plugins/core/orders/server/no-meteor/util/updateGroupTotals.js +++ b/imports/plugins/core/orders/server/no-meteor/util/updateGroupTotals.js @@ -9,6 +9,7 @@ import getSurchargesForGroup from "./getSurchargesForGroup"; * something else relevant about the group may have changed. All shipping, tax, * and surcharge values will be recalculated and invoice totals updated. * @param {Object} context App context + * @param {String} [accountId] ID of account that is placing or already did place the order * @param {Object} [billingAddress] The primary billing address for the order, if known * @param {String} [cartId] ID of the cart from which the order is being placed, if applicable * @param {String} currencyCode Currency code for all money values @@ -20,6 +21,7 @@ import getSurchargesForGroup from "./getSurchargesForGroup"; * @returns {Promise} Object with surcharge and tax info on it */ export default async function updateGroupTotals(context, { + accountId, billingAddress = null, cartId = null, currencyCode, @@ -31,6 +33,7 @@ export default async function updateGroupTotals(context, { }) { // Apply shipment method await addShipmentMethodToGroup(context, { + accountId, billingAddress, cartId, currencyCode, @@ -44,6 +47,7 @@ export default async function updateGroupTotals(context, { groupSurcharges, groupSurchargeTotal } = await getSurchargesForGroup(context, { + accountId, billingAddress, cartId, currencyCode, @@ -55,6 +59,7 @@ export default async function updateGroupTotals(context, { // Calculate and set taxes. Mutates group object in addition to returning the totals. const { taxTotal, taxableAmount } = await addTaxesToGroup(context, { + accountId, billingAddress, cartId, currencyCode, diff --git a/imports/plugins/core/orders/server/no-meteor/util/xformOrderGroupToCommonOrder.js b/imports/plugins/core/orders/server/no-meteor/util/xformOrderGroupToCommonOrder.js index b8d764f0d6a..c73f37724b0 100644 --- a/imports/plugins/core/orders/server/no-meteor/util/xformOrderGroupToCommonOrder.js +++ b/imports/plugins/core/orders/server/no-meteor/util/xformOrderGroupToCommonOrder.js @@ -9,7 +9,16 @@ import { toFixed } from "accounting-js"; * @param {String} orderId The order ID * @returns {Object} Valid CommonOrder for the given order group */ -export default async function xformOrderGroupToCommonOrder({ billingAddress = null, cartId, collections, currencyCode, group, orderId, discountTotal }) { +export default async function xformOrderGroupToCommonOrder({ + accountId = null, + billingAddress = null, + cartId, + collections, + currencyCode, + group, + orderId, + discountTotal +}) { // ** If you add any data here, be sure to add the same data to the matching xformCartGroupToCommonOrder xform const items = group.items.map((item) => ({ _id: item._id, @@ -94,6 +103,7 @@ export default async function xformOrderGroupToCommonOrder({ billingAddress = nu }; return { + accountId, billingAddress, cartId, currencyCode, From 87c40ee07cf51ac7e3e0f12c4f4c9b0596229282 Mon Sep 17 00:00:00 2001 From: Eric Dobbertin Date: Mon, 16 Sep 2019 14:43:01 -0500 Subject: [PATCH 3/5] feat: remove sensitive info headers from context.requestHeaders Signed-off-by: Eric Dobbertin --- imports/node-app/core/util/buildContext.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/imports/node-app/core/util/buildContext.js b/imports/node-app/core/util/buildContext.js index 66b9fbd49ec..006b145ebf7 100644 --- a/imports/node-app/core/util/buildContext.js +++ b/imports/node-app/core/util/buildContext.js @@ -44,5 +44,10 @@ export default async function buildContext(context, request = {}) { context.rootUrl = getRootUrl(request); context.getAbsoluteUrl = (path) => getAbsoluteUrl(context.rootUrl, path); - context.requestHeaders = request.headers; + // Make some request headers available to resolvers on context, but remove any + // with potentially sensitive information in them. + context.requestHeaders = { ...request.headers }; + delete context.requestHeaders.authorization; + delete context.requestHeaders.cookie; + delete context.requestHeaders["meteor-login-token"]; } From dd00f96c16a98672e542b5be9d19e9b9bac22fc9 Mon Sep 17 00:00:00 2001 From: Eric Dobbertin Date: Mon, 16 Sep 2019 18:22:17 -0500 Subject: [PATCH 4/5] test: fix context test Signed-off-by: Eric Dobbertin --- imports/node-app/core/util/buildContext.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/imports/node-app/core/util/buildContext.test.js b/imports/node-app/core/util/buildContext.test.js index 011c1726568..0120f4ef618 100644 --- a/imports/node-app/core/util/buildContext.test.js +++ b/imports/node-app/core/util/buildContext.test.js @@ -21,6 +21,7 @@ test("properly mutates the context object without user", async () => { queries: { primaryShopId: jasmine.any(Function) }, + requestHeaders: {}, rootUrl: "http://localhost:3000/", shopId: "PRIMARY_SHOP_ID", shopsUserHasPermissionFor: jasmine.any(Function), @@ -50,6 +51,7 @@ test("properly mutates the context object with user", async () => { queries: { primaryShopId: jasmine.any(Function) }, + requestHeaders: {}, shopId: "PRIMARY_SHOP_ID", shopsUserHasPermissionFor: jasmine.any(Function), user: fakeUser, From 249f879de5aa29f4d9aaa5471d662674c20cd64b Mon Sep 17 00:00:00 2001 From: Eric Dobbertin Date: Tue, 17 Sep 2019 15:28:14 -0500 Subject: [PATCH 5/5] fix: avoid errors disconnecting mongo before connect Signed-off-by: Eric Dobbertin --- imports/node-app/core/ReactionNodeApp.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/imports/node-app/core/ReactionNodeApp.js b/imports/node-app/core/ReactionNodeApp.js index 0df0f515d77..c0ccac32305 100644 --- a/imports/node-app/core/ReactionNodeApp.js +++ b/imports/node-app/core/ReactionNodeApp.js @@ -142,8 +142,10 @@ export default class ReactionNodeApp { }); } - disconnectFromMongo() { - return this.mongoClient.close(); + async disconnectFromMongo() { + if (this.mongoClient) { + await this.mongoClient.close(); + } } /**