From da4a379586c347a39adb3984d842490a210c7392 Mon Sep 17 00:00:00 2001 From: Aaron Judd Date: Mon, 15 Aug 2016 10:36:55 -0700 Subject: [PATCH] logout and hasPermission updates (#1290) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * updated hasPermissions, router behaviour - resolves #1122 - refactors client hasPermissions to wait for a userId if one isn’t immediately found - intentionally not redirecting to home page (not sure if that’s the best behavior, better to have login?) - adds subscription manager to a few more collections * fix typo * import lodash might work better if _.find exists * check for existing route table --- .../accounts/templates/dropdown/dropdown.js | 4 - client/modules/core/main.js | 120 ++++++++++++------ client/modules/core/subscriptions.js | 11 +- client/modules/router/main.js | 11 +- client/modules/router/startup.js | 13 ++ 5 files changed, 105 insertions(+), 54 deletions(-) diff --git a/client/modules/accounts/templates/dropdown/dropdown.js b/client/modules/accounts/templates/dropdown/dropdown.js index d016391ced4..4e0ad0c6c7f 100644 --- a/client/modules/accounts/templates/dropdown/dropdown.js +++ b/client/modules/accounts/templates/dropdown/dropdown.js @@ -30,10 +30,6 @@ Template.loginDropdown.events({ if (error) { Logger.warn("Failed to logout.", error); } - // go home on logout - Reaction.Subscriptions.Manager.reset(); - Reaction.Router.reload(); - Reaction.Router.go("/"); }); }, diff --git a/client/modules/core/main.js b/client/modules/core/main.js index 889b1e1686a..effd6fb9361 100644 --- a/client/modules/core/main.js +++ b/client/modules/core/main.js @@ -8,6 +8,7 @@ import Logger from "/client/modules/logger"; import { Countries } from "/client/collections"; import { localeDep } from "/client/modules/i18n"; import { Packages, Shops } from "/lib/collections"; +import { Router } from "/client/modules/router"; /** * Reaction namespace @@ -77,56 +78,95 @@ export default { hasPermission(checkPermissions, checkUserId, checkGroup) { let group = this.getShopId(); let permissions = ["owner"]; + let id = ""; + const userId = checkUserId || this.userId || Meteor.userId(); + // + // local roleCheck function + // is the bulk of the logic + // called out a userId is validated. + // + function roleCheck() { + // permissions can be either a string or an array + // we'll force it into an array and use that + if (checkPermissions === undefined) { + permissions = ["owner"]; + } else if (typeof checkPermissions === "string") { + permissions = [checkPermissions]; + } else { + permissions = checkPermissions; + } + // if the user has admin, owner permissions we'll always check if those roles are enough + permissions.push("owner"); + permissions = _.uniq(permissions); - // default group to the shop or global if shop - // isn't defined for some reason. - if (checkGroup !== undefined && typeof checkGroup === "string") { - group = checkGroup; - } - if (!group) { - group = Roles.GLOBAL_GROUP; + // + // return if user has permissions in the group + // + if (Roles.userIsInRole(userId, permissions, group)) { + return true; + } + // global roles check + let sellerShopPermissions = Roles.getGroupsForUser(userId, "admin"); + // we're looking for seller permissions. + if (sellerShopPermissions) { + // loop through shops roles and check permissions + for (let key in sellerShopPermissions) { + if (key) { + let shop = sellerShopPermissions[key]; + if (Roles.userIsInRole(userId, permissions, shop)) { + return true; + } + } + } + } + // no specific permissions found returning false + return false; } - // use current user if userId if not provided - // becauase you gotta have a user to check permissions - const userId = checkUserId || this.userId || Meteor.userId(); - if (!userId) { + // + // check if a user id has been found + // in line 156 setTimeout + // + function validateUserId() { + if (Meteor.userId()) { + Meteor.clearTimeout(id); + Router.reload(); + return roleCheck(); + } return false; } - // permissions can be either a string or an array - // we'll force it into an array and use that - if (checkPermissions === undefined) { - permissions = ["owner"]; - } else if (typeof checkPermissions === "string") { - permissions = [checkPermissions]; - } else { - permissions = checkPermissions; - } - // if the user has admin, owner permissions we'll always check if those roles are enough - permissions.push("owner"); - permissions = _.uniq(permissions); // - // return if user has permissions in the group + // actual logic block to check permissions + // we'll bypass unecessary checks during + // a user logging, as we'll check again + // when everything is ready // - if (Roles.userIsInRole(userId, permissions, group)) { - return true; - } - // global roles check - let sellerShopPermissions = Roles.getGroupsForUser(userId, "admin"); - // we're looking for seller permissions. - if (sellerShopPermissions) { - // loop through shops roles and check permissions - for (let key in sellerShopPermissions) { - if (key) { - let shop = sellerShopPermissions[key]; - if (Roles.userIsInRole(userId, permissions, shop)) { - return true; - } - } + if (Meteor.loggingIn() === false) { + // + // this userId check happens because when logout + // occurs it takes a few cycles for a new anonymous user + // to get created and during this time the user has no + // permission, not even guest permissions so we + // need to wait and reload the routes. This + // mainly affects the logout from dashboard pages + // + if (!userId) { + id = Meteor.setTimeout(validateUserId, 5000); + } else { + return roleCheck(); + } + + // default group to the shop or global if shop + // isn't defined for some reason. + if (checkGroup !== undefined && typeof checkGroup === "string") { + group = checkGroup; + } + if (!group) { + group = Roles.GLOBAL_GROUP; } } - // no specific permissions found returning false + // return false to be safe return false; }, diff --git a/client/modules/core/subscriptions.js b/client/modules/core/subscriptions.js index 1413d26a1f9..a3278ecc154 100644 --- a/client/modules/core/subscriptions.js +++ b/client/modules/core/subscriptions.js @@ -28,17 +28,17 @@ Subscriptions.Account = Subscriptions.Manager.subscribe("Accounts", Meteor.userI /** * General Subscriptions */ -Subscriptions.Shops = Meteor.subscribe("Shops"); +Subscriptions.Shops = Subscriptions.Manager.subscribe("Shops"); -Subscriptions.Packages = Meteor.subscribe("Packages"); +Subscriptions.Packages = Subscriptions.Manager.subscribe("Packages"); -Subscriptions.Tags = Meteor.subscribe("Tags"); +Subscriptions.Tags = Subscriptions.Manager.subscribe("Tags"); -Subscriptions.Media = Meteor.subscribe("Media"); +Subscriptions.Media = Subscriptions.Manager.subscribe("Media"); // admin only // todo should we put this inside autorun and detect user changes -Subscriptions.Inventory = Meteor.subscribe("Inventory"); +Subscriptions.Inventory = Subscriptions.Manager.subscribe("Inventory"); /** * Subscriptions that need to reload on new sessions @@ -70,4 +70,5 @@ Tracker.autorun(() => { sessionId = Session.get("sessionId"); }); Subscriptions.Cart = Meteor.subscribe("Cart", sessionId, Meteor.userId()); + Subscriptions.UserProfile = Meteor.subscribe("UserProfile", Meteor.userId()); }); diff --git a/client/modules/router/main.js b/client/modules/router/main.js index d5a1b2ed1ba..5d61a2f8e63 100644 --- a/client/modules/router/main.js +++ b/client/modules/router/main.js @@ -1,11 +1,12 @@ +import _ from "lodash"; +import { Session } from "meteor/session"; +import { Meteor } from "meteor/meteor"; +import { Tracker } from "meteor/tracker"; import { FlowRouter as Router } from "meteor/kadira:flow-router-ssr"; import { BlazeLayout } from "meteor/kadira:blaze-layout"; import { Reaction, Logger } from "/client/api"; import { Packages, Shops } from "/lib/collections"; import { MetaData } from "/lib/api/router/metadata"; -import { Session } from "meteor/session"; -import { Meteor } from "meteor/meteor"; -import { Tracker } from "meteor/tracker"; import Hooks from "./hooks"; @@ -27,6 +28,7 @@ Router.Hooks = Hooks; */ function checkRouterPermissions(context) { const routeName = context.route.name; + if (Reaction.hasPermission(routeName, Meteor.userId())) { if (context.unauthorized === true) { delete context.unauthorized; @@ -171,7 +173,7 @@ Router.initPackageRoutes = () => { // // index / home route // to overide layout, ie: home page templates - // set DEFAULT_LAYOUT, in config.js + // set INDEX_OPTIONS, in config.js // shop.route("/", { name: "index", @@ -256,7 +258,6 @@ Router.initPackageRoutes = () => { Router.initialize(); } catch (e) { Logger.error(e); - Router.reload(); } } }; diff --git a/client/modules/router/startup.js b/client/modules/router/startup.js index 58bf7c86c85..1b86468352d 100644 --- a/client/modules/router/startup.js +++ b/client/modules/router/startup.js @@ -12,4 +12,17 @@ Meteor.startup(function () { } } }); + + // + // we need to sometimes force + // router reload on login to get + // the entire layout to rerender + // we only do this when the routes table + // has already been generated (existing user) + // + Accounts.onLogin(() => { + if (Meteor.loggingIn() === false && Router._routes.length > 0) { + Router.reload(); + } + }); });