saving my place so i dont have too many threads

This commit is contained in:
riley
2017-05-15 16:25:32 -06:00
parent e32ab99edf
commit 4d3788e4c9
8 changed files with 177 additions and 16 deletions
@@ -38,6 +38,8 @@ class LayoutContainer extends Component {
}
if (roleUtils.canAccessAdmin(user) && loggedIn) {
return <Layout handleLogout={handleLogout} toggleShortcutModal={toggleShortcutModal} {...this.props} />;
} else if (loggedIn) {
return <p>you do not have permission to see this page.</p>;
}
return <FullLoading />;
}
+28 -8
View File
@@ -1,10 +1,30 @@
import includes from 'lodash/includes';
import intersection from 'lodash/intersection';
export default {
canAccessConfig: (user) => includes(user.roles, 'ADMIN'),
canChangeRoles: user => includes(user.roles, 'ADMIN'),
hasStaffTag: user => includes(user.roles, 'ADMIN', 'MODERATOR', 'STAFF'),
canViewUserEmails: user => includes(user.roles, 'ADMIN'),
canModerate: user => includes(user.roles, 'ADMIN', 'MODERATOR'),
canAccessAdmin: user => includes(user.roles, 'ADMIN', 'MODERATOR')
const basicRoles = {
hasStaffTag: ['ADMIN', 'MODERATOR', 'STAFF']
};
const queryRoles = {
canAccessConfig: ['ADMIN', 'MODERATOR'],
canAccessAdmin: ['ADMIN', 'MODERATOR'],
canViewUserEmails: ['ADMIN']
};
const mutationRoles = {
canChangeRoles: ['ADMIN'],
canModerateComments: ['ADMIN', 'MODERATOR']
};
const roles = {...basicRoles, ...queryRoles, ...mutationRoles};
export const can = (user, perms) => {
for (let perm in perms) {
const role = roles[perm];
if (typeof role === 'undefined') {
continue;
}
let grant = intersection(role, user.roles).length > 0;
return grant;
}
return false;
};
+1 -1
View File
@@ -11,7 +11,7 @@ const Action = {
// This will load the user for the specific action. We'll limit this to the
// admin users only or the current logged in user.
user({user_id}, _, {loaders: {Users}, user}) {
if (user && (user.hasRole('ADMIN') || user_id === user.id)) {
if (user && (user.canViewOtherUsers() || user_id === user.id)) {
return Users.getByID.load(user_id);
}
}
+2 -7
View File
@@ -2,6 +2,7 @@ const mongoose = require('../services/mongoose');
const bcrypt = require('bcrypt');
const uuid = require('uuid');
const intersection = require('lodash/intersection');
const can = require('../perms');
// USER_ROLES is the array of roles that is permissible as a user role.
const USER_ROLES = [
@@ -269,13 +270,7 @@ const USER_GRAPH_OPERATIONS = [
* operation.
*/
UserSchema.method('can', function(...actions) {
if (actions.some((action) => USER_GRAPH_OPERATIONS.indexOf(action) === -1)) {
throw new Error(`invalid actions: ${actions}`);
}
if (this.status === 'BANNED') {
return false;
}
return can(this, null, actions);
if (actions.some((action) => action === 'mutation:setUserStatus' || action === 'mutation:suspendUser' || action === 'mutation:setCommentStatus') && !this.canSetUserStatus()) {
return false;
+48
View File
@@ -0,0 +1,48 @@
const root = require('./rootReducer');
const queries = require('./queryReducer');
const mutations = require('./mutationReducer');
const reducers = [
root.reducer,
queries.reducer,
mutations.reducer
];
const allPermissions = [...root.constants, ...queries.constants, ...mutations.constants];
const findGrant = (user, perms, context, initialState) => {
return perms.every(perm => {
for (let reducer in reducers) {
const grant = reducer(user, perm, context, initialState);
if (grant !== null && typeof grant !== 'undefined') {
return grant;
}
}
return false;
});
};
/**
* returns true, false, or null depending on whether the user has those permissions
* throws an error if you pass a permission that's not known to the system
* @param {User} user the user making the request for db operations
* @param {[type]} context [description]
* @param {String/Array} perms a string an array of strings which are the names of the permissions
* @return {Boolean}
*/
module.exports = (user, context, ...perms) => {
// make sure all the passed permissions are not typos
const missingPerms = perms.filter(perm => {
return typeof allPermissions[perm] === 'undefined';
});
if (missingPerms.length) {
throw new Error(`${missingPerms.join(' ')} are not valid permissions.`);
}
return findGrant(user, perms, context, null);
};
+48
View File
@@ -0,0 +1,48 @@
const intersection = require('lodash/intersection');
const check = (user, roles) => {
return !!intersection(roles, user.roles).length;
};
const CREATE_COMMENT = 'CREATE_COMMENT';
const CREATE_ACTION = 'CREATE_ACTION';
const DELETE_ACTION = 'DELETE_ACTION';
const EDIT_NAME = 'EDIT_NAME';
const SET_USER_STATUS = 'SET_USER_STATUS';
const SUSPEND_USER = 'SUSPEND_USER';
const SET_COMMENT_STATUS = 'SET_COMMENT_STATUS';
const ADD_COMMENT_TAG = 'ADD_COMMENT_TAG';
const REMOVE_COMMENT_TAG = 'REMOVE_COMMENT_TAG';
const UPDATE_CONFIG = 'UPDATE_CONFIG';
module.exports = {
constants: [
CREATE_COMMENT, CREATE_ACTION, DELETE_ACTION, EDIT_NAME, SET_USER_STATUS,
SUSPEND_USER, SET_COMMENT_STATUS, ADD_COMMENT_TAG, REMOVE_COMMENT_TAG, UPDATE_CONFIG
],
reducer: (user, perm, context, initialState) => {
switch (perm) {
case 'muation:createComment':
return true;
case 'mutation:createAction':
return true;
case 'mutation:deleteAction':
return true;
case 'mutation:editName':
return true;
case 'mutation:setUserStatus':
return check(user, ['ADMIN', 'MODERATOR']);
case 'mutation:suspendUser':
return check(user, ['ADMIN', 'MODERATOR']);
case 'mutation:setCommentStatus':
return check(user, ['ADMIN', 'MODERATOR']);
case 'mutation:addCommentTag':
return check(user, ['ADMIN', 'MODERATOR']);
case 'mutation:removeCommentTag':
return check(user, ['ADMIN', 'MODERATOR']);
case 'mutation:updateConfig':
return check(user, ['ADMIN', 'MODERATOR']);
default:
return initialState;
}
}
};
+36
View File
@@ -0,0 +1,36 @@
const intersection = require('lodash/intersection');
const check = (user, roles) => {
return !!intersection(roles, user.roles).length;
};
const SEARCH_ASSETS = 'SEARCH_ASSETS';
const SEARCH_OTHER_USERS = 'SEARCH_OTHER_USERS';
const SEARCH_ACTIONS = 'SEARCH_ACTIONS';
const SEARCH_NON_NULL_OR_ACCEPTED_COMMENTS = 'SEARCH_NON_NULL_OR_ACCEPTED_COMMENTS';
const SEARCH_OTHERS_COMMENTS = 'SEARCH_OTHERS_COMMENTS';
const SEARCH_COMMENT_METRICS = 'SEARCH_COMMENT_METRICS';
module.exports = {
constants: [
SEARCH_ASSETS, SEARCH_OTHER_USERS, SEARCH_ACTIONS, SEARCH_NON_NULL_OR_ACCEPTED_COMMENTS,
SEARCH_OTHERS_COMMENTS, SEARCH_COMMENT_METRICS
],
reducer: (perm, user, context, initialState) => {
switch (perm) {
case SEARCH_ASSETS:
return check(user, ['ADMIN', 'MODERATOR']);
case SEARCH_OTHER_USERS:
return check(user, ['ADMIN', 'MODERATOR']);
case SEARCH_ACTIONS:
return check(user, ['ADMIN', 'MODERATOR']);
case SEARCH_NON_NULL_OR_ACCEPTED_COMMENTS:
return check(user, ['ADMIN', 'MODERATOR']);
case SEARCH_OTHERS_COMMENTS:
return check(user, ['ADMIN', 'MODERATOR']);
case SEARCH_COMMENT_METRICS:
return check(user, ['ADMIN', 'MODERATOR']);
default:
return initialState;
}
}
};
+12
View File
@@ -0,0 +1,12 @@
module.exports = {
constants: [],
reducer: (perm, user, context, initialState) => {
// this runs before everything
if (user.status === 'BANNED') {
return false;
}
return initialState;
}
};