mirror of
https://github.com/scratchfoundation/scratch-www.git
synced 2025-02-17 00:21:20 -05:00
Use lodash.get to simplify permissions, move test data into fixtures for better testing
This commit is contained in:
parent
8144b0c2e1
commit
cd8ae4b197
10 changed files with 130 additions and 102 deletions
5
package-lock.json
generated
5
package-lock.json
generated
|
@ -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",
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
"express": "4.16.1",
|
||||
"express-http-proxy": "1.1.0",
|
||||
"lodash.defaults": "4.0.1",
|
||||
"lodash.get": "^4.4.2",
|
||||
"react-helmet": "5.2.0",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"scratch-parser": "^5.0.0",
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
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(
|
||||
|
|
51
test/helpers/state-fixtures.json
Normal file
51
test/helpers/state-fixtures.json
Normal file
|
@ -0,0 +1,51 @@
|
|||
{
|
||||
"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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
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);
|
||||
});
|
||||
});
|
|
@ -1,23 +1,46 @@
|
|||
import {
|
||||
getInitialState, selectUserId, sessionReducer, setSession
|
||||
getInitialState, selectIsAdmin, selectIsSocial, selectUserId,
|
||||
selectUsername, selectToken, sessionReducer, setSession
|
||||
} from '../../../src/redux/session';
|
||||
|
||||
describe('session selectors', () => {
|
||||
describe('selectUserId', () => {
|
||||
import {sessions} from '../../helpers/state-fixtures.json';
|
||||
|
||||
test('is initially undefined', () => {
|
||||
const state = {session: getInitialState()};
|
||||
expect(selectUserId(state)).toBeUndefined();
|
||||
});
|
||||
test('returns the user id when it is available', () => {
|
||||
describe('session selectors', () => {
|
||||
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');
|
||||
});
|
||||
|
||||
describe('permissions', () => {
|
||||
test('selectIsAdmin', () => {
|
||||
let state = {session: getInitialState()};
|
||||
const newSession = {
|
||||
user: {
|
||||
id: 123
|
||||
}
|
||||
};
|
||||
const newSession = sessions.user1Admin.session;
|
||||
state.session = sessionReducer(state.session, setSession(newSession));
|
||||
expect(selectUserId(state)).toBe(123);
|
||||
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('selectIsSocial', () => {
|
||||
let state = {session: getInitialState()};
|
||||
const newSession = sessions.user1Social.session;
|
||||
state.session = sessionReducer(state.session, setSession(newSession));
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue