mirror of
https://github.com/scratchfoundation/scratch-www.git
synced 2024-11-27 09:35:56 -05:00
Add studio selector and tests
This commit is contained in:
parent
f03fbb503b
commit
99195d6df3
2 changed files with 131 additions and 2 deletions
|
@ -3,6 +3,9 @@ const keyMirror = require('keymirror');
|
||||||
const api = require('../lib/api');
|
const api = require('../lib/api');
|
||||||
const log = require('../lib/log');
|
const log = require('../lib/log');
|
||||||
|
|
||||||
|
const {selectUserId} = require('./session');
|
||||||
|
const {selectIsAdmin, selectIsSocial} = require('./permissions');
|
||||||
|
|
||||||
const Status = keyMirror({
|
const Status = keyMirror({
|
||||||
FETCHED: null,
|
FETCHED: null,
|
||||||
NOT_FETCHED: null,
|
NOT_FETCHED: null,
|
||||||
|
@ -18,6 +21,7 @@ const getInitialState = () => ({
|
||||||
commentingAllowed: false,
|
commentingAllowed: false,
|
||||||
thumbnail: '',
|
thumbnail: '',
|
||||||
followers: 0,
|
followers: 0,
|
||||||
|
owner: null,
|
||||||
|
|
||||||
rolesStatus: Status.NOT_FETCHED,
|
rolesStatus: Status.NOT_FETCHED,
|
||||||
manager: false,
|
manager: false,
|
||||||
|
@ -55,6 +59,8 @@ const studioReducer = (state, action) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Action Creators
|
||||||
|
|
||||||
const setFetchStatus = (fetchType, fetchStatus, error) => ({
|
const setFetchStatus = (fetchType, fetchStatus, error) => ({
|
||||||
type: 'SET_FETCH_STATUS',
|
type: 'SET_FETCH_STATUS',
|
||||||
fetchType,
|
fetchType,
|
||||||
|
@ -72,6 +78,8 @@ const setRoles = roles => ({
|
||||||
roles: roles
|
roles: roles
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Thunks
|
||||||
|
|
||||||
const getInfo = studioId => (dispatch => {
|
const getInfo = studioId => (dispatch => {
|
||||||
dispatch(setFetchStatus('infoStatus', Status.FETCHING));
|
dispatch(setFetchStatus('infoStatus', Status.FETCHING));
|
||||||
api({uri: `/studios/${studioId}`}, (err, body, res) => {
|
api({uri: `/studios/${studioId}`}, (err, body, res) => {
|
||||||
|
@ -86,7 +94,8 @@ const getInfo = studioId => (dispatch => {
|
||||||
openToAll: body.open_to_all,
|
openToAll: body.open_to_all,
|
||||||
commentingAllowed: body.commenting_allowed,
|
commentingAllowed: body.commenting_allowed,
|
||||||
updated: new Date(body.history.modified),
|
updated: new Date(body.history.modified),
|
||||||
followers: body.stats.followers
|
followers: body.stats.followers,
|
||||||
|
owner: body.owner
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -111,10 +120,32 @@ 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 isCurator = state => state.studio.curator;
|
||||||
|
const isManager = state => state.studio.manager || isCreator(state);
|
||||||
|
|
||||||
|
// Action-based permissions selectors
|
||||||
|
const selectCanEditInfo = state => selectIsAdmin(state) || isManager(state);
|
||||||
|
const selectCanAddProjects = state =>
|
||||||
|
isManager(state) ||
|
||||||
|
isCurator(state) ||
|
||||||
|
(selectIsSocial(state) && state.studio.openToAll);
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getInitialState,
|
getInitialState,
|
||||||
studioReducer,
|
studioReducer,
|
||||||
Status,
|
Status,
|
||||||
|
|
||||||
|
// Thunks
|
||||||
getInfo,
|
getInfo,
|
||||||
getRoles
|
getRoles,
|
||||||
|
|
||||||
|
// Selectors
|
||||||
|
selectCanEditInfo,
|
||||||
|
selectCanAddProjects
|
||||||
};
|
};
|
||||||
|
|
98
test/unit/redux/studio.test.js
Normal file
98
test/unit/redux/studio.test.js
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
import {
|
||||||
|
getInitialState as getInitialStudioState,
|
||||||
|
selectCanEditInfo,
|
||||||
|
selectCanAddProjects
|
||||||
|
} from '../../../src/redux/studio';
|
||||||
|
|
||||||
|
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}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('studio selectors', () => {
|
||||||
|
let state;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
state = {
|
||||||
|
permissions: {},
|
||||||
|
session: getInitialSessionState(),
|
||||||
|
studio: getInitialStudioState()
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('studio info', () => {
|
||||||
|
test('is editable by admin', () => {
|
||||||
|
state.permissions = fixtures.permissions.isAdmin;
|
||||||
|
expect(selectCanEditInfo(state)).toBe(true);
|
||||||
|
});
|
||||||
|
test('is editable by managers and studio creator', () => {
|
||||||
|
state.studio = fixtures.studio.isManager;
|
||||||
|
expect(selectCanEditInfo(state)).toBe(true);
|
||||||
|
|
||||||
|
state.studio = fixtures.studio.creator1;
|
||||||
|
state.session = fixtures.session.user1;
|
||||||
|
expect(selectCanEditInfo(state)).toBe(true);
|
||||||
|
});
|
||||||
|
test('is not editable by curators', () => {
|
||||||
|
state.studio = fixtures.studio.isCurator;
|
||||||
|
state.session = fixtures.session.user1;
|
||||||
|
expect(selectCanEditInfo(state)).toBe(false);
|
||||||
|
});
|
||||||
|
test('is not editable by other logged in users', () => {
|
||||||
|
state.session = fixtures.session.user1;
|
||||||
|
expect(selectCanEditInfo(state)).toBe(false);
|
||||||
|
});
|
||||||
|
test('is not editable by logged out users', () => {
|
||||||
|
expect(selectCanEditInfo(state)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('studio projects', () => {
|
||||||
|
test('cannot be added by admin', () => {
|
||||||
|
state.permissions = fixtures.permissions.isAdmin;
|
||||||
|
state.session = fixtures.session.user1;
|
||||||
|
expect(selectCanAddProjects(state)).toBe(false);
|
||||||
|
});
|
||||||
|
test('can be added by managers and studio creator', () => {
|
||||||
|
state.studio = fixtures.studio.isManager;
|
||||||
|
expect(selectCanAddProjects(state)).toBe(true);
|
||||||
|
|
||||||
|
state.studio = fixtures.studio.creator1;
|
||||||
|
state.session = fixtures.session.user1;
|
||||||
|
expect(selectCanAddProjects(state)).toBe(true);
|
||||||
|
});
|
||||||
|
test('can be added by curators', () => {
|
||||||
|
state.studio = fixtures.studio.isCurator;
|
||||||
|
state.session = fixtures.session.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;
|
||||||
|
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;
|
||||||
|
expect(selectCanAddProjects(state)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in a new issue