Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move all /server files to plugins #4366

Merged
merged 30 commits into from
Jul 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
2715886
chore: remove empty file
aldeed Jun 22, 2018
68cea06
refactor: move server/startup and init files to core plugin
aldeed Jun 22, 2018
1aafe1d
refactor: move core app tests and import Reaction from /server/api/core
aldeed Jun 22, 2018
cf839fc
refactor: move core Email functions
aldeed Jun 22, 2018
38cca9d
refactor: move core roles files
aldeed Jun 22, 2018
5111a17
refactor: remove unused templates code
aldeed Jun 22, 2018
c23d39d
refactor: move fixtures folder
aldeed Jun 22, 2018
c168a19
refactor: put core shop methods in separate files
aldeed Jun 24, 2018
881fe0b
refactor: move accounts methods into plugin
aldeed Jun 24, 2018
625f4ff
refactor: move email methods to plugin
aldeed Jun 25, 2018
8eb3511
refactor: move helper methods
aldeed Jun 25, 2018
b41d5d2
refactor: move i18n methods to plugin
aldeed Jun 25, 2018
e56268b
refactor: move shipping methods to plugin
aldeed Jun 25, 2018
719f8ee
refactor: move registry methods to plugin
aldeed Jun 25, 2018
d504b8a
refactor: move payments methods to plugin
aldeed Jun 25, 2018
01db577
refactor: move package methods to plugin
aldeed Jun 25, 2018
6c7f545
refactor: move order methods to plugin
aldeed Jun 25, 2018
84bbae9
refactor: move cart methods to plugin
aldeed Jun 25, 2018
e33f7d8
refactor: move group methods to plugin
aldeed Jun 25, 2018
b9805b8
refactor: move order workflow methods to plugin
aldeed Jun 25, 2018
e4c7f4f
refactor: move hooks to plugins
aldeed Jun 25, 2018
75a1a3e
refactor: move Reaction obj to core plugin
aldeed Jun 25, 2018
23d9668
refactor: move core publications to plugin
aldeed Jun 25, 2018
373d9ca
refactor: fix refactor mistakes
aldeed Jun 25, 2018
db55943
fix: broken import after refactor
aldeed Jun 25, 2018
6c13016
fix: Twilio and Nexmo libs are now imported correctly
aldeed Jun 29, 2018
8f97255
fix: correctly finish copying cart to order
aldeed Jun 29, 2018
4d8d379
Merge branch 'release-1.14.0' into refactor-aldeed-server-to-plugin
aldeed Jun 29, 2018
4490817
refactor: move new merged test file
aldeed Jun 29, 2018
72b31c4
Merge branch 'release-1.14.0' into refactor-aldeed-server-to-plugin
aldeed Jul 2, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Empty file removed client/modules/index.js
Empty file.
2 changes: 1 addition & 1 deletion imports/plugins/core/accounts/register.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Reaction } from "/server/api";
import Reaction from "/imports/plugins/core/core/server/Reaction";

/**
* @file Accounts core plugin: Manage how members sign into your shop
Expand Down
2 changes: 1 addition & 1 deletion imports/plugins/core/accounts/server/i18n/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { loadTranslations } from "/server/startup/i18n";
import { loadTranslations } from "/imports/plugins/core/core/server/startup/i18n";

import ar from "./ar.json";
import bg from "./bg.json";
Expand Down
14 changes: 13 additions & 1 deletion imports/plugins/core/accounts/server/init.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
import { Reaction, Hooks } from "/server/api";
import Hooks from "@reactioncommerce/hooks";
import Reaction from "/imports/plugins/core/core/server/Reaction";
import { Accounts, Groups } from "/lib/collections";

// set default admin user's account as "owner"
Hooks.Events.add("afterCreateDefaultAdminUser", (user) => {
const group = Groups.findOne({ slug: "owner", shopId: Reaction.getShopId() });
Accounts.update({ _id: user._id }, { $set: { groups: [group._id] } });
Hooks.Events.run("afterAccountsUpdate", null, {
accountId: user._id,
updatedFields: ["groups"]
});
});

Hooks.Events.add("afterCoreInit", () => {
Reaction.addRolesToGroups({
Expand Down
30 changes: 30 additions & 0 deletions imports/plugins/core/accounts/server/methods/addUserPermissions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import Logger from "@reactioncommerce/logger";
import { Meteor } from "meteor/meteor";
import { check, Match } from "meteor/check";
import { Roles } from "meteor/alanning:roles";
import Reaction from "/imports/plugins/core/core/server/Reaction";

/**
* @name accounts/addUserPermissions
* @memberof Accounts/Methods
* @method
* @param {String} userId - userId
* @param {Array|String} permissions - Name of role/permission.
* If array, users returned will have at least one of the roles specified but need not have _all_ roles.
* @param {String} [group] Optional name of group to restrict roles to. User's Roles.GLOBAL_GROUP will also be checked.
* @returns {Boolean} success/failure
*/
export default function addUserPermissions(userId, permissions, group) {
if (!Reaction.hasPermission("reaction-accounts", Meteor.userId(), group)) {
throw new Meteor.Error("access-denied", "Access denied");
}
check(userId, Match.OneOf(String, Array));
check(permissions, Match.OneOf(String, Array));
check(group, Match.Optional(String));
this.unblock();
try {
return Roles.addUsersToRoles(userId, permissions, group);
} catch (error) {
return Logger.error(error);
}
}
58 changes: 58 additions & 0 deletions imports/plugins/core/accounts/server/methods/addressBookRemove.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import Hooks from "@reactioncommerce/hooks";
import { Meteor } from "meteor/meteor";
import { check, Match } from "meteor/check";
import { Accounts } from "/lib/collections";
import Reaction from "/imports/plugins/core/core/server/Reaction";

