Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,82 @@
# v3.0.0-alpha

Reaction v3.0.0-alpha is our alpha release of the new Reaction project.

This release is being coordinated with [Reaction Platform](https://github.com/reactioncommerce/reaction-platform) and is designed to work with `v2.9.0` of [Reaction Hydra](https://github.com/reactioncommerce/reaction-hydra) and [Example Storefront](https://github.com/reactioncommerce/example-storefront).

## Notable changes

### De-meteorized the API

Abstracted meteor-related sections into other projects.
This drastically improves build, startup, and restart times.

### Completed GraphQL API coverage

All of the still-used old meteor methods have been ported to GraphQL queries and mutations.

## Features

- Authorization plugin & checkPermissions functionality [#5724](https://github.com/reactioncommerce/reaction/pull/5724)
- Add checkPermissions function [#5727](https://github.com/reactioncommerce/reaction/pull/5727)
- Add updateProduct and updateProductVariant mutations for 3.0 [#5768](https://github.com/reactioncommerce/reaction/pull/5768)
- GQL tax rates [#5774](https://github.com/reactioncommerce/reaction/pull/5774)
- Improved performance of tag queries [#5783](https://github.com/reactioncommerce/reaction/pull/5783)
- De-meteorize `tags/getBySlug` [#5786](https://github.com/reactioncommerce/reaction/pull/5786)
- De-meteorize `templates/email/update` [#5792](https://github.com/reactioncommerce/reaction/pull/5792)
- Add `retryFailed` method for emails [#5793](https://github.com/reactioncommerce/reaction/pull/5793)
- Add GQL queries and mutations for discount codes [#5800](https://github.com/reactioncommerce/reaction/pull/5800)
- Update `updateShop` mutation to set all necessary settings [#5804](https://github.com/reactioncommerce/reaction/pull/5804)
- Retry initial MongoDB connections [#5807](https://github.com/reactioncommerce/reaction/pull/5807)
- Add email templates query [#5811](https://github.com/reactioncommerce/reaction/pull/5811)
- Add `addAccountEmailRecord` mutation [#5813](https://github.com/reactioncommerce/reaction/pull/5813)
- Add `addCartItems` mutation [#5814](https://github.com/reactioncommerce/reaction/pull/5814)
- Add queries for `product` and `products` [#5818](https://github.com/reactioncommerce/reaction/pull/5818)
- Add flat-rate fulfillment method query[#5844](https://github.com/reactioncommerce/reaction/pull/5844)
- Update `updateShop` mutation to accept parcel size and brand assets [#5846](https://github.com/reactioncommerce/reaction/pull/5846)
- Add Accounts GraphQL query to find non-admin accounts [#5848](https://github.com/reactioncommerce/reaction/pull/5848)
- Stop using packages for tax settings [#5852](https://github.com/reactioncommerce/reaction/pull/5852)
- Add integration test for `accountCartByAccountId` query [#5857](https://github.com/reactioncommerce/reaction/pull/5857)
- Source Stripe API keys from ENV vars [#5771](https://github.com/reactioncommerce/reaction/pull/5771)

## Fixes

- Various 3.0.0 fixes [#5722](https://github.com/reactioncommerce/reaction/pull/5722)
- Fix account invite flow and account email data [#5799](https://github.com/reactioncommerce/reaction/pull/5799)
- Respect `allowGuestCheckout` setting [#5815](https://github.com/reactioncommerce/reaction/pull/5815)
- Use api-utils for currency definitions [#5823](https://github.com/reactioncommerce/reaction/pull/5823)
- Unified `updateTag` and `createTag` mutations [#5824](https://github.com/reactioncommerce/reaction/pull/5824)
- Parse complicated `MONGO_URL` properly [#5827](https://github.com/reactioncommerce/reaction/pull/5827)

## Refactor

- Move xforms into plugins [#5713](https://github.com/reactioncommerce/reaction/pull/5713)
- Use new `URL` instead of `url.parse` [#5717](https://github.com/reactioncommerce/reaction/pull/5717)
- Remove previously deprecated code [#5718](https://github.com/reactioncommerce/reaction/pull/5718)
- Clean up translations for products view [#5746](https://github.com/reactioncommerce/reaction/pull/5746)
- Source SMTP email configuation from ENV vars instead of DB [#5788](https://github.com/reactioncommerce/reaction/pull/5788)
- Make cart token param name consistent [#5820](https://github.com/reactioncommerce/reaction/pull/5820)

## Tests

- Add Babel config to make Jest tests work [#5728](https://github.com/reactioncommerce/reaction/pull/5728)
- Fixed integration tests [#5732](https://github.com/reactioncommerce/reaction/pull/5732)
- Add navigation query integration tests [#5856](https://github.com/reactioncommerce/reaction/pull/5856)
- fix failing integration tests [#5862](https://github.com/reactioncommerce/reaction/pull/5862)

## Chores

- Check node version on run [#5734](https://github.com/reactioncommerce/reaction/pull/5734)
- Lock `api-utils` version number [#5851](https://github.com/reactioncommerce/reaction/pull/5851)
- Add integration test for `anonymousCartByCartId` query [#5859](https://github.com/reactioncommerce/reaction/pull/5859)
- Add integration test for available payment methods [#5864](https://github.com/reactioncommerce/reaction/pull/5864)
- Add integration test for `getFlatRateFulfillmentRestrictions` [#5866](https://github.com/reactioncommerce/reaction/pull/5866)
- Add integration test for `getFlatRateFulfillmentRestriction` [#5869](https://github.com/reactioncommerce/reaction/pull/5869)

## Contributors

Thanks to [@trojanh](https://github.com/trojanh) for contributing to this release! 🎉

# v2.9.0

Reaction v2.9.0 adds integration tests for GraphQL API endpoints, security updates and fixes a fulfillment method bug.
Expand Down
5 changes: 1 addition & 4 deletions src/core-services/catalog/startup.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,7 @@ export default async function startup(context) {
});

appEvents.on("afterVariantUpdate", async ({ productId }) => {
const variant = await collections.Products.findOne({ _id: productId });
const productIdFromVariant = variant.ancestors[0];

hashRelatedProduct(productIdFromVariant, collections).catch((error) => {
hashRelatedProduct(productId, collections).catch((error) => {
Logger.error("Error in afterVariantUpdate", error);
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ exports[`throws if no action 1`] = `"Action must be provided"`;

exports[`throws if no authContext 1`] = `"authContext must be provided"`;

exports[`throws if no authContext.shopId (referred to as \`roleGroup\`) 1`] = `"shopId (roleGroup) must be provided"`;

exports[`throws if no resource 1`] = `"Resource must be provided"`;

exports[`throws if roleGroup is present but an empty string 1`] = `"shopId (roleGroup) must be provided"`;
exports[`throws if roleGroup is present but an empty string 1`] = `"roleGroup must be a non-empty string"`;

exports[`throws if roleGroup is present but not a string 1`] = `"roleGroup must be a non-empty string"`;
2 changes: 0 additions & 2 deletions src/plugins/legacy-authorization/util/hasPermission.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ export default async function hasPermission(context, resource, action, authConte

if (!authContext) throw new ReactionError("invalid-param", "authContext must be provided");

if (!authContext.shopId) throw new ReactionError("invalid-param", "shopId (roleGroup) must be provided");

const { legacyRoles: permissions, shopId: roleGroup } = authContext; // TODO(pod-auth): temporarily provide legacy roles

if (!Array.isArray(permissions)) throw new ReactionError("invalid-param", "permissions must be an array of strings");
Expand Down
20 changes: 0 additions & 20 deletions src/plugins/legacy-authorization/util/hasPermission.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,26 +61,6 @@ test("throws if no authContext", async () => {
expect(result).rejects.toThrowErrorMatchingSnapshot();
});

test("throws if no authContext.shopId (referred to as `roleGroup`)", async () => {
const result = hasPermission(
{
user: {
roles: {
__global_roles__: ["can_fry_bacon"], // eslint-disable-line camelcase
scope: ["can_eat"]
}
}
},
"resource",
"action",
{
shopId: null,
legacyRoles: ["role1", "role2"]
}
);
expect(result).rejects.toThrowErrorMatchingSnapshot();
});

test("throws if roleGroup is present but not a string", async () => {
const result = hasPermission(
{
Expand Down
4 changes: 4 additions & 0 deletions src/plugins/simple-pricing/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import policies from "./policies.json";
import preStartup from "./preStartup.js";
import mutations from "./mutations/index.js";
import queries from "./queries/index.js";
import resolvers from "./resolvers/index.js";
import schemas from "./schemas/index.js";
Expand Down Expand Up @@ -30,6 +32,8 @@ export default async function register(app) {
resolvers,
schemas
},
mutations,
policies,
queries,
catalog: {
publishedProductFields: ["price"],
Expand Down
5 changes: 5 additions & 0 deletions src/plugins/simple-pricing/mutations/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import updateProductVariantPrices from "./updateProductVariantPrices.js";

export default {
updateProductVariantPrices
};
69 changes: 69 additions & 0 deletions src/plugins/simple-pricing/mutations/updateProductVariantPrices.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import SimpleSchema from "simpl-schema";
import ReactionError from "@reactioncommerce/reaction-error";

const pricesInput = new SimpleSchema({
compareAtPrice: {
type: Number,
optional: true
},
price: {
type: Number,
optional: true
}
});

const inputSchema = new SimpleSchema({
prices: {
type: pricesInput
},
shopId: String,
variantId: String
});

/**
* @method updateProductVariantPrices
* @summary Updates the price fields on a product variant
* @param {Object} context - an object containing the per-request state
* @param {Object} input - Input arguments for the bulk operation
* @param {Object} input.prices - prices to update
* @param {Object} [input.prices.compareAtPrice] - variant compareAtPrice
* @param {Object} [input.prices.price] - variant price
* @param {String} input.variantId - variantId of product to update
* @param {String} input.shopId - shopId of shop product belongs to
* @return {Promise<Object>} updateProductVariant payload
*/
export default async function updateProductVariantPrices(context, input) {
inputSchema.validate(input);
const { appEvents, collections } = context;
const { Products } = collections;
const { prices, variantId, shopId } = input;

// Check that user has permission to create product
await context.validatePermissions(`reaction:products:${variantId}`, "update:prices", {
shopId,
legacyRoles: ["createProduct", "product/admin", "product/update"]
});

const { value: updatedProduct } = await Products.findOneAndUpdate(
{ _id: variantId, shopId, type: "variant" },
{ $set: { ...prices } },
{ returnOriginal: false }
);

if (!updatedProduct) throw new ReactionError("error-occurred", "Unable to update variant prices");

Object.keys(prices).forEach((key) => {
const field = key;
const value = prices[key];

appEvents.emit("afterVariantUpdate", {
_id: variantId,
productId: updatedProduct.ancestors[0],
variant: updatedProduct,
field,
value
});
});

return updatedProduct;
}
11 changes: 11 additions & 0 deletions src/plugins/simple-pricing/policies.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[
{
"description": "Product managers acting on specific entities.",
"subjects": [ "reaction:groups:product-managers" ],
"resources": [ "reaction:products:*" ],
"actions": [
"update:prices"
],
"effect": "allow"
}
]
5 changes: 5 additions & 0 deletions src/plugins/simple-pricing/resolvers/Mutation/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import updateProductVariantPrices from "./updateProductVariantPrices.js";

export default {
updateProductVariantPrices
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { decodeProductOpaqueId, decodeShopOpaqueId } from "../../xforms/id.js";

/**
*
* @method updateProductVariantPrices
* @summary Updates the price fields on a product variant
* @param {Object} _ - unused
* @param {Object} args - The input arguments
* @param {Object} args.input - mutation input object
* @param {String} args.input.clientMutationId - The mutation id
* @param {Object} args.input.prices - prices to update
* @param {Object} [args.input.prices.compareAtPrice] - variant compareAtPrice
* @param {Object} [args.input.prices.price] - variant price
* @param {String} args.input.shopId - shopId of shop product belongs to
* @param {String} args.input.variantId - Id of variant to update
* @param {Object} context - an object containing the per-request state
* @return {Promise<Object>} updateProductVariantPrices payload
*/
export default async function updateProductVariantPrices(_, { input }, context) {
const {
clientMutationId = null,
prices,
shopId,
variantId
} = input;

const updatedVariant = await context.mutations.updateProductVariantPrices(context, {
variantId: decodeProductOpaqueId(variantId),
shopId: decodeShopOpaqueId(shopId),
prices
});

return {
clientMutationId,
variant: updatedVariant
};
}
2 changes: 2 additions & 0 deletions src/plugins/simple-pricing/resolvers/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import CatalogProduct from "./CatalogProduct.js";
import CatalogProductVariant from "./CatalogProductVariant.js";
import Mutation from "./Mutation/index.js";
import ProductPricingInfo from "./ProductPricingInfo.js";

export default {
CatalogProduct,
CatalogProductVariant,
Mutation,
ProductPricingInfo
};
53 changes: 52 additions & 1 deletion src/plugins/simple-pricing/schemas/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,55 @@ extend type CatalogProductVariant {
extend type Product {
"Price range"
price: ProductPriceRange
}
}

extend type ProductVariant {
"Compare at price of the variant"
compareAtPrice: Float

"Price of the variant"
price: Float
}

extend input ProductVariantInput {
"The price of the variant"
price: Float
}

"Input for the `updateProductVariantField` mutation"
input UpdateProductVariantPricesInput {
"Prices to update"
prices: ProductVariantPricesInput!

"ID of shop that owns the variant to update"
shopId: ID!

"ID of variant to update"
variantId: ID!
}

"Mutation input for a product variant or option"
input ProductVariantPricesInput {
"Variant compareAtPrice"
compareAtPrice: Float

"Variant price"
price: Float
}

extend type Mutation {
"Update an existing product variants prices"
updateProductVariantPrices(
"Mutation input"
input: UpdateProductVariantPricesInput!
): UpdateProductVariantPricesPayload!
}

"Response payload of `updateProductVariantPricesField` mutation"
type UpdateProductVariantPricesPayload {
"The same string you sent with the mutation params, for matching mutation calls with their responses"
clientMutationId: String

"Updated variant"
variant: ProductVariant!
}
13 changes: 13 additions & 0 deletions src/plugins/simple-pricing/xforms/id.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import decodeOpaqueIdForNamespace from "@reactioncommerce/api-utils/decodeOpaqueIdForNamespace.js";
import encodeOpaqueId from "@reactioncommerce/api-utils/encodeOpaqueId.js";

const namespaces = {
Product: "reaction/product",
Shop: "reaction/shop"
};

export const encodeProductOpaqueId = encodeOpaqueId(namespaces.Product);
export const encodeShopOpaqueId = encodeOpaqueId(namespaces.Shop);

export const decodeProductOpaqueId = decodeOpaqueIdForNamespace(namespaces.Product);
export const decodeShopOpaqueId = decodeOpaqueIdForNamespace(namespaces.Shop);
Loading