mirror of https://gitee.com/answerdev/answer.git
289 lines
7.0 KiB
TypeScript
289 lines
7.0 KiB
TypeScript
import { getLoggedUserInfo, getAppSettings } from '@/services';
|
|
import {
|
|
loggedUserInfoStore,
|
|
siteInfoStore,
|
|
interfaceStore,
|
|
brandingStore,
|
|
loginSettingStore,
|
|
customizeStore,
|
|
themeSettingStore,
|
|
seoSettingStore,
|
|
loginToContinueStore,
|
|
} from '@/stores';
|
|
import { RouteAlias } from '@/router/alias';
|
|
import { LOGGED_USER_STORAGE_KEY } from '@/common/constants';
|
|
|
|
import Storage from './storage';
|
|
import { setupAppLanguage, setupAppTimeZone } from './localize';
|
|
import { floppyNavigation } from './floppyNavigation';
|
|
|
|
type TLoginState = {
|
|
isLogged: boolean;
|
|
isNotActivated: boolean;
|
|
isActivated: boolean;
|
|
isForbidden: boolean;
|
|
isNormal: boolean;
|
|
isAdmin: boolean;
|
|
};
|
|
|
|
export type TGuardResult = {
|
|
ok: boolean;
|
|
redirect?: string;
|
|
};
|
|
export type TGuardFunc = () => TGuardResult;
|
|
|
|
export const deriveLoginState = (): TLoginState => {
|
|
const ls: TLoginState = {
|
|
isLogged: false,
|
|
isNotActivated: false,
|
|
isActivated: false,
|
|
isForbidden: false,
|
|
isNormal: false,
|
|
isAdmin: false,
|
|
};
|
|
const { user } = loggedUserInfoStore.getState();
|
|
if (user.access_token) {
|
|
ls.isLogged = true;
|
|
}
|
|
if (ls.isLogged && user.mail_status === 1) {
|
|
ls.isActivated = true;
|
|
}
|
|
if (ls.isLogged && user.mail_status === 2) {
|
|
ls.isNotActivated = true;
|
|
}
|
|
if (ls.isLogged && user.status === 'forbidden') {
|
|
ls.isForbidden = true;
|
|
}
|
|
if (ls.isActivated && !ls.isForbidden) {
|
|
ls.isNormal = true;
|
|
}
|
|
if (ls.isNormal && user.is_admin === true) {
|
|
ls.isAdmin = true;
|
|
}
|
|
return ls;
|
|
};
|
|
|
|
export const isIgnoredPath = (ignoredPath: string | string[]) => {
|
|
if (!Array.isArray(ignoredPath)) {
|
|
ignoredPath = [ignoredPath];
|
|
}
|
|
const { pathname } = window.location;
|
|
const matchingPath = ignoredPath.find((_) => {
|
|
return pathname.indexOf(_) !== -1;
|
|
});
|
|
return !!matchingPath;
|
|
};
|
|
|
|
let pullLock = false;
|
|
let dedupeTimestamp = 0;
|
|
export const pullLoggedUser = async (forceRePull = false) => {
|
|
// only pull once if not force re-pull
|
|
if (pullLock && !forceRePull) {
|
|
return;
|
|
}
|
|
// dedupe pull requests in this time span in 10 seconds
|
|
if (Date.now() - dedupeTimestamp < 1000 * 10) {
|
|
return;
|
|
}
|
|
dedupeTimestamp = Date.now();
|
|
const loggedUserInfo = await getLoggedUserInfo().catch((ex) => {
|
|
dedupeTimestamp = 0;
|
|
if (!deriveLoginState().isLogged) {
|
|
// load fallback userInfo from local storage
|
|
const storageLoggedUserInfo = Storage.get(LOGGED_USER_STORAGE_KEY);
|
|
if (storageLoggedUserInfo) {
|
|
loggedUserInfoStore.getState().update(storageLoggedUserInfo);
|
|
}
|
|
}
|
|
console.error(ex);
|
|
});
|
|
if (loggedUserInfo) {
|
|
pullLock = true;
|
|
loggedUserInfoStore.getState().update(loggedUserInfo);
|
|
}
|
|
};
|
|
|
|
export const logged = () => {
|
|
const gr: TGuardResult = { ok: true };
|
|
const us = deriveLoginState();
|
|
if (!us.isLogged) {
|
|
gr.ok = false;
|
|
gr.redirect = RouteAlias.login;
|
|
}
|
|
return gr;
|
|
};
|
|
|
|
export const notLogged = () => {
|
|
const gr: TGuardResult = { ok: true };
|
|
const us = deriveLoginState();
|
|
if (us.isLogged) {
|
|
gr.ok = false;
|
|
gr.redirect = RouteAlias.home;
|
|
}
|
|
return gr;
|
|
};
|
|
|
|
export const notActivated = () => {
|
|
const gr: TGuardResult = { ok: true };
|
|
const us = deriveLoginState();
|
|
if (us.isActivated) {
|
|
gr.ok = false;
|
|
gr.redirect = RouteAlias.home;
|
|
}
|
|
return gr;
|
|
};
|
|
|
|
export const activated = () => {
|
|
const gr = logged();
|
|
const us = deriveLoginState();
|
|
if (us.isNotActivated) {
|
|
gr.ok = false;
|
|
gr.redirect = RouteAlias.activation;
|
|
}
|
|
return gr;
|
|
};
|
|
|
|
export const forbidden = () => {
|
|
const gr: TGuardResult = { ok: true };
|
|
const us = deriveLoginState();
|
|
if (gr.ok && !us.isForbidden) {
|
|
gr.ok = false;
|
|
gr.redirect = RouteAlias.home;
|
|
}
|
|
return gr;
|
|
};
|
|
|
|
export const notForbidden = () => {
|
|
const gr: TGuardResult = { ok: true };
|
|
const us = deriveLoginState();
|
|
if (us.isForbidden) {
|
|
gr.ok = false;
|
|
gr.redirect = RouteAlias.suspended;
|
|
}
|
|
return gr;
|
|
};
|
|
|
|
export const admin = () => {
|
|
const gr = logged();
|
|
const us = deriveLoginState();
|
|
if (gr.ok && !us.isAdmin) {
|
|
gr.ok = false;
|
|
gr.redirect = RouteAlias.home;
|
|
}
|
|
return gr;
|
|
};
|
|
|
|
export const allowNewRegistration = () => {
|
|
const gr: TGuardResult = { ok: true };
|
|
const loginSetting = loginSettingStore.getState().login;
|
|
if (!loginSetting.allow_new_registrations) {
|
|
gr.ok = false;
|
|
gr.redirect = RouteAlias.home;
|
|
}
|
|
return gr;
|
|
};
|
|
|
|
export const shouldLoginRequired = () => {
|
|
const gr: TGuardResult = { ok: true };
|
|
const loginSetting = loginSettingStore.getState().login;
|
|
if (!loginSetting.login_required) {
|
|
return gr;
|
|
}
|
|
const us = deriveLoginState();
|
|
if (us.isLogged) {
|
|
return gr;
|
|
}
|
|
if (
|
|
isIgnoredPath([
|
|
RouteAlias.login,
|
|
RouteAlias.register,
|
|
'/users/account-recovery',
|
|
'users/change-email',
|
|
'users/password-reset',
|
|
'users/account-activation',
|
|
'users/account-activation/success',
|
|
'/users/account-activation/failed',
|
|
'/users/confirm-new-email',
|
|
])
|
|
) {
|
|
return gr;
|
|
}
|
|
gr.ok = false;
|
|
gr.redirect = RouteAlias.login;
|
|
return gr;
|
|
};
|
|
|
|
/**
|
|
* try user was logged and all state ok
|
|
* @param canNavigate // if true, will navigate to login page if not logged
|
|
*/
|
|
export const tryNormalLogged = (canNavigate: boolean = false) => {
|
|
const us = deriveLoginState();
|
|
|
|
if (us.isNormal) {
|
|
return true;
|
|
}
|
|
// must assert logged state first and return
|
|
if (!us.isLogged) {
|
|
if (canNavigate) {
|
|
loginToContinueStore.getState().update({ show: true });
|
|
}
|
|
return false;
|
|
}
|
|
if (us.isNotActivated) {
|
|
floppyNavigation.navigate(RouteAlias.activation, () => {
|
|
window.location.href = RouteAlias.activation;
|
|
});
|
|
} else if (us.isForbidden) {
|
|
floppyNavigation.navigate(RouteAlias.suspended, () => {
|
|
window.location.replace(RouteAlias.suspended);
|
|
});
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
export const tryLoggedAndActivated = () => {
|
|
const gr: TGuardResult = { ok: true };
|
|
const us = deriveLoginState();
|
|
|
|
if (!us.isLogged || !us.isActivated) {
|
|
gr.ok = false;
|
|
}
|
|
return gr;
|
|
};
|
|
|
|
/**
|
|
* Initialize app configuration
|
|
*/
|
|
let appInitialized = false;
|
|
export const initAppSettingsStore = async () => {
|
|
const appSettings = await getAppSettings();
|
|
if (appSettings) {
|
|
siteInfoStore.getState().update(appSettings.general);
|
|
siteInfoStore.getState().updateVersion(appSettings.version);
|
|
interfaceStore.getState().update(appSettings.interface);
|
|
brandingStore.getState().update(appSettings.branding);
|
|
loginSettingStore.getState().update(appSettings.login);
|
|
customizeStore.getState().update(appSettings.custom_css_html);
|
|
themeSettingStore.getState().update(appSettings.theme);
|
|
seoSettingStore.getState().update(appSettings.site_seo);
|
|
}
|
|
};
|
|
|
|
export const setupApp = async () => {
|
|
if (appInitialized) {
|
|
return;
|
|
}
|
|
/**
|
|
* WARN:
|
|
* 1. must pre init logged user info for router guard
|
|
* 2. must pre init app settings for app render
|
|
*/
|
|
// TODO: optimize `initAppSettingsStore` by server render
|
|
await Promise.allSettled([pullLoggedUser(), initAppSettingsStore()]);
|
|
setupAppLanguage();
|
|
setupAppTimeZone();
|
|
appInitialized = true;
|
|
};
|