Commit cd8ae4b1 authored by Paul Kaplan's avatar Paul Kaplan

Use lodash.get to simplify permissions, move test data into fixtures for better testing

parent 8144b0c2
......@@ -14071,6 +14071,11 @@
"integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=",
"dev": true
},
"lodash.get": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
},
"lodash.isarguments": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
......@@ -54,7 +54,3 @@ module.exports.setPermissionsError = error => ({
type: Types.SET_PERMISSIONS_ERROR,
error: error
});
// Selectors - Being extra cautious with stict truthiness
module.exports.selectIsAdmin = state => state.permissions.admin === true;
module.exports.selectIsSocial = state => state.permissions.social === true;
const keyMirror = require('keymirror');
const defaults = require('lodash.defaults');
const get = require('lodash.get');
const {requestSession, requestSessionWithRetry} = require('../lib/session');
const messageCountActions = require('./message-count.js');
......@@ -120,5 +121,11 @@ module.exports.refreshSessionWithRetry = () => (dispatch => {
});
// Selectors
module.exports.selectUserId = state =>
state.session.session.user && state.session.session.user.id;
module.exports.selectIsLoggedIn = state => get(state, ['session', 'session', 'user'], false);
module.exports.selectUsername = state => get(state, ['session', 'session', 'user', 'username'], null);
module.exports.selectToken = state => get(state, ['session', 'session', 'user', 'token'], null);
module.exports.selectIsAdmin = state => get(state, ['session', 'session', 'permissions', 'admin'], false);
module.exports.selectIsSocial = state => get(state, ['session', 'session', 'permissions', 'social'], false);
// NB logged out user id as NaN so that it can never be used in equality testing since NaN !== NaN
module.exports.selectUserId = state => get(state, ['session', 'session', 'user', 'id'], NaN);
......@@ -3,8 +3,7 @@ const keyMirror = require('keymirror');
const api = require('../lib/api');
const log = require('../lib/log');
const {selectUserId} = require('./session');
const {selectIsAdmin, selectIsSocial} = require('./permissions');
const {selectUserId, selectIsAdmin, selectIsSocial} = require('./session');
const Status = keyMirror({
FETCHED: null,
......@@ -123,9 +122,7 @@ const getRoles = (studioId, username, token) => (dispatch => {
// Selectors
// Fine-grain selector helpers - not exported, use the higher level selectors below
const isCreator = state =>
state.studio.owner !== null && // Never try matching if owner has not been set
selectUserId(state) === state.studio.owner;
const isCreator = state => selectUserId(state) === state.studio.owner;
const isCurator = state => state.studio.curator;
const isManager = state => state.studio.manager || isCreator(state);
......
......@@ -3,6 +3,8 @@ import PropTypes from 'prop-types';
import {useParams} from 'react-router-dom';
import {connect} from 'react-redux';
import Debug from './debug.jsx';
import {selectUsername, selectToken} from '../../redux/session';
import {getInfo, getRoles, selectCanEditInfo} from '../../redux/studio';
const StudioInfo = ({username, studio, token, canEditInfo, onLoadInfo, onLoadRoles}) => {
......@@ -43,15 +45,12 @@ StudioInfo.propTypes = {
};
export default connect(
state => {
const user = state.session.session.user;
return {
studio: state.studio,
username: user && user.username,
token: user && user.token,
canEditInfo: selectCanEditInfo(state)
};
},
state => ({
studio: state.studio,
username: selectUsername(state),
token: selectToken(state),
canEditInfo: selectCanEditInfo(state)
}),
dispatch => ({
onLoadInfo: studioId => dispatch(getInfo(studioId)),
onLoadRoles: (studioId, username, token) => dispatch(
......
{
"studios": {
"isManager": {
"manager": true
},
"isCurator": {
"curator": true
},
"creator1": {
"owner": 1
},
"openToAll": {
"openToAll": true
}
},
"sessions": {
"user1Admin": {
"session": {
"user": {
"id": 1
},
"permissions": {
"admin": true
}
}
},
"user1Social": {
"session": {
"user": {
"id": 1
},
"permissions": {
"social": true
}
}
},
"user1": {
"session": {
"user": {
"id": 1,
"username": "user1-username",
"token": "user1-token"
},
"permissions": {
"admin": false,
"social": false
}
}
}
}
}
\ No newline at end of file
import {
selectIsAdmin, selectIsSocial, permissionsReducer, setPermissions
} from '../../../src/redux/permissions';
describe('permission selectors', () => {
test('all permissions are initially false', () => {
const state = {
permissions: {}
};
expect(selectIsAdmin(state)).toBe(false);
expect(selectIsSocial(state)).toBe(false);
});
test('selectIsAdmin', () => {
let state = {
permissions: {}
};
const newPermissions = {admin: true};
state.permissions = permissionsReducer(state.session, setPermissions(newPermissions));
expect(selectIsAdmin(state)).toBe(true);
});
test('isSocial', () => {
let state = {
permissions: {}
};
const newPermissions = {social: true};
state.permissions = permissionsReducer(state.session, setPermissions(newPermissions));
expect(selectIsSocial(state)).toBe(true);
});
});
import {
getInitialState, selectUserId, sessionReducer, setSession
getInitialState, selectIsAdmin, selectIsSocial, selectUserId,
selectUsername, selectToken, sessionReducer, setSession
} from '../../../src/redux/session';
import {sessions} from '../../helpers/state-fixtures.json';
describe('session selectors', () => {
describe('selectUserId', () => {
test('logged out', () => {
const state = {session: getInitialState()};
expect(selectIsAdmin(state)).toBe(false);
expect(selectIsSocial(state)).toBe(false);
expect(selectUserId(state)).toBeNaN();
expect(selectToken(state)).toBeNull();
expect(selectUsername(state)).toBeNull();
});
test('user data', () => {
let state = {session: getInitialState()};
const newSession = sessions.user1.session;
state.session = sessionReducer(state.session, setSession(newSession));
expect(selectUserId(state)).toBe(1);
expect(selectUsername(state)).toBe('user1-username');
expect(selectToken(state)).toBe('user1-token');
});
test('is initially undefined', () => {
const state = {session: getInitialState()};
expect(selectUserId(state)).toBeUndefined();
describe('permissions', () => {
test('selectIsAdmin', () => {
let state = {session: getInitialState()};
const newSession = sessions.user1Admin.session;
state.session = sessionReducer(state.session, setSession(newSession));
expect(selectIsAdmin(state)).toBe(true);
// Confirm that admin/social are totally separate and just read directly from the state
expect(selectIsSocial(state)).toBe(false);
});
test('returns the user id when it is available', () => {
test('selectIsSocial', () => {
let state = {session: getInitialState()};
const newSession = {
user: {
id: 123
}
};
const newSession = sessions.user1Social.session;
state.session = sessionReducer(state.session, setSession(newSession));
expect(selectUserId(state)).toBe(123);
expect(selectIsSocial(state)).toBe(true);
// Confirm that admin/social are totally separate and just read directly from the state
expect(selectIsAdmin(state)).toBe(false);
});
});
});
......@@ -8,30 +8,13 @@ import {
getInitialState as getInitialSessionState
} from '../../../src/redux/session';
const fixtures = {
permissions: {
isAdmin: {admin: true},
isSocial: {social: true}
},
studio: {
isManager: {manager: true},
isCurator: {curator: true},
creator1: {owner: 1},
openToAll: {openToAll: true}
},
session: {
user1: {
session: {user: {id: 1}}
}
}
};
import {sessions, studios} from '../../helpers/state-fixtures.json';
describe('studio selectors', () => {
let state;
beforeEach(() => {
state = {
permissions: {},
session: getInitialSessionState(),
studio: getInitialStudioState()
};
......@@ -39,24 +22,24 @@ describe('studio selectors', () => {
describe('studio info', () => {
test('is editable by admin', () => {
state.permissions = fixtures.permissions.isAdmin;
state.session = sessions.user1Admin;
expect(selectCanEditInfo(state)).toBe(true);
});
test('is editable by managers and studio creator', () => {
state.studio = fixtures.studio.isManager;
state.studio = studios.isManager;
expect(selectCanEditInfo(state)).toBe(true);
state.studio = fixtures.studio.creator1;
state.session = fixtures.session.user1;
state.studio = studios.creator1;
state.session = sessions.user1;
expect(selectCanEditInfo(state)).toBe(true);
});
test('is not editable by curators', () => {
state.studio = fixtures.studio.isCurator;
state.session = fixtures.session.user1;
state.studio = studios.isCurator;
state.session = sessions.user1;
expect(selectCanEditInfo(state)).toBe(false);
});
test('is not editable by other logged in users', () => {
state.session = fixtures.session.user1;
state.session = sessions.user1;
expect(selectCanEditInfo(state)).toBe(false);
});
test('is not editable by logged out users', () => {
......@@ -66,32 +49,29 @@ describe('studio selectors', () => {
describe('studio projects', () => {
test('cannot be added by admin', () => {
state.permissions = fixtures.permissions.isAdmin;
state.session = fixtures.session.user1;
state.session = sessions.user1Admin;
expect(selectCanAddProjects(state)).toBe(false);
});
test('can be added by managers and studio creator', () => {
state.studio = fixtures.studio.isManager;
state.studio = studios.isManager;
expect(selectCanAddProjects(state)).toBe(true);
state.studio = fixtures.studio.creator1;
state.session = fixtures.session.user1;
state.studio = studios.creator1;
state.session = sessions.user1;
expect(selectCanAddProjects(state)).toBe(true);
});
test('can be added by curators', () => {
state.studio = fixtures.studio.isCurator;
state.session = fixtures.session.user1;
state.studio = studios.isCurator;
state.session = sessions.user1;
expect(selectCanAddProjects(state)).toBe(true);
});
test('can be added by social users if studio is openToAll', () => {
state.studio = fixtures.studio.openToAll;
state.permissions = fixtures.permissions.isSocial;
state.session = fixtures.session.user1;
state.studio = studios.openToAll;
state.session = sessions.user1Social;
expect(selectCanAddProjects(state)).toBe(true);
});
test('cannot be added by social users if not openToAll', () => {
state.permissions = fixtures.permissions.isSocial;
state.session = fixtures.session.user1;
state.session = sessions.user1Social;
expect(selectCanAddProjects(state)).toBe(false);
});
});
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment