Skip to content

Commit

Permalink
logout and hasPermission updates (#1290)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
Aaron Judd authored Aug 15, 2016
1 parent 5135cbe commit da4a379
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 54 deletions.
4 changes: 0 additions & 4 deletions client/modules/accounts/templates/dropdown/dropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -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("/");
});
},

Expand Down
120 changes: 80 additions & 40 deletions client/modules/core/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
},

Expand Down
11 changes: 6 additions & 5 deletions client/modules/core/subscriptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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());
});
11 changes: 6 additions & 5 deletions client/modules/router/main.js
Original file line number Diff line number Diff line change
@@ -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";


Expand All @@ -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;
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -256,7 +258,6 @@ Router.initPackageRoutes = () => {
Router.initialize();
} catch (e) {
Logger.error(e);
Router.reload();
}
}
};
Expand Down
13 changes: 13 additions & 0 deletions client/modules/router/startup.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
});
});

0 comments on commit da4a379

Please sign in to comment.