/**
* @name accounts/addressBookRemove
* @memberof Accounts/Methods
* @method
* @summary Remove existing address in user's profile
* @param {String} addressId - address `_id`
* @param {String} [accountUserId] - `account.userId` used by admin to edit users
* @return {Object} Removed address object
*/
export default function addressBookRemove(addressId, accountUserId) {
check(addressId, String);
check(accountUserId, Match.Optional(String));
// security, check for admin access. We don't need to check every user call
// here because we are calling `Meteor.userId` from within this Method.
if (typeof accountUserId === "string") { // if this will not be a String -
// `check` will not pass it.
if (Meteor.userId() !== accountUserId && !Reaction.hasPermission("reaction-accounts")) {
throw new Meteor.Error("access-denied", "Access denied");
}
}
this.unblock();

const userId = accountUserId || Meteor.userId();
const account = Accounts.findOne({ userId });
// remove this address in cart, if used, before completely removing
Meteor.call("cart/unsetAddresses", addressId, userId);

const updatedAccountResult = Accounts.update({
userId,
"profile.addressBook._id": addressId
}, {
$pull: {
"profile.addressBook": {
_id: addressId
}
}
}, { bypassCollection2: true });

// forceIndex when removing an address
Hooks.Events.run("afterAccountsUpdate", Meteor.userId(), {
accountId: account._id,
updatedFields: ["forceIndex"]
});

// If the address remove was successful, then return the removed addrtess
if (updatedAccountResult === 1) {
// Pull the address from the account before it was updated and return it
return account.profile.addressBook.find((removedAddress) => addressId === removedAddress._id);
}

throw new Meteor.Error("server-error", "Unable to remove address from account");
}
149 changes: 149 additions & 0 deletions imports/plugins/core/accounts/server/methods/addressBookUpdate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import _ from "lodash";
import Hooks from "@reactioncommerce/hooks";
import { Meteor } from "meteor/meteor";
import { check, Match } from "meteor/check";
import { Accounts, Cart } from "/lib/collections";
import * as Schemas from "/lib/collections/schemas";
import Reaction from "/imports/plugins/core/core/server/Reaction";

