diff --git a/imports/collections/defineCollections.js b/imports/collections/defineCollections.js
index 30f0436b920..0ac3982a0cb 100644
--- a/imports/collections/defineCollections.js
+++ b/imports/collections/defineCollections.js
@@ -22,7 +22,6 @@ export default function defineCollections(db, collections) {
Orders: db.collection("Orders"),
Packages: db.collection("Packages"),
Products: db.collection("Products"),
- Revisions: db.collection("Revisions"),
roles: db.collection("roles"),
SellerShops: db.collection("SellerShops"),
Shipping: db.collection("Shipping"),
diff --git a/imports/plugins/core/revisions/client/components/publishControls.js b/imports/plugins/core/catalog/client/components/publishControls.js
similarity index 78%
rename from imports/plugins/core/revisions/client/components/publishControls.js
rename to imports/plugins/core/catalog/client/components/publishControls.js
index 8381547b691..0e977b59eae 100644
--- a/imports/plugins/core/revisions/client/components/publishControls.js
+++ b/imports/plugins/core/catalog/client/components/publishControls.js
@@ -4,14 +4,9 @@ import { Components } from "@reactioncommerce/reaction-components";
import {
Button,
FlatButton,
- IconButton,
- Divider,
- DropDownMenu,
- MenuItem,
Switch,
Icon
} from "/imports/plugins/core/ui/client/components";
-import SimpleDiff from "./simpleDiff";
import { Translatable } from "/imports/plugins/core/ui/client/providers";
/** TMP **/
@@ -176,19 +171,6 @@ class PublishControls extends Component {
return false;
}
- renderChanges() {
- if (this.showDiffs) {
- const diffs = this.props.revisions.map((revision) => );
-
- return (
-
- {diffs}
-
- );
- }
- return null;
- }
-
renderDeletionStatus() {
if (this.hasChanges) {
if (this.primaryRevision && this.primaryRevision.documentData.isDeleted) {
@@ -232,48 +214,6 @@ class PublishControls extends Component {
);
}
- renderMoreOptionsButton() {
- return (
- }
- handleMenuItemChange={this.handleAction}
- >
-
-
-
-
-
-
-
-
-
-
- );
- }
-
renderViewControls() {
if (this.props.showViewAsControls) {
let tooltip = "Private";
@@ -304,19 +244,6 @@ class PublishControls extends Component {
return null;
}
- renderUndoButton() {
- return (
-
- );
- }
-
renderArchiveButton() {
return (
- {this.renderDeletionStatus()}
- {this.renderUndoButton()}
- {this.renderArchiveButton()}
- {this.renderViewControls()}
- {this.renderPublishButton()}
- {/* this.renderMoreOptionsButton() */}
-
- );
- }
-
- return null;
+ return (
+
+ {this.renderDeletionStatus()}
+ {this.renderArchiveButton()}
+ {this.renderViewControls()}
+ {this.renderPublishButton()}
+
+ );
}
}
diff --git a/imports/plugins/core/catalog/client/containers/publishContainer.js b/imports/plugins/core/catalog/client/containers/publishContainer.js
new file mode 100644
index 00000000000..c9c1d21efc2
--- /dev/null
+++ b/imports/plugins/core/catalog/client/containers/publishContainer.js
@@ -0,0 +1,83 @@
+import React, { Component } from "react";
+import PropTypes from "prop-types";
+import { composeWithTracker } from "@reactioncommerce/reaction-components";
+import PublishControls from "../components/publishControls";
+import { Meteor } from "meteor/meteor";
+import TranslationProvider from "/imports/plugins/core/ui/client/providers/translationProvider";
+import { Reaction, i18next } from "/client/api";
+
+/*
+ * PublishContainer is a container component connected to Meteor data source.
+ */
+class PublishContainer extends Component {
+ publishToCatalog(collection, documentIds) {
+ Meteor.call(`catalog/publish/${collection}`, documentIds, (error, result) => {
+ if (result) {
+ Alerts.toast(i18next.t("admin.catalogProductPublishSuccess", { defaultValue: "Product published to catalog" }), "success");
+ } else if (error) {
+ Alerts.toast(error.message, "error");
+ }
+ });
+ }
+
+ handlePublishClick = () => {
+ const productIds = this.props.documents
+ .filter((doc) => doc.type === "simple")
+ .map((doc) => doc._id);
+
+ this.publishToCatalog("products", productIds);
+ }
+
+ handlePublishActions = (event, action) => {
+ if (action === "archive" && this.props.onAction) {
+ this.props.onAction(event, action, this.props.documentIds);
+ }
+ }
+
+ render() {
+ return (
+
+
+
+ );
+ }
+}
+
+PublishContainer.propTypes = {
+ documentIds: PropTypes.arrayOf(PropTypes.string),
+ documents: PropTypes.arrayOf(PropTypes.object),
+ isEnabled: PropTypes.bool,
+ isPreview: PropTypes.bool,
+ onAction: PropTypes.func,
+ onPublishSuccess: PropTypes.func,
+ onVisibilityChange: PropTypes.func,
+ product: PropTypes.object
+};
+
+function composer(props, onData) {
+ const viewAs = Reaction.getUserPreferences("reaction-dashboard", "viewAs", "administrator");
+
+ if (Array.isArray(props.documentIds) && props.documentIds.length) {
+ onData(null, {
+ documentIds: props.documentIds,
+ documents: props.documents,
+ isPreview: viewAs === "customer"
+ });
+
+ return;
+ }
+
+ onData(null, {
+ isPreview: viewAs === "customer"
+ });
+}
+
+export default composeWithTracker(composer)(PublishContainer);
diff --git a/imports/plugins/core/catalog/server/methods/catalog.app-test.js b/imports/plugins/core/catalog/server/methods/catalog.app-test.js
index 5cf4b5247c3..1e975f99cfc 100644
--- a/imports/plugins/core/catalog/server/methods/catalog.app-test.js
+++ b/imports/plugins/core/catalog/server/methods/catalog.app-test.js
@@ -6,13 +6,12 @@ import { Meteor } from "meteor/meteor";
import { check, Match } from "meteor/check";
import { Factory } from "meteor/dburles:factory";
import { Reaction } from "/server/api";
-import { Products, Revisions, Tags } from "/lib/collections";
+import { Products, Tags } from "/lib/collections";
import { expect } from "meteor/practicalmeteor:chai";
import { sinon } from "meteor/practicalmeteor:sinon";
import { Roles } from "meteor/alanning:roles";
import { addProduct, addProductSingleVariant } from "/server/imports/fixtures/products";
import Fixtures from "/server/imports/fixtures";
-import { RevisionApi } from "/imports/plugins/core/revisions/lib/api/revisions";
Fixtures();
@@ -43,8 +42,6 @@ describe("core product methods", function () {
beforeEach(function () {
sandbox = sinon.sandbox.create();
- sandbox.stub(RevisionApi, "isRevisionControlEnabled", () => true);
- Revisions.remove({});
});
afterEach(function () {
@@ -166,7 +163,7 @@ describe("core product methods", function () {
expect(updateProductSpy).to.not.have.been.called;
});
- it("should not update individual variant by admin passing in full object", function (done) {
+ it("should update individual variant by admin passing in full object", function (done) {
sandbox.stub(Reaction, "hasPermission", () => true);
const product = addProduct();
let variant = Products.findOne({ ancestors: [product._id] });
@@ -174,55 +171,11 @@ describe("core product methods", function () {
variant["price"] = 7;
Meteor.call("products/updateVariant", variant);
variant = Products.findOne({ ancestors: [product._id] });
- expect(variant.price).to.not.equal(7);
- expect(variant.title).to.not.equal("Updated Title");
-
- return done();
- });
-
- it("should update individual variant revision by admin passing in full object", function (done) {
- sandbox.stub(Reaction, "hasPermission", () => true);
- const product = addProduct();
- const variant = Products.find({ ancestors: [product._id] }).fetch()[0];
- variant["title"] = "Updated Title";
- variant["price"] = 7;
- Meteor.call("products/updateVariant", variant);
- const variantRevision = Revisions.find({ documentId: variant._id }).fetch()[0];
- expect(variantRevision.documentData.price).to.equal(7);
- expect(variantRevision.documentData.title).to.equal("Updated Title");
+ expect(variant.price).to.equal(7);
+ expect(variant.title).to.equal("Updated Title");
return done();
});
-
- it("should not update individual variant by admin passing in partial object", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- const product = addProduct();
- const variant = Products.findOne({ ancestors: [product._id] });
- Meteor.call("products/updateVariant", {
- _id: variant._id,
- title: "Updated Title",
- price: 7
- });
- const updatedVariant = Products.findOne(variant._id);
- expect(updatedVariant.price).to.not.equal(7);
- expect(updatedVariant.title).to.not.equal("Updated Title");
- expect(updatedVariant.optionTitle).to.equal(variant.optionTitle);
- });
-
- it("should update individual variant revision by admin passing in partial object", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- const product = addProduct();
- const variant = Products.find({ ancestors: [product._id] }).fetch()[0];
- Meteor.call("products/updateVariant", {
- _id: variant._id,
- title: "Updated Title",
- price: 7
- });
- const updatedVariantRevision = Revisions.findOne({ documentId: variant._id });
- expect(updatedVariantRevision.documentData.price).to.equal(7);
- expect(updatedVariantRevision.documentData.title).to.equal("Updated Title");
- expect(updatedVariantRevision.documentData.optionTitle).to.equal(variant.optionTitle);
- });
});
describe("products/deleteVariant", function () {
@@ -235,38 +188,16 @@ describe("core product methods", function () {
expect(removeProductSpy).to.not.have.been.called;
});
- it("should not mark top-level variant as deleted", function () {
+ it("should mark top-level variant as deleted", function () {
sandbox.stub(Reaction, "hasPermission", () => true);
const product = addProduct();
let variant = Products.findOne({ ancestors: [product._id] });
expect(variant.isDeleted).to.equal(false);
Meteor.call("products/deleteVariant", variant._id);
variant = Products.findOne(variant._id);
- expect(variant.isDeleted).to.not.equal(true);
+ expect(variant.isDeleted).to.equal(true);
});
- it("should mark top-level variant revision as deleted", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- const product = addProduct();
- const variant = Products.findOne({ ancestors: [product._id] });
- expect(variant.isDeleted).to.equal(false);
- Meteor.call("products/deleteVariant", variant._id);
- const variantRevision = Revisions.findOne({ documentId: variant._id });
- expect(variantRevision.documentData.isDeleted).to.equal(true);
- });
-
- it("should publish top-level variant as deleted", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- const product = addProduct();
- const variant = Products.findOne({ ancestors: [product._id] });
- expect(variant.isDeleted).to.equal(false);
- Meteor.call("products/deleteVariant", variant._id);
- Meteor.call("revisions/publish", variant._id);
- const publishedProduct = Products.findOne(variant._id);
- expect(publishedProduct.isDeleted).to.equal(true);
- });
-
-
it("should mark all child variants (options) as deleted if top-level variant deleted", function () {
sandbox.stub(Reaction, "hasPermission", () => true);
const product = addProduct();
@@ -435,28 +366,11 @@ describe("core product methods", function () {
expect(removeProductSpy).to.not.have.been.called;
});
- it("should not mark product as deleted by admin", function () {
+ it("should mark product as deleted by admin", function () {
sandbox.stub(Reaction, "hasPermission", () => true);
let product = addProduct();
Meteor.call("products/archiveProduct", product._id);
product = Products.findOne(product._id);
- expect(product.isDeleted).to.equal(false);
- });
-
- it("should mark product revision as deleted by admin", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- const product = addProduct();
- Meteor.call("products/archiveProduct", product._id);
- const productRevision = Revisions.findOne({ documentId: product._id });
- expect(productRevision.documentData.isDeleted).to.equal(true);
- });
-
- it("should publish product revision marked as deleted by admin", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- let product = addProduct();
- Meteor.call("products/archiveProduct", product._id);
- Meteor.call("revisions/publish", product._id);
- product = Products.findOne(product._id);
expect(product.isDeleted).to.equal(true);
});
});
@@ -473,55 +387,19 @@ describe("core product methods", function () {
expect(updateProductSpy).to.not.have.been.called;
});
- it("should not update product field by admin", function () {
+ it("should update product field by admin", function () {
sandbox.stub(Reaction, "hasPermission", () => true);
let product = addProduct();
Meteor.call("products/updateProductField", product._id, "title", "Updated Title");
product = Products.findOne(product._id);
- expect(product.title).to.not.equal("Updated Title");
- });
-
- it("should update product revision field by admin", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- const product = addProduct();
- Meteor.call("products/updateProductField", product._id, "title", "Updated Title");
- const productRevision = Revisions.findOne({ documentId: product._id });
- expect(productRevision.documentData.title).to.equal("Updated Title");
- });
-
- it("should publish changes to product field by admin", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- let product = addProduct();
- Meteor.call("products/updateProductField", product._id, "title", "Updated Title");
- Meteor.call("revisions/publish", product._id);
- product = Products.findOne(product._id);
expect(product.title).to.equal("Updated Title");
});
- it("should not update variant fields", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- const product = addProduct();
- let variant = Products.findOne({ ancestors: [product._id] });
- Meteor.call("products/updateProductField", variant._id, "title", "Updated Title");
- variant = Products.findOne(variant._id);
- expect(variant.title).to.not.equal("Updated Title");
- });
-
- it("should update variant revision fields", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- const product = addProduct();
- const variant = Products.findOne({ ancestors: [product._id] });
- Meteor.call("products/updateProductField", variant._id, "title", "Updated Title");
- const variantRevision = Revisions.findOne({ documentId: variant._id });
- expect(variantRevision.documentData.title).to.equal("Updated Title");
- });
-
- it("should publish update for variant fields", function () {
+ it("should update variant fields", function () {
sandbox.stub(Reaction, "hasPermission", () => true);
const product = addProduct();
let variant = Products.findOne({ ancestors: [product._id] });
Meteor.call("products/updateProductField", variant._id, "title", "Updated Title");
- Meteor.call("revisions/publish", product._id);
variant = Products.findOne(variant._id);
expect(variant.title).to.equal("Updated Title");
});
@@ -542,31 +420,7 @@ describe("core product methods", function () {
expect(insertTagsSpy).to.not.have.been.called;
});
- it("should not new tag when passed tag name and null ID by admin", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- let product = addProduct();
- const tagName = "Product Tag";
- expect(Tags.findOne({ name: tagName })).to.be.undefined;
- Meteor.call("products/updateProductTags", product._id, tagName, null);
- const tag = Tags.findOne({ name: tagName });
- expect(tag.slug).to.equal(Reaction.getSlug(tagName));
- product = Products.findOne(product._id);
- expect(product.hashtags).to.not.contain(tag._id);
- });
-
- it("should add new tag to product revision when passed tag name and null ID by admin", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- const product = addProduct();
- const tagName = "Product Tag";
- expect(Tags.findOne({ name: tagName })).to.be.undefined;
- Meteor.call("products/updateProductTags", product._id, tagName, null);
- const tag = Tags.findOne({ name: tagName });
- expect(tag.slug).to.equal(Reaction.getSlug(tagName));
- const productRevision = Revisions.findOne({ documentId: product._id });
- expect(productRevision.documentData.hashtags).to.contain(tag._id);
- });
-
- it("should publish new product tag when passed tag name and null ID by admin", function () {
+ it("should create new tag when passed tag name and null ID by admin", function () {
sandbox.stub(Reaction, "hasPermission", () => true);
let product = addProduct();
const tagName = "Product Tag";
@@ -574,36 +428,11 @@ describe("core product methods", function () {
Meteor.call("products/updateProductTags", product._id, tagName, null);
const tag = Tags.findOne({ name: tagName });
expect(tag.slug).to.equal(Reaction.getSlug(tagName));
- Meteor.call("revisions/publish", product._id);
product = Products.findOne(product._id);
expect(product.hashtags).to.contain(tag._id);
});
- it("should not add existing tag when passed existing tag and tag._id by admin", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- let product = addProduct();
- const tag = Factory.create("tag");
- expect(Tags.find().count()).to.equal(1);
- expect(product.hashtags).to.not.contain(tag._id);
- Meteor.call("products/updateProductTags", product._id, tag.name, tag._id);
- expect(Tags.find().count()).to.equal(1);
- product = Products.findOne(product._id);
- expect(product.hashtags).to.not.contain(tag._id);
- });
-
- it("should add existing tag to product revision when passed existing tag and tag._id by admin", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- const product = addProduct();
- const tag = Factory.create("tag");
- expect(Tags.find().count()).to.equal(1);
- expect(product.hashtags).to.not.contain(tag._id);
- Meteor.call("products/updateProductTags", product._id, tag.name, tag._id);
- expect(Tags.find().count()).to.equal(1);
- const productRevision = Revisions.findOne({ documentId: product._id });
- expect(productRevision.documentData.hashtags).to.contain(tag._id);
- });
-
- it("should publish existing tag for product when passed existing tag and tag._id by admin", function () {
+ it("should add existing tag when passed existing tag and tag._id by admin", function () {
sandbox.stub(Reaction, "hasPermission", () => true);
let product = addProduct();
const tag = Factory.create("tag");
@@ -611,7 +440,6 @@ describe("core product methods", function () {
expect(product.hashtags).to.not.contain(tag._id);
Meteor.call("products/updateProductTags", product._id, tag.name, tag._id);
expect(Tags.find().count()).to.equal(1);
- Meteor.call("revisions/publish", product._id);
product = Products.findOne(product._id);
expect(product.hashtags).to.contain(tag._id);
});
@@ -633,70 +461,21 @@ describe("core product methods", function () {
expect(removeTagsSpy).to.not.have.been.called;
});
- it("should not remove product tag by admin", function () {
+ it("should remove product tag by admin", function () {
sandbox.stub(Reaction, "hasPermission", () => true);
let product = addProduct();
const tag = Factory.create("tag");
- // Update product tags and publish so the original prodcut will have the tags
+ // Update product tags and publish so the original product will have the tags
Meteor.call("products/updateProductTags", product._id, tag.name, tag._id);
- Meteor.call("revisions/publish", product._id);
product = Products.findOne(product._id);
expect(product.hashtags).to.contain(tag._id);
expect(Tags.find().count()).to.equal(1);
- // Remove the tag from the published prouct and ensure it didn't succeed.
- // Revision control should stop the published product from being changed.
+ // Remove the tag from the published product and ensure it succeed.
Meteor.call("products/removeProductTag", product._id, tag._id);
product = Products.findOne(product._id);
- expect(product.hashtags).to.contain(tag._id);
- expect(Tags.find().count()).to.equal(1);
- });
-
- it("should remove tag in product revision by admin", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- let product = addProduct();
- const tag = Factory.create("tag");
-
- // Update product tags and publish so the original prodcut will have the tags
- Meteor.call("products/updateProductTags", product._id, tag.name, tag._id);
- Meteor.call("revisions/publish", product._id);
- product = Products.findOne(product._id);
- expect(product.hashtags).to.contain(tag._id);
- expect(Tags.find().count()).to.equal(1);
-
- // Remove the tag from the published prouct and ensure it changed in the revision.
- Meteor.call("products/removeProductTag", product._id, tag._id);
- const productRevision = Revisions.findOne({
- "documentId": product._id,
- "workflow.status": { $nin: ["revision/published"] }
- });
- expect(productRevision.documentData.hashtags).to.not.contain(tag._id);
- expect(Tags.find().count()).to.equal(1);
- });
-
- it("should publish remove product tag by admin", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- let product = addProduct();
-
- // Update product tags and publish so the original prodcut will have the tags
- const tag = Factory.create("tag");
- Meteor.call("products/updateProductTags", product._id, tag.name, tag._id);
- Meteor.call("revisions/publish", product._id);
- product = Products.findOne(product._id);
- expect(product.hashtags).to.contain(tag._id);
- expect(Tags.find().count()).to.equal(1);
-
- // Remove the tag from the published prouct which should create a revision.
- // Then publish that revision and ensure that it published product changed.
- Meteor.call("products/removeProductTag", product._id, tag._id);
- Meteor.call("revisions/publish", product._id);
- product = Products.findOne(product._id);
- const tags = Tags.find();
expect(product.hashtags).to.not.contain(tag._id);
- expect(tags.count()).to.equal(1);
- // Tag should not be deleted, it should just be removed from the product
- expect(tags.fetch()[0].isDeleted).to.equal(false);
});
});
@@ -711,70 +490,13 @@ describe("core product methods", function () {
expect(productUpdateSpy).to.not.have.been.called;
});
- it("should not set handle for product by admin", function () {
+ it("should set handle for product by admin", function () {
sandbox.stub(Reaction, "hasPermission", () => true);
let product = addProduct();
- const productHandle = product.handle;
Meteor.call("products/updateProductField", product._id, "title", "new product name");
Meteor.call("products/setHandle", product._id);
product = Products.findOne(product._id);
- expect(product.handle).to.equal(productHandle);
- });
-
- it("should set handle correctly on product revision", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- const product = addProduct();
- Meteor.call("products/updateProductField", product._id, "title", "new second product name");
- Meteor.call("products/setHandle", product._id);
- const revision = Revisions.findOne({ documentId: product._id });
- expect(revision.documentData.handle).to.not.equal("new-second-product-name");
- });
-
- it("should not set handle on published product", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- let product = addProduct();
- Meteor.call("products/updateProductField", product._id, "title", "new second product name");
- Meteor.call("products/setHandle", product._id);
- product = Products.findOne(product._id);
- expect(product.handle).to.not.equal("new-second-product-name");
- });
-
- it("should publish handle correctly", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- let product = addProduct();
- Meteor.call("products/updateProductField", product._id, "title", "new second product name");
- Meteor.call("products/setHandle", product._id);
- Meteor.call("revisions/publish", product._id);
- product = Products.findOne(product._id);
- expect(product.handle).to.not.equal("new-second-product-name");
- });
-
- it("unpublished products with the same title should not receive correct handle", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- let product = addProduct();
- Meteor.call("products/updateProductField", product._id, "title", "new second product name");
- Meteor.call("products/setHandle", product._id);
- product = Products.findOne(product._id);
- expect(product.handle).to.not.equal("new-second-product-name-copy");
- });
-
- it("products with the same title should receive correct handle on revision", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- const product = addProduct();
- Meteor.call("products/updateProductField", product._id, "title", "new second product name");
- Meteor.call("products/setHandle", product._id);
- const productRevision = Revisions.findOne({ documentId: product._id });
- expect(productRevision.documentData.handle).to.not.equal("new-second-product-name-copy");
- });
-
- it("products with the same title should receive correct handle when published", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- let product = addProduct();
- Meteor.call("products/updateProductField", product._id, "title", "new second product name");
- Meteor.call("products/setHandle", product._id);
- Meteor.call("revisions/publish", product._id);
- product = Products.findOne(product._id);
- expect(product.handle).to.not.equal("new-second-product-name-copy");
+ expect(product.handle).to.equal("new-product-name");
});
});
@@ -794,31 +516,12 @@ describe("core product methods", function () {
expect(updateProductSpy).to.not.have.been.called;
});
- it("should not set handle tag for product by admin", function () {
+ it("should set handle tag for product by admin", function () {
sandbox.stub(Reaction, "hasPermission", () => true);
let product = addProduct();
const tag = Factory.create("tag");
Meteor.call("products/setHandleTag", product._id, tag._id);
product = Products.findOne(product._id);
- expect(product.handle).to.not.equal(tag.slug);
- });
-
- it("should set handle tag for product revision by admin", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- const product = addProduct();
- const tag = Factory.create("tag");
- Meteor.call("products/setHandleTag", product._id, tag._id);
- const productRevision = Revisions.findOne({ documentId: product._id });
- expect(productRevision.documentData.handle).to.equal(tag.slug);
- });
-
- it("should publish set handle tag for product by admin", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- let product = addProduct();
- const tag = Factory.create("tag");
- Meteor.call("products/setHandleTag", product._id, tag._id);
- Meteor.call("revisions/publish", product._id);
- product = Products.findOne(product._id);
expect(product.handle).to.equal(tag.slug);
});
});
@@ -840,7 +543,7 @@ describe("core product methods", function () {
expect(updateProductSpy).to.not.have.been.called;
});
- it("should not update product position by admin", function (done) {
+ it("should update product position by admin", function (done) {
sandbox.stub(Reaction, "hasPermission", () => true);
const product = addProduct();
const tag = Factory.create("tag");
@@ -851,49 +554,10 @@ describe("core product methods", function () {
};
expect(() => Meteor.call(
"products/updateProductPosition",
- product._id, position, tag._id
+ product._id, position, tag.slug
)).to.not.throw(Meteor.Error, /Access Denied/);
const updatedProduct = Products.findOne(product._id);
- expect(updatedProduct.positions).to.be.undefined;
-
- return done();
- });
-
- it("should update product revision position by admin", function (done) {
- sandbox.stub(Reaction, "hasPermission", () => true);
- const product = addProduct();
- const tag = Factory.create("tag");
- const position = {
- position: 0,
- weight: 0,
- updatedAt: new Date()
- };
- expect(() => Meteor.call(
- "products/updateProductPosition",
- product._id, position, tag._id
- )).to.not.throw(Meteor.Error, /Access Denied/);
- const updatedProductRevision = Revisions.findOne({ documentId: product._id });
- expect(updatedProductRevision.documentData.positions[tag._id].position).to.equal(0);
-
- return done();
- });
-
- it("should publish product position by admin", function (done) {
- sandbox.stub(Reaction, "hasPermission", () => true);
- const product = addProduct();
- const tag = Factory.create("tag");
- const position = {
- position: 0,
- weight: 0,
- updatedAt: new Date()
- };
- expect(() => Meteor.call(
- "products/updateProductPosition",
- product._id, position, tag._id
- )).to.not.throw(Meteor.Error, /Access Denied/);
- Meteor.call("revisions/publish", product._id);
- const updatedProduct = Products.findOne(product._id);
- expect(updatedProduct.positions[tag._id].position).to.equal(0);
+ expect(updatedProduct.positions).to.be.defined;
return done();
});
@@ -910,7 +574,7 @@ describe("core product methods", function () {
expect(updateProductSpy).to.not.have.been.called;
});
- it("should not update variants' position", function () {
+ it("should update variants' position", function () {
sandbox.stub(Reaction, "hasPermission", () => true);
const { variant: variant1 } = addProductSingleVariant();
const { variant: variant2 } = addProductSingleVariant();
@@ -926,54 +590,9 @@ describe("core product methods", function () {
const modifiedVariant1 = Products.findOne(variant1._id);
const modifiedVariant2 = Products.findOne(variant2._id);
const modifiedVariant3 = Products.findOne(variant3._id);
- expect(modifiedVariant1.index).to.be.undefined;
- expect(modifiedVariant2.index).to.be.undefined;
- expect(modifiedVariant3.index).to.be.undefined;
- });
-
- it("should update variants' revision position", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- const { variant: variant1 } = addProductSingleVariant();
- const { variant: variant2 } = addProductSingleVariant();
- const { variant: variant3 } = addProductSingleVariant();
-
- expect(variant1.index).to.be.undefined;
- expect(variant2.index).to.be.undefined;
- expect(variant3.index).to.be.undefined;
-
- Meteor.call("products/updateVariantsPosition", [
- variant2._id, variant3._id, variant1._id
- ]);
- const modifiedVariantRevision1 = Revisions.findOne({ documentId: variant1._id });
- const modifiedVariantRevision2 = Revisions.findOne({ documentId: variant2._id });
- const modifiedVariantRevision3 = Revisions.findOne({ documentId: variant3._id });
- expect(modifiedVariantRevision1.documentData.index).to.equal(2);
- expect(modifiedVariantRevision2.documentData.index).to.equal(0);
- expect(modifiedVariantRevision3.documentData.index).to.equal(1);
- });
-
- it("should publish variants' revision position", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- const { variant: variant1 } = addProductSingleVariant();
- const { variant: variant2 } = addProductSingleVariant();
- const { variant: variant3 } = addProductSingleVariant();
-
- expect(variant1.index).to.be.undefined;
- expect(variant2.index).to.be.undefined;
- expect(variant3.index).to.be.undefined;
-
- Meteor.call("products/updateVariantsPosition", [
- variant2._id, variant3._id, variant1._id
- ]);
- Meteor.call("revisions/publish", [
- variant1._id, variant2._id, variant3._id
- ]);
- const modifiedVariant1 = Products.findOne(variant1._id);
- const modifiedVariant2 = Products.findOne(variant2._id);
- const modifiedVariant3 = Products.findOne(variant3._id);
- expect(modifiedVariant1.index).to.equal(2);
- expect(modifiedVariant2.index).to.equal(0);
- expect(modifiedVariant3.index).to.equal(1);
+ expect(modifiedVariant1.index).to.be.equal(2);
+ expect(modifiedVariant2.index).to.be.equal(0);
+ expect(modifiedVariant3.index).to.be.equal(1);
});
});
@@ -989,44 +608,15 @@ describe("core product methods", function () {
expect(updateProductSpy).to.not.have.been.called;
});
- it("should not add meta fields by admin", function (done) {
- sandbox.stub(Reaction, "hasPermission", () => true);
- let product = addProduct();
- Meteor.call("products/updateMetaFields", product._id, {
- key: "Material",
- value: "Spandex"
- });
- product = Products.findOne(product._id);
- expect(product.metafields.length).to.be.equal(0);
-
- return done();
- });
-
- it("should add meta fields to product revision by admin", function (done) {
- sandbox.stub(Reaction, "hasPermission", () => true);
- const product = addProduct();
- Meteor.call("products/updateMetaFields", product._id, {
- key: "Material",
- value: "Spandex"
- });
- const productRevision = Revisions.findOne({ documentId: product._id });
- expect(productRevision.documentData.metafields[0].key).to.equal("Material");
- expect(productRevision.documentData.metafields[0].value).to.equal("Spandex");
-
- return done();
- });
-
- it("should publish add meta fields by admin", function (done) {
+ it("should add meta fields by admin", function (done) {
sandbox.stub(Reaction, "hasPermission", () => true);
let product = addProduct();
Meteor.call("products/updateMetaFields", product._id, {
key: "Material",
value: "Spandex"
});
- Meteor.call("revisions/publish", product._id);
product = Products.findOne(product._id);
- expect(product.metafields[0].key).to.equal("Material");
- expect(product.metafields[0].value).to.equal("Spandex");
+ expect(product.metafields.length).to.be.equal(1);
return done();
});
@@ -1041,60 +631,15 @@ describe("core product methods", function () {
expect(updateProductSpy).to.not.have.been.called;
});
- it("should let admin publish product changes", function () {
+ it("should let admin toggle product visibility", function () {
sandbox.stub(Reaction, "hasPermission", () => true);
let product = addProduct();
const { isVisible } = product;
expect(() => Meteor.call("products/publishProduct", product._id)).to.not.throw(Meteor.Error, /Access Denied/);
- Meteor.call("revisions/publish", product._id);
product = Products.findOne(product._id);
- // We switch the visible state in `products/publishProdct` for revisions
expect(product.isVisible).to.equal(!isVisible);
});
- it("should not let admin toggle product visibility", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- let product = addProduct();
- const { isVisible } = product;
- expect(() => Meteor.call("products/publishProduct", product._id)).to.not.throw(Meteor.Error, /Access Denied/);
- product = Products.findOne(product._id);
- expect(product.isVisible).to.equal(isVisible);
- expect(() => Meteor.call("products/publishProduct", product._id)).to.not.throw(Meteor.Error, /Bad Request/);
- product = Products.findOne(product._id);
- expect(product.isVisible).to.equal(isVisible);
- });
-
- it("should let admin toggle product revision visibility", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- const product = addProduct();
- let productRevision = Revisions.findOne({ documentId: product._id });
- const { isVisible } = productRevision.documentData;
- expect(() => Meteor.call("products/publishProduct", product._id)).to.not.throw(Meteor.Error, /Access Denied/);
- productRevision = Revisions.findOne({ documentId: product._id });
- expect(productRevision.documentData.isVisible).to.equal(!isVisible);
- expect(() => Meteor.call("products/publishProduct", product._id)).to.not.throw(Meteor.Error, /Bad Request/);
- productRevision = Revisions.findOne({ documentId: product._id });
- expect(productRevision.documentData.isVisible).to.equal(!isVisible);
- });
-
- it("should publish admin toggle product visibility", function () {
- sandbox.stub(Reaction, "hasPermission", () => true);
- let product = addProduct();
- const { isVisible } = product; // false
-
- // Toggle visible
- expect(() => Meteor.call("products/publishProduct", product._id)).to.not.throw(Meteor.Error, /Access Denied/);
- Meteor.call("revisions/publish", product._id);
- product = Products.findOne(product._id);
- expect(product.isVisible).to.equal(!isVisible);
-
- // Toggle not visible
- expect(() => Meteor.call("products/publishProduct", product._id)).to.not.throw(Meteor.Error, /Bad Request/);
- Meteor.call("revisions/publish", product._id);
- product = Products.findOne(product._id);
- expect(product.isVisible).to.equal(isVisible);
- });
-
it("should not publish product when missing title", function () {
sandbox.stub(Reaction, "hasPermission", () => true);
let product = addProduct();
diff --git a/imports/plugins/core/catalog/server/methods/catalog.js b/imports/plugins/core/catalog/server/methods/catalog.js
index 75e9e9fe9dc..e33d33da7db 100644
--- a/imports/plugins/core/catalog/server/methods/catalog.js
+++ b/imports/plugins/core/catalog/server/methods/catalog.js
@@ -5,11 +5,11 @@ import { EJSON } from "meteor/ejson";
import { Meteor } from "meteor/meteor";
import { ReactionProduct } from "/lib/api";
import { Hooks, Logger, Reaction } from "/server/api";
-import { MediaRecords, Products, Revisions, Tags } from "/lib/collections";
+import { MediaRecords, Products, Tags } from "/lib/collections";
import { Media } from "/imports/plugins/core/files/server";
import rawCollections from "/imports/collections/rawCollections";
-import getProductPriceRange from "/imports/plugins/core/revisions/server/no-meteor/utils/getProductPriceRange";
-import getVariants from "/imports/plugins/core/revisions/server/no-meteor/utils/getVariants";
+import getProductPriceRange from "../no-meteor/utils/getProductPriceRange";
+import getVariants from "../no-meteor/utils/getVariants";
import isSoldOut from "../no-meteor/utils/isSoldOut";
import isLowQuantity from "../no-meteor/utils/isLowQuantity";
import isBackorder from "../no-meteor/utils/isBackorder";
@@ -189,7 +189,7 @@ function copyMedia(newId, variantOldId, variantNewId) {
})
.then((fileRecords) => {
fileRecords.forEach((fileRecord) => {
- // Copy File and insert directly, bypasing revision control
+ // Copy File and insert
fileRecord
.fullClone({
productId: newId,
@@ -259,7 +259,6 @@ function denormalize(id, field) {
}
}
- // TODO: Determine if product revision needs to be updated as well.
Products.update(
id,
{
@@ -338,9 +337,7 @@ function createProduct(props = null) {
/**
* @function
* @name updateCatalogProduct
- * @summary Updates a product's revision and conditionally updates
- * the underlying product.
- *
+ * @summary Updates a product document.
* @param {String} userId - currently logged in user
* @param {Object} selector - selector for product to update
* @param {Object} modifier - Object describing what parts of the document to update.
@@ -350,23 +347,17 @@ function createProduct(props = null) {
function updateCatalogProduct(userId, selector, modifier, validation) {
const product = Products.findOne(selector);
- const shouldUpdateProduct = Hooks.Events.run("beforeUpdateCatalogProduct", product, {
+ Hooks.Events.run("beforeUpdateCatalogProduct", product, {
userId,
modifier,
validation
});
- if (shouldUpdateProduct) {
- const result = Products.update(selector, modifier, validation);
-
- Hooks.Events.run("afterUpdateCatalogProduct", product, { modifier });
-
- return result;
- }
+ const result = Products.update(selector, modifier, validation);
- Logger.debug(`beforeUpdateCatalogProduct hook returned falsy, not updating catalog product`);
+ Hooks.Events.run("afterUpdateCatalogProduct", product, { modifier });
- return false;
+ return result;
}
Meteor.methods({
@@ -396,8 +387,7 @@ Meteor.methods({
}
// Verify that this variant and any ancestors are not deleted.
- // Child variants cannot be added if a parent product or product revision
- // is marked as `{ isDeleted: true }`
+ // Child variants cannot be added if a parent product is marked as `{ isDeleted: true }`
if (ReactionProduct.isAncestorDeleted(variant, true)) {
throw new Meteor.Error("server-error", "Unable to create product variant");
}
@@ -472,7 +462,6 @@ Meteor.methods({
let newId;
try {
- Hooks.Events.run("beforeInsertCatalogProductInsertRevision", clone);
newId = Products.insert(clone, { validate: false });
const newProduct = Products.findOne(newId);
Hooks.Events.run("afterInsertCatalogProduct", newProduct);
@@ -515,8 +504,7 @@ Meteor.methods({
const { ancestors } = product;
// Verify that the parent variant and any ancestors are not deleted.
- // Child variants cannot be added if a parent product or product revision
- // is marked as `{ isDeleted: true }`
+ // Child variants cannot be added if a parent product is marked as `{ isDeleted: true }`
if (ReactionProduct.isAncestorDeleted(product, true)) {
throw new Meteor.Error("server-error", "Unable to create product variant");
}
@@ -543,11 +531,9 @@ Meteor.methods({
}
Hooks.Events.run("beforeInsertCatalogProduct", assembledVariant);
- const _id = Products.insert(assembledVariant);
+ Products.insert(assembledVariant);
Hooks.Events.run("afterInsertCatalogProduct", assembledVariant);
- Hooks.Events.run("afterInsertCatalogProductInsertRevision", Products.findOne({ _id }));
-
Logger.debug(`products/createVariant: created variant: ${newVariantId} for ${parentId}`);
return newVariantId;
@@ -649,9 +635,17 @@ Meteor.methods({
// out if nothing to delete
if (!Array.isArray(toDelete) || toDelete.length === 0) return false;
- // Flag the variant and all its children as deleted in Revisions collection.
+ // Flag the variant and all its children as deleted.
toDelete.forEach((product) => {
Hooks.Events.run("beforeRemoveCatalogProduct", product, { userId: this.userId });
+ Products.update({
+ _id: product._id,
+ type: product.type
+ }, {
+ $set: {
+ isDeleted: true
+ }
+ });
Hooks.Events.run("afterRemoveCatalogProduct", this.userId, product);
});
@@ -760,7 +754,6 @@ Meteor.methods({
newProduct.title = createTitle(newProduct.title, newProduct._id);
newProduct.handle = createHandle(Reaction.getSlug(newProduct.title), newProduct._id);
}
- Hooks.Events.run("beforeInsertCatalogProductInsertRevision", newProduct);
result = Products.insert(newProduct, { validate: false });
Hooks.Events.run("afterInsertCatalogProduct", newProduct);
results.push(result);
@@ -789,7 +782,6 @@ Meteor.methods({
delete newVariant.createdAt;
delete newVariant.publishedAt; // TODO can variant have this param?
- Hooks.Events.run("beforeInsertCatalogProductInsertRevision", newVariant);
result = Products.insert(newVariant, { validate: false });
Hooks.Events.run("afterInsertCatalogProduct", newVariant);
copyMedia(productNewId, variant._id, variantNewId);
@@ -822,27 +814,20 @@ Meteor.methods({
throw new Meteor.Error("invalid-parameter", "Product should have a valid shopId");
}
- // Create product revision
- Hooks.Events.run("beforeInsertCatalogProductInsertRevision", product);
-
return Products.insert(product);
}
+ // Create a product
const newSimpleProduct = createProduct();
- // Create simple product revision
- Hooks.Events.run("afterInsertCatalogProductInsertRevision", newSimpleProduct);
-
- const newVariant = createProduct({
+ // Create a product variant
+ createProduct({
ancestors: [newSimpleProduct._id],
price: 0.0,
title: "",
type: "variant" // needed for multi-schema
});
- // Create variant revision
- Hooks.Events.run("afterInsertCatalogProductInsertRevision", newVariant);
-
return newSimpleProduct._id;
},
@@ -902,18 +887,25 @@ Meteor.methods({
return ids;
});
- // Flag the product and all its variants as deleted in the Revisions collection.
+ // Flag the product and all of it's variants as deleted.
productsWithVariants.forEach((toArchiveProduct) => {
Hooks.Events.run("beforeRemoveCatalogProduct", toArchiveProduct, { userId: this.userId });
-
+ Products.update({
+ _id: toArchiveProduct._id,
+ type: toArchiveProduct.type
+ }, {
+ $set: {
+ isDeleted: true
+ }
+ });
Hooks.Events.run("afterRemoveCatalogProduct", this.userId, toArchiveProduct);
});
- const numFlaggedAsDeleted = Revisions.find({
- "documentId": {
+ const numFlaggedAsDeleted = Products.find({
+ _id: {
$in: ids
},
- "documentData.isDeleted": true
+ isDeleted: true
}).count();
if (numFlaggedAsDeleted > 0) {
@@ -1017,7 +1009,6 @@ Meteor.methods({
}
// If we get a result from the product update,
- // meaning the update went past revision control,
// denormalize and attach results to top-level product
if (result === 1) {
if (type === "variant" && toDenormalize.indexOf(field) >= 0) {
diff --git a/imports/plugins/core/revisions/server/no-meteor/utils/getProductPriceRange.js b/imports/plugins/core/catalog/server/no-meteor/utils/getProductPriceRange.js
similarity index 91%
rename from imports/plugins/core/revisions/server/no-meteor/utils/getProductPriceRange.js
rename to imports/plugins/core/catalog/server/no-meteor/utils/getProductPriceRange.js
index 7107ce9a4be..b92229840bf 100644
--- a/imports/plugins/core/revisions/server/no-meteor/utils/getProductPriceRange.js
+++ b/imports/plugins/core/catalog/server/no-meteor/utils/getProductPriceRange.js
@@ -1,4 +1,4 @@
-import getPriceRange from "/imports/plugins/core/catalog/server/no-meteor/utils/getPriceRange";
+import getPriceRange from "./getPriceRange";
import getVariants from "./getVariants";
import getVariantPriceRange from "./getVariantPriceRange";
diff --git a/imports/plugins/core/revisions/server/no-meteor/utils/getProductPriceRange.test.js b/imports/plugins/core/catalog/server/no-meteor/utils/getProductPriceRange.test.js
similarity index 100%
rename from imports/plugins/core/revisions/server/no-meteor/utils/getProductPriceRange.test.js
rename to imports/plugins/core/catalog/server/no-meteor/utils/getProductPriceRange.test.js
diff --git a/imports/plugins/core/revisions/server/no-meteor/utils/getVariantPriceRange.js b/imports/plugins/core/catalog/server/no-meteor/utils/getVariantPriceRange.js
similarity index 83%
rename from imports/plugins/core/revisions/server/no-meteor/utils/getVariantPriceRange.js
rename to imports/plugins/core/catalog/server/no-meteor/utils/getVariantPriceRange.js
index 843ad196f4e..8a1411993e4 100644
--- a/imports/plugins/core/revisions/server/no-meteor/utils/getVariantPriceRange.js
+++ b/imports/plugins/core/catalog/server/no-meteor/utils/getVariantPriceRange.js
@@ -1,5 +1,4 @@
-import getPriceRange from "/imports/plugins/core/catalog/server/no-meteor/utils/getPriceRange";
-import getProduct from "./getProduct";
+import getPriceRange from "./getPriceRange";
import getVariants from "./getVariants";
/**
@@ -12,11 +11,12 @@ import getVariants from "./getVariants";
* @return {Promise