Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions frontend/src/hooks/UsePermissions.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export function useEditProjectAllowed(project) {
export function useEditTeamAllowed(team) {
const userDetails = useSelector((state) => state.auth.userDetails);
const organisations = useSelector((state) => state.auth.organisations);
const pmTeams = useSelector((state) => state.auth.pmTeams);
const tmTeams = useSelector((state) => state.auth.tmTeams);
const [isAllowed, setIsAllowed] = useState(false);

useEffect(() => {
Expand All @@ -39,17 +39,19 @@ export function useEditTeamAllowed(team) {
if (organisations && organisations.includes(team.organisation_id)) setIsAllowed(true);
// team managers can edit it
// verify from the redux store
if (pmTeams && pmTeams.includes(team.teamId)) setIsAllowed(true);
// and verify based on the team members list
// removed pm and use tm list
if (tmTeams && tmTeams?.includes(team?.teamId)) setIsAllowed(true);

if (team.members) {
// and verify based on the team members list
const managers = team.members
.filter((member) => member.active && member.function === 'MANAGER')
.map((member) => member.username);
if (userDetails.username && managers.includes(userDetails.username)) {
setIsAllowed(true);
}
}
}, [pmTeams, userDetails.role, userDetails.username, organisations, team]);
}, [userDetails.role, userDetails.username, organisations, team, tmTeams]);
return [isAllowed];
}