/**
* @name accounts/addressBookUpdate
* @memberof Accounts/Methods
* @method
* @summary Update existing address in user's profile
* @param {Object} address - address
* @param {String|null} [accountUserId] - `account.userId` used by admin to edit users
* @param {shipping|billing} [type] - name of selected address type
* @return {Object} The updated address
*/
export default function addressBookUpdate(address, accountUserId, type) {
Schemas.Address.validate(address);
check(accountUserId, Match.OneOf(String, null, undefined));
check(type, Match.Maybe(String));
// security, check for admin access. We don't need to check every user call
// here because we are calling `Meteor.userId` from within this Method.
if (typeof accountUserId === "string") { // if this will not be a String -
// `check` will not pass it.
if (Meteor.userId() !== accountUserId && !Reaction.hasPermission("reaction-accounts")) {
throw new Meteor.Error("access-denied", "Access denied");
}
}
this.unblock();

// If no userId is provided, use the current user
const userId = accountUserId || Meteor.userId();
// Find old state of isShippingDefault & isBillingDefault to compare and reflect in cart
const account = Accounts.findOne({ userId });
const oldAddress = (account.profile.addressBook || []).find((addr) => addr._id === address._id);

if (!oldAddress) throw new Meteor.Error("not-found", `No existing address found with ID ${address._id}`);

// Set new address to be default for `type`
if (typeof type === "string") {
Object.assign(address, { [type]: true });
}

// We want the cart addresses to be updated when current default address
// (shipping or Billing) are different than the previous one, but also
// when the current default address(ship or bill) gets edited(so Current and Previous default are the same).
// This check can be simplified to :
if (address.isShippingDefault || address.isBillingDefault ||
oldAddress.isShippingDefault || oldAddress.isBillingDefault) {
// Find user cart
// Cart should exist to this moment, so we don't need to to verify its existence.
const cart = Cart.findOne({ userId });

// If isShippingDefault address has changed
if (oldAddress.isShippingDefault !== address.isShippingDefault) {
// Update the cart to use new default shipping address
if (address.isShippingDefault) {
Meteor.call("cart/setShipmentAddress", cart._id, address);
} else {
// If the new address is not the shipping default, remove it from the cart
Meteor.call("cart/unsetAddresses", address._id, userId, "shipping");
}
} else if (address.isShippingDefault && oldAddress.isShippingDefault) {
// If shipping address was edited, but isShippingDefault status not changed, update the cart address
Meteor.call("cart/setShipmentAddress", cart._id, address);
}

// If isBillingDefault address has changed
if (oldAddress.isBillingDefault !== address.isBillingDefault) {
// Update the cart to use new default billing address
if (address.isBillingDefault) {
Meteor.call("cart/setPaymentAddress", cart._id, address);
} else {
// If the new address is not the shipping default, remove it from the cart
Meteor.call("cart/unsetAddresses", address._id, userId, "billing");
}
} else if (address.isBillingDefault && oldAddress.isBillingDefault) {
// If shipping address was edited, but isShippingDefault status not changed, update the cart address
Meteor.call("cart/setPaymentAddress", cart._id, address);
}
}

// Update all other to set the default type to false
account.profile.addressBook.forEach((addr) => {
if (addr._id === address._id) {
Object.assign(addr, address);
} else if (typeof type === "string") {
Object.assign(addr, { [type]: false });
}
});

// TODO: revisit why we update Meteor.users differently than accounts
// We could possibly remove the whole `userUpdateQuery` variable
// and update Meteor.users with the accountsUpdateQuery data
const userUpdateQuery = {
$set: {
"profile.addressBook": address
}
};

const accountsUpdateQuery = {
$set: {
"profile.addressBook": account.profile.addressBook
}
};
// update the name when there is no name or the user updated his only shipping address
if (!account.name || _.get(account, "profile.addressBook.length", 0) <= 1) {
userUpdateQuery.$set.name = address.fullName;
accountsUpdateQuery.$set.name = address.fullName;
}

// Update the Meteor.users collection with new address info
Meteor.users.update(Meteor.userId(), userUpdateQuery);

// Update the Reaction Accounts collection with new address info
const updatedAccountResult = Accounts.update({
userId
}, accountsUpdateQuery);

// Create an array which contains all fields that have changed
// This is used for search, to determine if we need to re-index
const updatedFields = [];
Object.keys(address).forEach((key) => {
if (address[key] !== oldAddress[key]) {
updatedFields.push(key);
}
});

// Run afterAccountsUpdate hook to update Accounts Search
Hooks.Events.run("afterAccountsUpdate", Meteor.userId(), {
accountId: account._id,
updatedFields
});

// If the address update was successful, then return the full updated addrtess
if (updatedAccountResult === 1) {
// Find the account
const updatedAccount = Accounts.findOne({
userId
});

// Pull the updated address and return it
return updatedAccount.profile.addressBook.find((updatedAddress) => address._id === updatedAddress._id);
}

throw new Meteor.Error("server-error", "Unable to update account address");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Accounts as MeteorAccounts } from "meteor/accounts-base";

/**
* @name accounts/createFallbackLoginToken
* @memberof Accounts/Methods
* @method
* @summary Returns a new loginToken for current user, that can be used for special login scenarios
* e.g. store the newly created token as cookie on the browser, if the client does not offer local storage.
* @returns {String|null} loginToken for current user
*/
export default function createFallbackLoginToken() {
if (this.userId) {
const stampedLoginToken = MeteorAccounts._generateStampedLoginToken();
const loginToken = stampedLoginToken.token;
MeteorAccounts._insertLoginToken(this.userId, stampedLoginToken);
return loginToken;
}

return null;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Meteor } from "meteor/meteor";

/**
* @name accounts/currentUserHasPassword
* @method
* @memberof Accounts/Methods
* @summary Check if current user has password
* @returns {Boolean} True if current user has password
* @private
*/
export default function currentUserHasPassword() {
const user = Meteor.users.findOne(Meteor.userId());
return !!user.services.password;
}
12 changes: 12 additions & 0 deletions imports/plugins/core/accounts/server/methods/getUserId.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Meteor } from "meteor/meteor";

/**
* @name reaction/getUserId
* @method
* @memberof Reaction/Methods
* @summary return server side userId if available
* @return {String} userId - if available
*/
export default function getUserId() {
return Meteor.userId();
}
Loading