From dc241e1c6f3eebfcba5657a90960169eab5836f2 Mon Sep 17 00:00:00 2001 From: seotts Date: Fri, 17 Sep 2021 15:50:16 -0400 Subject: [PATCH 1/3] Accept studio "host" from api; use "host" in state --- src/redux/studio-permissions.js | 8 ++++---- src/redux/studio.js | 4 ++-- src/views/studio/lib/studio-member-actions.js | 2 +- .../studio/modals/transfer-host-confirmation.jsx | 2 +- .../studio/modals/transfer-host-selection.jsx | 2 +- src/views/studio/studio-member-tile.jsx | 2 +- test/helpers/state-fixtures.json | 2 +- test/unit/redux/studio-member-actions.test.js | 16 ++++++++-------- test/unit/redux/studio-permissions.test.js | 6 +++--- 9 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/redux/studio-permissions.js b/src/redux/studio-permissions.js index 3895d044c..e716e9dc6 100644 --- a/src/redux/studio-permissions.js +++ b/src/redux/studio-permissions.js @@ -3,7 +3,7 @@ const {selectUserId, selectIsAdmin, selectIsSocial, selectHasFetchedSession, selectStudioCommentsGloballyEnabled} = require('./session'); // Fine-grain selector helpers - not exported, use the higher level selectors below -const isHost = state => selectUserId(state) === state.studio.owner; +const isHost = state => selectUserId(state) === state.studio.host; const isCurator = state => state.studio.curator; const isManager = state => state.studio.manager || isHost(state); @@ -51,7 +51,7 @@ const selectCanRemoveCurator = (state, username) => { return false; }; const selectCanRemoveManager = (state, managerId) => - !selectIsMuted(state) && (selectIsAdmin(state) || isManager(state)) && managerId !== state.studio.owner; + !selectIsMuted(state) && (selectIsAdmin(state) || isManager(state)) && managerId !== state.studio.host; const selectCanPromoteCurators = state => !selectIsMuted(state) && isManager(state); const selectCanTransfer = (state, managerId) => { @@ -61,7 +61,7 @@ const selectCanTransfer = (state, managerId) => { if (state.studio.classroomId !== null) return false; if (selectIsMuted(state)) return false; // Muted users cannot transfer studios. if (state.studio.managers > 1) { // If there is more than one manager, - if (managerId === state.studio.owner) { // and the selected manager is the current owner/host, + if (managerId === state.studio.host) { // and the selected manager is the current owner/host, if (isHost(state)) return true; // Owner/host can transfer if (selectIsAdmin(state)) return true; // Admin can transfer } @@ -74,7 +74,7 @@ const selectCanRemoveProject = (state, creatorUsername, actorId) => { // Admins/managers can remove any projects if (isManager(state) || selectIsAdmin(state)) return true; - // Project owners can always remove their projects + // Project hosts can always remove their projects if (selectUsername(state) === creatorUsername) { return true; } diff --git a/src/redux/studio.js b/src/redux/studio.js index 0fa77c7ba..88bb213b7 100644 --- a/src/redux/studio.js +++ b/src/redux/studio.js @@ -25,7 +25,7 @@ const getInitialState = () => ({ image: '', followers: 0, managers: 0, - owner: null, + host: null, public: null, // BEWARE: classroomId is only loaded if the user is an educator or admin @@ -135,7 +135,7 @@ const getInfo = () => ((dispatch, getState) => { followers: body.stats.followers, managers: body.stats.managers, projectCount: body.stats.projects, - owner: body.owner, + host: body.host, public: body.public })); }); diff --git a/src/views/studio/lib/studio-member-actions.js b/src/views/studio/lib/studio-member-actions.js index 69edfd980..4399e20e7 100644 --- a/src/views/studio/lib/studio-member-actions.js +++ b/src/views/studio/lib/studio-member-actions.js @@ -218,7 +218,7 @@ const transferHost = (password, newHostName, newHostId) => }, (err, body, res) => { const error = normalizeError(err, body, res); if (error) return reject(error); - dispatch(setInfo({owner: newHostId})); + dispatch(setInfo({host: newHostId})); return resolve(); }); })); diff --git a/src/views/studio/modals/transfer-host-confirmation.jsx b/src/views/studio/modals/transfer-host-confirmation.jsx index b81dbabab..33d7502a9 100644 --- a/src/views/studio/modals/transfer-host-confirmation.jsx +++ b/src/views/studio/modals/transfer-host-confirmation.jsx @@ -202,7 +202,7 @@ TransferHostConfirmation.propTypes = { const connectedConfirmationStep = connect( state => ({ - hostId: state.studio.owner, + hostId: state.studio.host, ...managers.selector(state) }), { handleTransferHost: transferHost, diff --git a/src/views/studio/modals/transfer-host-selection.jsx b/src/views/studio/modals/transfer-host-selection.jsx index c1c37e24d..7e4e10f70 100644 --- a/src/views/studio/modals/transfer-host-selection.jsx +++ b/src/views/studio/modals/transfer-host-selection.jsx @@ -107,7 +107,7 @@ TransferHostSelection.propTypes = { export default connect( state => ({ - hostId: state.studio.owner, + hostId: state.studio.host, ...managers.selector(state) }), { diff --git a/src/views/studio/studio-member-tile.jsx b/src/views/studio/studio-member-tile.jsx index 6ab8fc75a..56b2e68db 100644 --- a/src/views/studio/studio-member-tile.jsx +++ b/src/views/studio/studio-member-tile.jsx @@ -164,7 +164,7 @@ const ManagerTile = connect( canPromote: false, canTransferHost: selectCanTransfer(state, ownProps.id) && selectStudioTransferLaunched(state), - isCreator: state.studio.owner === ownProps.id, + isCreator: state.studio.host === ownProps.id, studioTransferLaunched: selectStudioTransferLaunched(state) }), { diff --git a/test/helpers/state-fixtures.json b/test/helpers/state-fixtures.json index f028a369e..4e887841d 100644 --- a/test/helpers/state-fixtures.json +++ b/test/helpers/state-fixtures.json @@ -10,7 +10,7 @@ "invited": true }, "creator1": { - "owner": 1 + "host": 1 }, "openToAll": { "openToAll": true diff --git a/test/unit/redux/studio-member-actions.test.js b/test/unit/redux/studio-member-actions.test.js index a76da4849..657ff8c98 100644 --- a/test/unit/redux/studio-member-actions.test.js +++ b/test/unit/redux/studio-member-actions.test.js @@ -415,7 +415,7 @@ describe('transferHost', () => { studio: { id: 123123, managers: 3, - owner: 'oldHost' + host: 'oldHost' } }); }); @@ -427,7 +427,7 @@ describe('transferHost', () => { await store.dispatch(transferHost('password', 'newHostName', 'newHostId')); const state = store.getState(); expect(api.mock.calls[0][0].uri).toBe('/studios/123123/transfer/newHostName'); - expect(state.studio.owner).toBe('newHostId'); + expect(state.studio.host).toBe('newHostId'); }); test('error because of permissions issue', async () => { @@ -437,7 +437,7 @@ describe('transferHost', () => { await expect(store.dispatch(transferHost('password', 'newHostName', 'newHostId'))) .rejects.toBe(Errors.PERMISSION); const state = store.getState(); - expect(state.studio.owner).toBe('oldHost'); + expect(state.studio.host).toBe('oldHost'); }); test('error because of authorization issue', async () => { @@ -447,7 +447,7 @@ describe('transferHost', () => { await expect(store.dispatch(transferHost('password', 'newHostName', 'newHostId'))) .rejects.toBe(Errors.PERMISSION); const state = store.getState(); - expect(state.studio.owner).toBe('oldHost'); + expect(state.studio.host).toBe('oldHost'); }); test('error because of issue with new host', async () => { @@ -457,7 +457,7 @@ describe('transferHost', () => { await expect(store.dispatch(transferHost('password', 'newHostName', 'newHostId'))) .rejects.toBe(Errors.CANNOT_BE_HOST); const state = store.getState(); - expect(state.studio.owner).toBe('oldHost'); + expect(state.studio.host).toBe('oldHost'); }); test('error because of incorrect password', async () => { @@ -467,7 +467,7 @@ describe('transferHost', () => { await expect(store.dispatch(transferHost('password', 'newHostName', 'newHostId'))) .rejects.toBe(Errors.PASSWORD); const state = store.getState(); - expect(state.studio.owner).toBe('oldHost'); + expect(state.studio.host).toBe('oldHost'); }); test('error because of too many password attempts', async () => { @@ -477,7 +477,7 @@ describe('transferHost', () => { await expect(store.dispatch(transferHost('password', 'newHostName', 'newHostId'))) .rejects.toBe(Errors.PASSWORD_ATTEMPT_LIMIT); const state = store.getState(); - expect(state.studio.owner).toBe('oldHost'); + expect(state.studio.host).toBe('oldHost'); }); test('error because of rate limit', async () => { @@ -487,6 +487,6 @@ describe('transferHost', () => { await expect(store.dispatch(transferHost('password', 'newHostName', 'newHostId'))) .rejects.toBe(Errors.RATE_LIMIT); const state = store.getState(); - expect(state.studio.owner).toBe('oldHost'); + expect(state.studio.host).toBe('oldHost'); }); }); diff --git a/test/unit/redux/studio-permissions.test.js b/test/unit/redux/studio-permissions.test.js index 8753b953a..538ee6ade 100644 --- a/test/unit/redux/studio-permissions.test.js +++ b/test/unit/redux/studio-permissions.test.js @@ -411,7 +411,7 @@ describe('studio members', () => { ['muted logged in', false] ])('%s: %s', (role, expected) => { setStateByRole(role); - state.studio = {...state.studio, owner: 'the creator'}; + state.studio = {...state.studio, host: 'the creator'}; expect(selectCanRemoveManager(state, 'the creator')).toBe(expected); }); }); @@ -449,12 +449,12 @@ describe('studio members', () => { setStateByRole(role); state.studio = {...state.studio, managers: 2, classroomId: null}; // Only admin and host see the option to transfer the current host - expect(selectCanTransfer(state, state.studio.owner)).toBe(expected); + expect(selectCanTransfer(state, state.studio.host)).toBe(expected); // Nobody sees the option to transfer a manager who is not the host expect(selectCanTransfer(state, 123)).toBe(false); // Nobody can transfer classroom studios state.studio = {...state.studio, classroomId: 1}; - expect(selectCanTransfer(state, state.studio.owner)).toBe(false); + expect(selectCanTransfer(state, state.studio.host)).toBe(false); }); }); }); From c70b67cde5b8ca6f8280ddaa39438231d6ed9555 Mon Sep 17 00:00:00 2001 From: seotts Date: Mon, 20 Sep 2021 11:31:36 -0400 Subject: [PATCH 2/3] If studio response body has no host yet, use owner --- src/redux/studio.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/redux/studio.js b/src/redux/studio.js index 88bb213b7..a76cecc43 100644 --- a/src/redux/studio.js +++ b/src/redux/studio.js @@ -135,7 +135,7 @@ const getInfo = () => ((dispatch, getState) => { followers: body.stats.followers, managers: body.stats.managers, projectCount: body.stats.projects, - host: body.host, + host: body.host || body.owner, // TODO: Remove owner once api updated public: body.public })); }); From 2b1dfcda625650daf2869eeb83cea62051e2c935 Mon Sep 17 00:00:00 2001 From: seotts Date: Mon, 20 Sep 2021 12:09:47 -0400 Subject: [PATCH 3/3] Fix a couple of comments --- src/redux/studio-permissions.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/redux/studio-permissions.js b/src/redux/studio-permissions.js index e716e9dc6..a1fe04008 100644 --- a/src/redux/studio-permissions.js +++ b/src/redux/studio-permissions.js @@ -61,7 +61,7 @@ const selectCanTransfer = (state, managerId) => { if (state.studio.classroomId !== null) return false; if (selectIsMuted(state)) return false; // Muted users cannot transfer studios. if (state.studio.managers > 1) { // If there is more than one manager, - if (managerId === state.studio.host) { // and the selected manager is the current owner/host, + if (managerId === state.studio.host) { // and the selected manager is the current host, if (isHost(state)) return true; // Owner/host can transfer if (selectIsAdmin(state)) return true; // Admin can transfer } @@ -74,7 +74,7 @@ const selectCanRemoveProject = (state, creatorUsername, actorId) => { // Admins/managers can remove any projects if (isManager(state) || selectIsAdmin(state)) return true; - // Project hosts can always remove their projects + // Project owners can always remove their projects if (selectUsername(state) === creatorUsername) { return true; }