scratch-www/src/redux/session.js
2023-08-14 21:36:16 -04:00

173 lines
6.1 KiB
JavaScript

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');
const permissionsActions = require('./permissions.js');
const Types = keyMirror({
SET_SESSION: null,
SET_SESSION_ERROR: null,
SET_STATUS: null
});
const banGoodListPaths = [
'/ip_ban_appeal',
'/vpn_required',
'/accounts/banned-response',
'/accounts/bad-username',
'/community_guidelines',
'/privacy_policy',
'/terms_of_use'
];
module.exports.Status = keyMirror({
FETCHED: null,
NOT_FETCHED: null,
FETCHING: null
});
module.exports.getInitialState = () => ({
status: module.exports.Status.NOT_FETCHED,
session: {}
});
module.exports.sessionReducer = (state, action) => {
// Reducer for handling changes to session state
if (typeof state === 'undefined') {
state = module.exports.getInitialState();
}
switch (action.type) {
case Types.SET_SESSION:
return defaults({session: action.session}, state);
case Types.SET_STATUS:
return defaults({status: action.status}, state);
case Types.SET_SESSION_ERROR:
// TODO: do something with action.error
return state;
default:
return state;
}
};
module.exports.setSessionError = error => ({
type: Types.SET_SESSION_ERROR,
error: error
});
module.exports.setSession = session => ({
type: Types.SET_SESSION,
session: session
});
module.exports.setStatus = status => ({
type: Types.SET_STATUS,
status: status
});
const handleSessionResponse = (dispatch, body) => {
if (typeof body === 'undefined') return dispatch(module.exports.setSessionError('No session content'));
if (
body.vpn_required &&
banGoodListPaths.every(goodPath => window.location.pathname.indexOf(goodPath) === -1)
) {
window.location = '/vpn_required/';
return;
} else if (
body.banned &&
body.redirectURL &&
banGoodListPaths.every(goodPath => window.location.pathname.indexOf(goodPath) === -1)
) {
window.location = body.redirectURL;
return;
} else if (
body.user &&
body.user.banned &&
banGoodListPaths.every(goodPath => window.location.pathname.indexOf(goodPath) === -1)
) {
window.location = '/accounts/banned-response/';
return;
} else if (
body.flags &&
body.flags.must_complete_registration &&
window.location.pathname !== '/classes/complete_registration'
) {
window.location = '/classes/complete_registration';
return;
} else if (
body.flags &&
body.flags.must_reset_password &&
!body.flags.must_complete_registration &&
window.location.pathname !== '/classes/student_password_reset/'
) {
window.location = '/classes/student_password_reset/';
return;
}
dispatch(module.exports.setSession(body));
dispatch(module.exports.setStatus(module.exports.Status.FETCHED));
// get the permissions from the updated session
dispatch(permissionsActions.storePermissions(body.permissions));
if (typeof body.user !== 'undefined') {
dispatch(messageCountActions.getCount(body.user.username));
}
return;
};
module.exports.refreshSession = () => (dispatch => {
dispatch(module.exports.setStatus(module.exports.Status.FETCHING));
return new Promise((resolve, reject) => {
requestSession(resolve, reject);
}).then(body => {
handleSessionResponse(dispatch, body);
}, err => {
dispatch(module.exports.setSessionError(err));
});
});
module.exports.refreshSessionWithRetry = () => (dispatch => {
dispatch(module.exports.setStatus(module.exports.Status.FETCHING));
return new Promise((resolve, reject) => {
requestSessionWithRetry(resolve, reject, 4, 7500);
}).then(body => {
handleSessionResponse(dispatch, body);
}, err => {
dispatch(module.exports.setSessionError(err));
});
});
module.exports.updateMuteStatus = muteStatus => ((dispatch, getState) => {
const session = getState().session.session;
const newSession = {
...session,
permissions: {
...session.permissions,
mute_status: muteStatus
}
};
dispatch(module.exports.setSession(newSession));
});
// Selectors
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.selectUser = state => get(state, ['session', 'session', 'user'], false);
module.exports.selectIsSocial = state => get(state, ['session', 'session', 'permissions', 'social'], false);
module.exports.selectIsEducator = state => get(state, ['session', 'session', 'permissions', 'educator'], false);
module.exports.selectProjectCommentsGloballyEnabled = state =>
get(state, ['session', 'session', 'flags', 'project_comments_enabled'], false);
module.exports.selectStudioCommentsGloballyEnabled = state =>
get(state, ['session', 'session', 'flags', 'gallery_comments_enabled'], false);
module.exports.selectIsTotallyNormal = state =>
get(state, ['session', 'session', 'flags', 'everything_is_totally_normal'], false);
module.exports.selectMuteStatus = state => get(state, ['session', 'session', 'permissions', 'mute_status'],
{muteExpiresAt: 0, offenses: [], showWarning: false});
module.exports.selectIsMuted = state => (module.exports.selectMuteStatus(state).muteExpiresAt || 0) * 1000 > Date.now();
module.exports.selectHasFetchedSession = state => state.session.status === module.exports.Status.FETCHED;
// 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);