Expand Down
8 changes: 4 additions & 4 deletions frontend/src/hooks/tests/UseEditTeamPermissions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ describe('test edit team permissions based on manager permissions', () => {
};
it('team manager CAN edit it - verify based on redux store', () => {
act(() => {
store.dispatch({ type: 'SET_PM_TEAMS', teams: [1, 2, 3] });
store.dispatch({ type: 'SET_TM_TEAMS', teams: [1, 2, 3] });
});
const wrapper = ({ children }) => <Provider store={store}>{children}</Provider>;
const { result } = renderHook(() => useEditTeamAllowed(team), { wrapper });
Expand All @@ -48,7 +48,7 @@ describe('test edit team permissions based on manager permissions', () => {
it('team manager CAN edit it - verify based on team members', () => {
const userDetails = { username: 'test', role: 'MAPPER' };
act(() => {
store.dispatch({ type: 'SET_PM_TEAMS', teams: [] });
store.dispatch({ type: 'SET_TM_TEAMS', teams: [] });
store.dispatch({ type: 'SET_USER_DETAILS', userDetails: userDetails });
});
const wrapper = ({ children }) => <Provider store={store}>{children}</Provider>;
Expand All @@ -60,7 +60,7 @@ describe('test edit team permissions based on manager permissions', () => {
it('MAPPER can not edit it - verify based on team members', () => {
const userDetails = { username: 'another_user', role: 'MAPPER' };
act(() => {
store.dispatch({ type: 'SET_PM_TEAMS', teams: [] });
store.dispatch({ type: 'SET_TM_TEAMS', teams: [] });
store.dispatch({ type: 'SET_USER_DETAILS', userDetails: userDetails });
});
const wrapper = ({ children }) => <Provider store={store}>{children}</Provider>;
Expand All @@ -71,7 +71,7 @@ describe('test edit team permissions based on manager permissions', () => {

it('user that is NOT a team manager can not edit it', () => {
act(() => {
store.dispatch({ type: 'SET_PM_TEAMS', teams: [2, 3] });
store.dispatch({ type: 'SET_TM_TEAMS', teams: [2, 3] });
});
const wrapper = ({ children }) => <Provider store={store}>{children}</Provider>;
const { result } = renderHook(() => useEditTeamAllowed(team), { wrapper });
Expand Down
73 changes: 47 additions & 26 deletions frontend/src/store/actions/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const types = {
SET_OSM: 'SET_OSM',
SET_ORGANISATIONS: 'SET_ORGANISATIONS',
SET_PM_TEAMS: 'SET_PM_TEAMS',
SET_TM_TEAMS: 'SET_TM_TEAMS',
UPDATE_OSM_INFO: 'UPDATE_OSM_INFO',
GET_USER_DETAILS: 'GET_USER_DETAILS',
SET_TOKEN: 'SET_TOKEN',
Expand Down Expand Up @@ -75,6 +76,13 @@ export function updatePMsTeams(teams) {
};
}

export function updateTMsTeams(teams) {
return {
type: types.SET_TM_TEAMS,
teams: teams,
};
}

export function updateToken(token) {
return {
type: types.SET_TOKEN,
Expand Down Expand Up @@ -106,7 +114,7 @@ export const setAuthDetails = (username, token, osm_oauth_token) => (dispatch) =
// UPDATES OSM INFORMATION OF THE USER
export const setUserDetails =
(username, encodedToken, update = false) =>
(dispatch) => {
async (dispatch) => {
// only trigger the loader if this function is not being triggered to update the user information
if (!update) dispatch(setLoader(true));
fetchLocalJSONAPI(`users/${username}/openstreetmap/`, encodedToken)
Expand All @@ -115,31 +123,44 @@ export const setUserDetails =
console.log(error);
dispatch(setLoader(false));
});
// GET USER DETAILS
fetchLocalJSONAPI(`users/queries/${username}/`, encodedToken)
.then((userDetails) => {
dispatch(updateUserDetails(userDetails));
// GET USER ORGS INFO
fetchLocalJSONAPI(
`organisations/?omitManagerList=true&manager_user_id=${userDetails.id}`,
encodedToken,
)
.then((orgs) =>
dispatch(updateOrgsInfo(orgs.organisations.map((org) => org.organisationId))),
)
.catch((error) => dispatch(updateOrgsInfo([])));
fetchLocalJSONAPI(
`teams/?omitMemberList=true&team_role=PROJECT_MANAGER&member=${userDetails.id}`,
encodedToken,
)
.then((teams) => dispatch(updatePMsTeams(teams.teams.map((team) => team.teamId))))
.catch((error) => dispatch(updatePMsTeams([])));
dispatch(setLoader(false));
})
.catch((error) => {
if (error.message === 'InvalidToken') dispatch(logout());
dispatch(setLoader(false));
});

try {
const userDetails = await fetchLocalJSONAPI(`users/queries/${username}/`, encodedToken);

dispatch(updateUserDetails(userDetails));

const userId = userDetails.id;

const orgsPromise = fetchLocalJSONAPI(
`organisations/?omitManagerList=true&manager_user_id=${userId}`,
encodedToken,
)
.then((orgs) => dispatch(updateOrgsInfo(orgs.organisations.map((o) => o.organisationId))))
.catch(() => dispatch(updateOrgsInfo([])));

const pmsTeamsPromise = fetchLocalJSONAPI(
`teams/?omitMemberList=true&team_role=PROJECT_MANAGER&member=${userId}`,
encodedToken,
)
.then((teams) => dispatch(updatePMsTeams(teams.teams.map((t) => t.teamId))))
.catch(() => dispatch(updatePMsTeams([])));

const tmsTeamsPromise = fetchLocalJSONAPI(
`teams/?fullMemberList=false&manager=${userId}`,
encodedToken,
)
.then((teams) => dispatch(updateTMsTeams(teams.teams.map((t) => t.teamId))))
.catch(() => dispatch(updateTMsTeams([])));

// Run all parallel requests at once
await Promise.all([orgsPromise, pmsTeamsPromise, tmsTeamsPromise]);
} catch (error) {
if (error.message === 'InvalidToken') {
dispatch(logout());
}
} finally {
dispatch(setLoader(false));
}
};

export const getUserDetails = (state) => (dispatch) => {
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/store/reducers/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ export function authorizationReducer(state = initialState, action) {
case types.SET_PM_TEAMS: {
return { ...state, pmTeams: action.teams };
}
case types.SET_TM_TEAMS: {
return { ...state, tmTeams: action.teams };
}
case types.SET_TOKEN: {
return { ...state, token: action.token };
}
Expand Down