fix: Allow users to login even if they have access to more than 15 accounts (#4475)
This commit is contained in:
parent
80e5d6d7a0
commit
0319b78eac
19 changed files with 368 additions and 350 deletions
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="app" class="app-wrapper app-root">
|
<div v-if="!authUIFlags.isFetching" id="app" class="app-wrapper app-root">
|
||||||
<update-banner :latest-chatwoot-version="latestChatwootVersion" />
|
<update-banner :latest-chatwoot-version="latestChatwootVersion" />
|
||||||
<transition name="fade" mode="out-in">
|
<transition name="fade" mode="out-in">
|
||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
|
@ -11,21 +11,28 @@
|
||||||
<woot-snackbar-box />
|
<woot-snackbar-box />
|
||||||
<network-notification />
|
<network-notification />
|
||||||
</div>
|
</div>
|
||||||
|
<loading-state v-else />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { accountIdFromPathname } from './helper/URLHelper';
|
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import AddAccountModal from '../dashboard/components/layout/sidebarComponents/AddAccountModal';
|
import AddAccountModal from '../dashboard/components/layout/sidebarComponents/AddAccountModal';
|
||||||
|
import LoadingState from './components/widgets/LoadingState.vue';
|
||||||
import NetworkNotification from './components/NetworkNotification';
|
import NetworkNotification from './components/NetworkNotification';
|
||||||
import UpdateBanner from './components/app/UpdateBanner.vue';
|
import UpdateBanner from './components/app/UpdateBanner.vue';
|
||||||
|
import vueActionCable from './helper/actionCable';
|
||||||
import WootSnackbarBox from './components/SnackbarContainer';
|
import WootSnackbarBox from './components/SnackbarContainer';
|
||||||
|
import {
|
||||||
|
registerSubscription,
|
||||||
|
verifyServiceWorkerExistence,
|
||||||
|
} from './helper/pushHelper';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
AddAccountModal,
|
AddAccountModal,
|
||||||
|
LoadingState,
|
||||||
NetworkNotification,
|
NetworkNotification,
|
||||||
UpdateBanner,
|
UpdateBanner,
|
||||||
WootSnackbarBox,
|
WootSnackbarBox,
|
||||||
|
@ -43,13 +50,12 @@ export default {
|
||||||
getAccount: 'accounts/getAccount',
|
getAccount: 'accounts/getAccount',
|
||||||
currentUser: 'getCurrentUser',
|
currentUser: 'getCurrentUser',
|
||||||
globalConfig: 'globalConfig/get',
|
globalConfig: 'globalConfig/get',
|
||||||
|
authUIFlags: 'getAuthUIFlags',
|
||||||
|
currentAccountId: 'getCurrentAccountId',
|
||||||
}),
|
}),
|
||||||
hasAccounts() {
|
hasAccounts() {
|
||||||
return (
|
const { accounts = [] } = this.currentUser || {};
|
||||||
this.currentUser &&
|
return accounts.length > 0;
|
||||||
this.currentUser.accounts &&
|
|
||||||
this.currentUser.accounts.length !== 0
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -58,32 +64,37 @@ export default {
|
||||||
if (!this.hasAccounts) {
|
if (!this.hasAccounts) {
|
||||||
this.showAddAccountModal = true;
|
this.showAddAccountModal = true;
|
||||||
}
|
}
|
||||||
|
verifyServiceWorkerExistence(registration =>
|
||||||
|
registration.pushManager.getSubscription().then(subscription => {
|
||||||
|
if (subscription) {
|
||||||
|
registerSubscription();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
|
currentAccountId() {
|
||||||
|
if (this.currentAccountId) {
|
||||||
|
this.initializeAccount();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$store.dispatch('setUser');
|
|
||||||
this.setLocale(window.chatwootConfig.selectedLocale);
|
this.setLocale(window.chatwootConfig.selectedLocale);
|
||||||
this.initializeAccount();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
setLocale(locale) {
|
setLocale(locale) {
|
||||||
this.$root.$i18n.locale = locale;
|
this.$root.$i18n.locale = locale;
|
||||||
},
|
},
|
||||||
|
|
||||||
async initializeAccount() {
|
async initializeAccount() {
|
||||||
const { pathname } = window.location;
|
await this.$store.dispatch('accounts/get');
|
||||||
const accountId = accountIdFromPathname(pathname);
|
const {
|
||||||
|
locale,
|
||||||
if (accountId) {
|
latest_chatwoot_version: latestChatwootVersion,
|
||||||
await this.$store.dispatch('accounts/get');
|
} = this.getAccount(this.currentAccountId);
|
||||||
const {
|
const { pubsub_token: pubsubToken } = this.currentUser || {};
|
||||||
locale,
|
this.setLocale(locale);
|
||||||
latest_chatwoot_version: latestChatwootVersion,
|
this.latestChatwootVersion = latestChatwootVersion;
|
||||||
} = this.getAccount(accountId);
|
vueActionCable.init(pubsubToken);
|
||||||
this.setLocale(locale);
|
|
||||||
this.latestChatwootVersion = latestChatwootVersion;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
/* eslint no-console: 0 */
|
|
||||||
/* global axios */
|
/* global axios */
|
||||||
/* eslint no-undef: "error" */
|
|
||||||
|
|
||||||
import Cookies from 'js-cookie';
|
import Cookies from 'js-cookie';
|
||||||
import endPoints from './endPoints';
|
import endPoints from './endPoints';
|
||||||
|
@ -61,41 +59,15 @@ export default {
|
||||||
});
|
});
|
||||||
return fetchPromise;
|
return fetchPromise;
|
||||||
},
|
},
|
||||||
|
hasAuthCookie() {
|
||||||
isLoggedIn() {
|
return !!Cookies.getJSON('cw_d_session_info');
|
||||||
const hasAuthCookie = !!Cookies.getJSON('auth_data');
|
|
||||||
const hasUserCookie = !!Cookies.getJSON('user');
|
|
||||||
return hasAuthCookie && hasUserCookie;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
isAdmin() {
|
|
||||||
if (this.isLoggedIn()) {
|
|
||||||
return Cookies.getJSON('user').role === 'administrator';
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
getAuthData() {
|
getAuthData() {
|
||||||
if (this.isLoggedIn()) {
|
if (this.hasAuthCookie()) {
|
||||||
return Cookies.getJSON('auth_data');
|
return Cookies.getJSON('cw_d_session_info');
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
getPubSubToken() {
|
|
||||||
if (this.isLoggedIn()) {
|
|
||||||
const user = Cookies.getJSON('user') || {};
|
|
||||||
const { pubsub_token: pubsubToken } = user;
|
|
||||||
return pubsubToken;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
getCurrentUser() {
|
|
||||||
if (this.isLoggedIn()) {
|
|
||||||
return Cookies.getJSON('user');
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
|
|
||||||
verifyPasswordToken({ confirmationToken }) {
|
verifyPasswordToken({ confirmationToken }) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
axios
|
axios
|
||||||
|
|
|
@ -53,7 +53,7 @@ export default {
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters({
|
...mapGetters({
|
||||||
getCurrentUserAvailability: 'getCurrentUserAvailability',
|
getCurrentUserAvailability: 'getCurrentUserAvailability',
|
||||||
getCurrentAccountId: 'getCurrentAccountId',
|
currentAccountId: 'getCurrentAccountId',
|
||||||
}),
|
}),
|
||||||
availabilityDisplayLabel() {
|
availabilityDisplayLabel() {
|
||||||
const availabilityIndex = AVAILABILITY_STATUS_KEYS.findIndex(
|
const availabilityIndex = AVAILABILITY_STATUS_KEYS.findIndex(
|
||||||
|
@ -63,9 +63,6 @@ export default {
|
||||||
availabilityIndex
|
availabilityIndex
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
currentAccountId() {
|
|
||||||
return this.getCurrentAccountId;
|
|
||||||
},
|
|
||||||
currentUserAvailability() {
|
currentUserAvailability() {
|
||||||
return this.getCurrentUserAvailability;
|
return this.getCurrentUserAvailability;
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
/* eslint no-console: 0 */
|
|
||||||
import Auth from '../api/auth';
|
import Auth from '../api/auth';
|
||||||
|
|
||||||
const parseErrorCode = error => Promise.reject(error);
|
const parseErrorCode = error => Promise.reject(error);
|
||||||
|
@ -7,7 +6,7 @@ export default axios => {
|
||||||
const { apiHost = '' } = window.chatwootConfig || {};
|
const { apiHost = '' } = window.chatwootConfig || {};
|
||||||
const wootApi = axios.create({ baseURL: `${apiHost}/` });
|
const wootApi = axios.create({ baseURL: `${apiHost}/` });
|
||||||
// Add Auth Headers to requests if logged in
|
// Add Auth Headers to requests if logged in
|
||||||
if (Auth.isLoggedIn()) {
|
if (Auth.hasAuthCookie()) {
|
||||||
const {
|
const {
|
||||||
'access-token': accessToken,
|
'access-token': accessToken,
|
||||||
'token-type': tokenType,
|
'token-type': tokenType,
|
||||||
|
|
|
@ -14,6 +14,9 @@ export const getLoginRedirectURL = (ssoAccountId, user) => {
|
||||||
if (ssoAccount) {
|
if (ssoAccount) {
|
||||||
return frontendURL(`accounts/${ssoAccountId}/dashboard`);
|
return frontendURL(`accounts/${ssoAccountId}/dashboard`);
|
||||||
}
|
}
|
||||||
|
if (accounts.length) {
|
||||||
|
return frontendURL(`accounts/${accounts[0].id}/dashboard`);
|
||||||
|
}
|
||||||
return DEFAULT_REDIRECT_URL;
|
return DEFAULT_REDIRECT_URL;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -41,15 +44,6 @@ export const conversationUrl = ({
|
||||||
return url;
|
return url;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const accountIdFromPathname = pathname => {
|
|
||||||
const isInsideAccountScopedURLs = pathname.includes('/app/accounts');
|
|
||||||
const urlParam = pathname.split('/')[3];
|
|
||||||
// eslint-disable-next-line no-restricted-globals
|
|
||||||
const isScoped = isInsideAccountScopedURLs && !isNaN(urlParam);
|
|
||||||
const accountId = isScoped ? Number(urlParam) : '';
|
|
||||||
return accountId;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const isValidURL = value => {
|
export const isValidURL = value => {
|
||||||
/* eslint-disable no-useless-escape */
|
/* eslint-disable no-useless-escape */
|
||||||
const URL_REGEX = /^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$/gm;
|
const URL_REGEX = /^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$/gm;
|
||||||
|
|
|
@ -142,14 +142,7 @@ class ActionCableConnector extends BaseActionCableConnector {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
init() {
|
init(pubsubToken) {
|
||||||
if (AuthAPI.isLoggedIn()) {
|
return new ActionCableConnector(window.WOOT, pubsubToken);
|
||||||
const actionCable = new ActionCableConnector(
|
|
||||||
window.WOOT,
|
|
||||||
AuthAPI.getPubSubToken()
|
|
||||||
);
|
|
||||||
return actionCable;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -44,7 +44,7 @@ export const getPushSubscriptionPayload = subscription => ({
|
||||||
});
|
});
|
||||||
|
|
||||||
export const sendRegistrationToServer = subscription => {
|
export const sendRegistrationToServer = subscription => {
|
||||||
if (auth.isLoggedIn()) {
|
if (auth.hasAuthCookie()) {
|
||||||
return NotificationSubscriptions.create(
|
return NotificationSubscriptions.create(
|
||||||
getPushSubscriptionPayload(subscription)
|
getPushSubscriptionPayload(subscription)
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import {
|
import {
|
||||||
frontendURL,
|
frontendURL,
|
||||||
conversationUrl,
|
conversationUrl,
|
||||||
accountIdFromPathname,
|
|
||||||
isValidURL,
|
isValidURL,
|
||||||
getLoginRedirectURL,
|
getLoginRedirectURL,
|
||||||
} from '../URLHelper';
|
} from '../URLHelper';
|
||||||
|
@ -39,18 +38,6 @@ describe('#URL Helpers', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('accountIdFromPathname', () => {
|
|
||||||
it('should return account id if accont scoped url is passed', () => {
|
|
||||||
expect(accountIdFromPathname('/app/accounts/1/settings/general')).toBe(1);
|
|
||||||
});
|
|
||||||
it('should return empty string if accont scoped url not is passed', () => {
|
|
||||||
expect(accountIdFromPathname('/app/accounts/settings/general')).toBe('');
|
|
||||||
});
|
|
||||||
it('should return empty string if empty string is passed', () => {
|
|
||||||
expect(accountIdFromPathname('')).toBe('');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('isValidURL', () => {
|
describe('isValidURL', () => {
|
||||||
it('should return true if valid url is passed', () => {
|
it('should return true if valid url is passed', () => {
|
||||||
expect(isValidURL('https://chatwoot.com')).toBe(true);
|
expect(isValidURL('https://chatwoot.com')).toBe(true);
|
||||||
|
@ -75,7 +62,7 @@ describe('#URL Helpers', () => {
|
||||||
getLoginRedirectURL('7500', {
|
getLoginRedirectURL('7500', {
|
||||||
accounts: [{ id: '7501', name: 'Test Account 7501' }],
|
accounts: [{ id: '7501', name: 'Test Account 7501' }],
|
||||||
})
|
})
|
||||||
).toBe('/app/');
|
).toBe('/app/accounts/7501/dashboard');
|
||||||
expect(getLoginRedirectURL('7500', null)).toBe('/app/');
|
expect(getLoginRedirectURL('7500', null)).toBe('/app/');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -92,7 +92,6 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$store.dispatch('setCurrentAccountId', this.$route.params.accountId);
|
|
||||||
window.addEventListener('resize', this.handleResize);
|
window.addEventListener('resize', this.handleResize);
|
||||||
this.handleResize();
|
this.handleResize();
|
||||||
bus.$on(BUS_EVENTS.TOGGLE_SIDEMENU, this.toggleSidebar);
|
bus.$on(BUS_EVENTS.TOGGLE_SIDEMENU, this.toggleSidebar);
|
||||||
|
|
|
@ -1,21 +1,13 @@
|
||||||
import VueRouter from 'vue-router';
|
import VueRouter from 'vue-router';
|
||||||
|
|
||||||
import auth from '../api/auth';
|
|
||||||
import login from './login/login.routes';
|
|
||||||
import dashboard from './dashboard/dashboard.routes';
|
|
||||||
import authRoute from './auth/auth.routes';
|
|
||||||
import { frontendURL } from '../helper/URLHelper';
|
import { frontendURL } from '../helper/URLHelper';
|
||||||
import { clearBrowserSessionCookies } from '../store/utils/api';
|
import { clearBrowserSessionCookies } from '../store/utils/api';
|
||||||
|
import authRoute from './auth/auth.routes';
|
||||||
|
import dashboard from './dashboard/dashboard.routes';
|
||||||
|
import login from './login/login.routes';
|
||||||
|
import store from '../store';
|
||||||
|
|
||||||
const routes = [
|
const routes = [...login.routes, ...dashboard.routes, ...authRoute.routes];
|
||||||
...login.routes,
|
|
||||||
...dashboard.routes,
|
|
||||||
...authRoute.routes,
|
|
||||||
{
|
|
||||||
path: '/',
|
|
||||||
redirect: '/app',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
window.roleWiseRoutes = {
|
window.roleWiseRoutes = {
|
||||||
agent: [],
|
agent: [],
|
||||||
|
@ -63,8 +55,8 @@ const routeValidators = [
|
||||||
{
|
{
|
||||||
protected: false,
|
protected: false,
|
||||||
loggedIn: true,
|
loggedIn: true,
|
||||||
handler: () => {
|
handler: (_, getters) => {
|
||||||
const user = auth.getCurrentUser();
|
const user = getters.getCurrentUser;
|
||||||
return `accounts/${user.account_id}/dashboard`;
|
return `accounts/${user.account_id}/dashboard`;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -76,8 +68,8 @@ const routeValidators = [
|
||||||
{
|
{
|
||||||
protected: true,
|
protected: true,
|
||||||
loggedIn: true,
|
loggedIn: true,
|
||||||
handler: to => {
|
handler: (to, getters) => {
|
||||||
const user = auth.getCurrentUser();
|
const user = getters.getCurrentUser;
|
||||||
const userRole = getUserRole(user, Number(to.params.accountId));
|
const userRole = getUserRole(user, Number(to.params.accountId));
|
||||||
const isAccessible = routeIsAccessibleFor(to.name, userRole);
|
const isAccessible = routeIsAccessibleFor(to.name, userRole);
|
||||||
return isAccessible ? null : `accounts/${to.params.accountId}/dashboard`;
|
return isAccessible ? null : `accounts/${to.params.accountId}/dashboard`;
|
||||||
|
@ -90,15 +82,20 @@ const routeValidators = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const validateAuthenticateRoutePermission = (to, from, next) => {
|
export const validateAuthenticateRoutePermission = (
|
||||||
const isLoggedIn = auth.isLoggedIn();
|
to,
|
||||||
|
from,
|
||||||
|
next,
|
||||||
|
{ getters }
|
||||||
|
) => {
|
||||||
|
const isLoggedIn = getters.isLoggedIn;
|
||||||
const isProtectedRoute = !unProtectedRoutes.includes(to.name);
|
const isProtectedRoute = !unProtectedRoutes.includes(to.name);
|
||||||
const strategy = routeValidators.find(
|
const strategy = routeValidators.find(
|
||||||
validator =>
|
validator =>
|
||||||
validator.protected === isProtectedRoute &&
|
validator.protected === isProtectedRoute &&
|
||||||
validator.loggedIn === isLoggedIn
|
validator.loggedIn === isLoggedIn
|
||||||
);
|
);
|
||||||
const nextRoute = strategy.handler(to);
|
const nextRoute = strategy.handler(to, getters);
|
||||||
return nextRoute ? next(frontendURL(nextRoute)) : next();
|
return nextRoute ? next(frontendURL(nextRoute)) : next();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -109,38 +106,47 @@ const validateSSOLoginParams = to => {
|
||||||
return isLoginRoute && hasValidSSOParams;
|
return isLoginRoute && hasValidSSOParams;
|
||||||
};
|
};
|
||||||
|
|
||||||
const validateRouteAccess = (to, from, next) => {
|
export const validateRouteAccess = (to, from, next, { getters }) => {
|
||||||
|
// Disable navigation to signup page if signups are disabled
|
||||||
|
// Signup route has an attribute (requireSignupEnabled)
|
||||||
|
// defined in it's route definition
|
||||||
if (
|
if (
|
||||||
window.chatwootConfig.signupEnabled !== 'true' &&
|
window.chatwootConfig.signupEnabled !== 'true' &&
|
||||||
to.meta &&
|
to.meta &&
|
||||||
to.meta.requireSignupEnabled
|
to.meta.requireSignupEnabled
|
||||||
) {
|
) {
|
||||||
const user = auth.getCurrentUser();
|
return next(frontendURL('login'));
|
||||||
next(frontendURL(`accounts/${user.account_id}/dashboard`));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (validateSSOLoginParams(to)) {
|
|
||||||
clearBrowserSessionCookies();
|
|
||||||
return next();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For routes which doesn't care about authentication, skip validation
|
||||||
if (authIgnoreRoutes.includes(to.name)) {
|
if (authIgnoreRoutes.includes(to.name)) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
return validateAuthenticateRoutePermission(to, from, next);
|
|
||||||
|
return validateAuthenticateRoutePermission(to, from, next, { getters });
|
||||||
};
|
};
|
||||||
|
|
||||||
// protecting routes
|
export const initalizeRouter = () => {
|
||||||
router.beforeEach((to, from, next) => {
|
const userAuthentication = store.dispatch('setUser');
|
||||||
if (!to.name) {
|
router.beforeEach((to, from, next) => {
|
||||||
const user = auth.getCurrentUser();
|
if (validateSSOLoginParams(to)) {
|
||||||
if (user) {
|
clearBrowserSessionCookies();
|
||||||
return next(frontendURL(`accounts/${user.account_id}/dashboard`));
|
next();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return next('/app/login');
|
|
||||||
}
|
|
||||||
|
|
||||||
return validateRouteAccess(to, from, next);
|
userAuthentication.then(() => {
|
||||||
});
|
if (!to.name) {
|
||||||
|
const { isLoggedIn, getCurrentUser: user } = store.getters;
|
||||||
|
if (isLoggedIn) {
|
||||||
|
return next(frontendURL(`accounts/${user.account_id}/dashboard`));
|
||||||
|
}
|
||||||
|
return next('/app/login');
|
||||||
|
}
|
||||||
|
|
||||||
|
return validateRouteAccess(to, from, next, store);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import 'expect-more-jest';
|
import 'expect-more-jest';
|
||||||
import { validateAuthenticateRoutePermission } from './index';
|
import {
|
||||||
import auth from '../api/auth';
|
validateAuthenticateRoutePermission,
|
||||||
|
validateRouteAccess,
|
||||||
|
} from './index';
|
||||||
|
|
||||||
jest.mock('./dashboard/dashboard.routes', () => ({
|
jest.mock('./dashboard/dashboard.routes', () => ({
|
||||||
routes: [],
|
routes: [],
|
||||||
|
@ -11,94 +13,119 @@ jest.mock('./auth/auth.routes', () => ({
|
||||||
jest.mock('./login/login.routes', () => ({
|
jest.mock('./login/login.routes', () => ({
|
||||||
routes: [],
|
routes: [],
|
||||||
}));
|
}));
|
||||||
jest.mock('../constants', () => {
|
|
||||||
return {
|
|
||||||
GRAVATAR_URL: 'https://www.gravatar.com/avatar',
|
|
||||||
CHANNELS: {
|
|
||||||
FACEBOOK: 'facebook',
|
|
||||||
},
|
|
||||||
ASSIGNEE_TYPE: {
|
|
||||||
ME: 'me',
|
|
||||||
UNASSIGNED: 'unassigned',
|
|
||||||
ALL: 'all',
|
|
||||||
},
|
|
||||||
STATUS_TYPE: {
|
|
||||||
OPEN: 'open',
|
|
||||||
RESOLVED: 'resolved',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
window.roleWiseRoutes = {};
|
window.roleWiseRoutes = {};
|
||||||
|
|
||||||
describe(`behavior`, () => {
|
describe('#validateAuthenticateRoutePermission', () => {
|
||||||
describe(`when route is not protected`, () => {
|
describe(`when route is not protected`, () => {
|
||||||
it(`should go to the dashboard when user is logged in`, () => {
|
it(`should go to the dashboard when user is logged in`, () => {
|
||||||
// Arrange
|
const to = { name: 'login', params: { accountId: 1 } };
|
||||||
spyOn(auth, 'isLoggedIn').and.returnValue(true);
|
|
||||||
spyOn(auth, 'getCurrentUser').and.returnValue({
|
|
||||||
account_id: 1,
|
|
||||||
accounts: [{ id: 1, role: 'agent' }],
|
|
||||||
});
|
|
||||||
const to = { name: 'login' };
|
|
||||||
const from = { name: '', params: { accountId: 1 } };
|
const from = { name: '', params: { accountId: 1 } };
|
||||||
const next = jest.fn();
|
const next = jest.fn();
|
||||||
// Act
|
const getters = {
|
||||||
validateAuthenticateRoutePermission(to, from, next);
|
isLoggedIn: true,
|
||||||
// Assert
|
getCurrentUser: {
|
||||||
|
account_id: 1,
|
||||||
|
id: 1,
|
||||||
|
accounts: [{ id: 1, role: 'admin' }],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
validateAuthenticateRoutePermission(to, from, next, { getters });
|
||||||
expect(next).toHaveBeenCalledWith('/app/accounts/1/dashboard');
|
expect(next).toHaveBeenCalledWith('/app/accounts/1/dashboard');
|
||||||
});
|
});
|
||||||
|
it(`should go there when user is not logged in`, () => {
|
||||||
|
const to = { name: 'login', params: {} };
|
||||||
|
const from = { name: '', params: {} };
|
||||||
|
const next = jest.fn();
|
||||||
|
const getters = { isLoggedIn: false };
|
||||||
|
validateAuthenticateRoutePermission(to, from, next, { getters });
|
||||||
|
expect(next).toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
describe(`when route is protected`, () => {
|
describe(`when route is protected`, () => {
|
||||||
describe(`when user not logged in`, () => {
|
describe(`when user not logged in`, () => {
|
||||||
it(`should redirect to login`, () => {
|
it(`should redirect to login`, () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
spyOn(auth, 'isLoggedIn').and.returnValue(false);
|
|
||||||
spyOn(auth, 'getCurrentUser').and.returnValue(null);
|
|
||||||
const to = { name: 'some-protected-route', params: { accountId: 1 } };
|
const to = { name: 'some-protected-route', params: { accountId: 1 } };
|
||||||
const from = { name: '' };
|
const from = { name: '' };
|
||||||
const next = jest.fn();
|
const next = jest.fn();
|
||||||
// Act
|
const getters = {
|
||||||
validateAuthenticateRoutePermission(to, from, next);
|
isLoggedIn: false,
|
||||||
// Assert
|
getCurrentUser: {
|
||||||
|
account_id: null,
|
||||||
|
id: null,
|
||||||
|
accounts: [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
validateAuthenticateRoutePermission(to, from, next, { getters });
|
||||||
expect(next).toHaveBeenCalledWith('/app/login');
|
expect(next).toHaveBeenCalledWith('/app/login');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe(`when user is logged in`, () => {
|
describe(`when user is logged in`, () => {
|
||||||
describe(`when route is not accessible to current user`, () => {
|
describe(`when route is not accessible to current user`, () => {
|
||||||
it(`should redirect to dashboard`, () => {
|
it(`should redirect to dashboard`, () => {
|
||||||
// Arrange
|
|
||||||
spyOn(auth, 'isLoggedIn').and.returnValue(true);
|
|
||||||
spyOn(auth, 'getCurrentUser').and.returnValue({
|
|
||||||
accounts: [{ id: 1, role: 'agent' }],
|
|
||||||
});
|
|
||||||
window.roleWiseRoutes.agent = ['dashboard'];
|
window.roleWiseRoutes.agent = ['dashboard'];
|
||||||
const to = { name: 'admin', params: { accountId: 1 } };
|
const to = { name: 'admin', params: { accountId: 1 } };
|
||||||
const from = { name: '' };
|
const from = { name: '' };
|
||||||
const next = jest.fn();
|
const next = jest.fn();
|
||||||
// Act
|
const getters = {
|
||||||
validateAuthenticateRoutePermission(to, from, next);
|
isLoggedIn: true,
|
||||||
// Assert
|
getCurrentUser: {
|
||||||
|
account_id: 1,
|
||||||
|
id: 1,
|
||||||
|
accounts: [{ id: 1, role: 'agent' }],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
validateAuthenticateRoutePermission(to, from, next, { getters });
|
||||||
expect(next).toHaveBeenCalledWith('/app/accounts/1/dashboard');
|
expect(next).toHaveBeenCalledWith('/app/accounts/1/dashboard');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe(`when route is accessible to current user`, () => {
|
describe(`when route is accessible to current user`, () => {
|
||||||
it(`should go there`, () => {
|
it(`should go there`, () => {
|
||||||
// Arrange
|
|
||||||
spyOn(auth, 'isLoggedIn').and.returnValue(true);
|
|
||||||
spyOn(auth, 'getCurrentUser').and.returnValue({
|
|
||||||
accounts: [{ id: 1, role: 'agent' }],
|
|
||||||
});
|
|
||||||
window.roleWiseRoutes.agent = ['dashboard', 'admin'];
|
window.roleWiseRoutes.agent = ['dashboard', 'admin'];
|
||||||
const to = { name: 'admin', params: { accountId: 1 } };
|
const to = { name: 'admin', params: { accountId: 1 } };
|
||||||
const from = { name: '' };
|
const from = { name: '' };
|
||||||
const next = jest.fn();
|
const next = jest.fn();
|
||||||
// Act
|
const getters = {
|
||||||
validateAuthenticateRoutePermission(to, from, next);
|
isLoggedIn: true,
|
||||||
// Assert
|
getCurrentUser: {
|
||||||
|
account_id: 1,
|
||||||
|
id: 1,
|
||||||
|
accounts: [{ id: 1, role: 'agent' }],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
validateAuthenticateRoutePermission(to, from, next, { getters });
|
||||||
expect(next).toHaveBeenCalledWith();
|
expect(next).toHaveBeenCalledWith();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('#validateRouteAccess', () => {
|
||||||
|
it('returns to login if signup is disabled', () => {
|
||||||
|
window.chatwootConfig = { signupEnabled: 'false' };
|
||||||
|
const to = { name: 'auth_signup', meta: { requireSignupEnabled: true } };
|
||||||
|
const from = { name: '' };
|
||||||
|
const next = jest.fn();
|
||||||
|
validateRouteAccess(to, from, next, {});
|
||||||
|
expect(next).toHaveBeenCalledWith('/app/login');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns next for an auth ignore route ', () => {
|
||||||
|
const to = { name: 'auth_confirmation' };
|
||||||
|
const from = { name: '' };
|
||||||
|
const next = jest.fn();
|
||||||
|
|
||||||
|
validateRouteAccess(to, from, next, {});
|
||||||
|
expect(next).toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns route validation for everything else ', () => {
|
||||||
|
const to = { name: 'login' };
|
||||||
|
const from = { name: '' };
|
||||||
|
const next = jest.fn();
|
||||||
|
|
||||||
|
validateRouteAccess(to, from, next, { getters: { isLoggedIn: false } });
|
||||||
|
expect(next).toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
@ -1,28 +1,20 @@
|
||||||
/* eslint no-param-reassign: 0 */
|
|
||||||
import axios from 'axios';
|
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import * as types from '../mutation-types';
|
import types from '../mutation-types';
|
||||||
import authAPI from '../../api/auth';
|
import authAPI from '../../api/auth';
|
||||||
import createAxios from '../../helper/APIHelper';
|
import { setUser, clearCookiesOnLogout } from '../utils/api';
|
||||||
import actionCable from '../../helper/actionCable';
|
|
||||||
import { setUser, getHeaderExpiry, clearCookiesOnLogout } from '../utils/api';
|
|
||||||
import { getLoginRedirectURL } from '../../helper/URLHelper';
|
import { getLoginRedirectURL } from '../../helper/URLHelper';
|
||||||
|
|
||||||
const state = {
|
const initialState = {
|
||||||
currentUser: {
|
currentUser: {
|
||||||
id: null,
|
id: null,
|
||||||
account_id: null,
|
account_id: null,
|
||||||
channel: null,
|
accounts: [],
|
||||||
email: null,
|
email: null,
|
||||||
name: null,
|
name: null,
|
||||||
provider: null,
|
|
||||||
uid: null,
|
|
||||||
subscription: {
|
|
||||||
state: null,
|
|
||||||
expiry: null,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
currentAccountId: null,
|
uiFlags: {
|
||||||
|
isFetching: true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// getters
|
// getters
|
||||||
|
@ -31,18 +23,22 @@ export const getters = {
|
||||||
return !!$state.currentUser.id;
|
return !!$state.currentUser.id;
|
||||||
},
|
},
|
||||||
|
|
||||||
getCurrentUserID(_state) {
|
getCurrentUserID($state) {
|
||||||
return _state.currentUser.id;
|
return $state.currentUser.id;
|
||||||
},
|
},
|
||||||
|
|
||||||
getUISettings(_state) {
|
getUISettings($state) {
|
||||||
return _state.currentUser.ui_settings || {};
|
return $state.currentUser.ui_settings || {};
|
||||||
},
|
},
|
||||||
|
|
||||||
getCurrentUserAvailability(_state) {
|
getAuthUIFlags($state) {
|
||||||
const { accounts = [] } = _state.currentUser;
|
return $state.uiFlags;
|
||||||
|
},
|
||||||
|
|
||||||
|
getCurrentUserAvailability($state, $getters) {
|
||||||
|
const { accounts = [] } = $state.currentUser;
|
||||||
const [currentAccount = {}] = accounts.filter(
|
const [currentAccount = {}] = accounts.filter(
|
||||||
account => account.id === _state.currentAccountId
|
account => account.id === $getters.getCurrentAccountId
|
||||||
);
|
);
|
||||||
return currentAccount.availability;
|
return currentAccount.availability;
|
||||||
},
|
},
|
||||||
|
@ -54,49 +50,45 @@ export const getters = {
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
getCurrentRole(_state) {
|
getCurrentRole($state, $getters) {
|
||||||
const { accounts = [] } = _state.currentUser;
|
const { accounts = [] } = $state.currentUser;
|
||||||
const [currentAccount = {}] = accounts.filter(
|
const [currentAccount = {}] = accounts.filter(
|
||||||
account => account.id === _state.currentAccountId
|
account => account.id === $getters.getCurrentAccountId
|
||||||
);
|
);
|
||||||
return currentAccount.role;
|
return currentAccount.role;
|
||||||
},
|
},
|
||||||
|
|
||||||
getCurrentUser(_state) {
|
getCurrentUser($state) {
|
||||||
return _state.currentUser;
|
return $state.currentUser;
|
||||||
},
|
},
|
||||||
|
|
||||||
getMessageSignature(_state) {
|
getMessageSignature($state) {
|
||||||
const { message_signature: messageSignature } = _state.currentUser;
|
const { message_signature: messageSignature } = $state.currentUser;
|
||||||
|
|
||||||
return messageSignature || '';
|
return messageSignature || '';
|
||||||
},
|
},
|
||||||
|
|
||||||
getCurrentAccount(_state) {
|
getCurrentAccount($state, $getters) {
|
||||||
const { accounts = [] } = _state.currentUser;
|
const { accounts = [] } = $state.currentUser;
|
||||||
const [currentAccount = {}] = accounts.filter(
|
const [currentAccount = {}] = accounts.filter(
|
||||||
account => account.id === _state.currentAccountId
|
account => account.id === $getters.getCurrentAccountId
|
||||||
);
|
);
|
||||||
return currentAccount || {};
|
return currentAccount || {};
|
||||||
},
|
},
|
||||||
|
|
||||||
getUserAccounts(_state) {
|
getUserAccounts($state) {
|
||||||
const { accounts = [] } = _state.currentUser;
|
const { accounts = [] } = $state.currentUser;
|
||||||
return accounts;
|
return accounts;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// actions
|
// actions
|
||||||
export const actions = {
|
export const actions = {
|
||||||
login({ commit }, { ssoAccountId, ...credentials }) {
|
login(_, { ssoAccountId, ...credentials }) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
authAPI
|
authAPI
|
||||||
.login(credentials)
|
.login(credentials)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
commit(types.default.SET_CURRENT_USER);
|
|
||||||
window.axios = createAxios(axios);
|
|
||||||
actionCable.init(Vue);
|
|
||||||
|
|
||||||
window.location = getLoginRedirectURL(ssoAccountId, response.data);
|
window.location = getLoginRedirectURL(ssoAccountId, response.data);
|
||||||
resolve();
|
resolve();
|
||||||
})
|
})
|
||||||
|
@ -108,43 +100,40 @@ export const actions = {
|
||||||
async validityCheck(context) {
|
async validityCheck(context) {
|
||||||
try {
|
try {
|
||||||
const response = await authAPI.validityCheck();
|
const response = await authAPI.validityCheck();
|
||||||
setUser(response.data.payload.data, getHeaderExpiry(response), {
|
const currentUser = response.data.payload.data;
|
||||||
setUserInSDK: true,
|
setUser(currentUser);
|
||||||
});
|
context.commit(types.SET_CURRENT_USER, currentUser);
|
||||||
context.commit(types.default.SET_CURRENT_USER);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error?.response?.status === 401) {
|
if (error?.response?.status === 401) {
|
||||||
clearCookiesOnLogout();
|
clearCookiesOnLogout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setUser({ commit, dispatch }) {
|
async setUser({ commit, dispatch }) {
|
||||||
if (authAPI.isLoggedIn()) {
|
if (authAPI.hasAuthCookie()) {
|
||||||
commit(types.default.SET_CURRENT_USER);
|
await dispatch('validityCheck');
|
||||||
dispatch('validityCheck');
|
|
||||||
} else {
|
} else {
|
||||||
commit(types.default.CLEAR_USER);
|
commit(types.CLEAR_USER);
|
||||||
}
|
}
|
||||||
|
commit(types.SET_CURRENT_USER_UI_FLAGS, { isFetching: false });
|
||||||
},
|
},
|
||||||
logout({ commit }) {
|
logout({ commit }) {
|
||||||
commit(types.default.CLEAR_USER);
|
commit(types.CLEAR_USER);
|
||||||
},
|
},
|
||||||
|
|
||||||
updateProfile: async ({ commit }, params) => {
|
updateProfile: async ({ commit }, params) => {
|
||||||
// eslint-disable-next-line no-useless-catch
|
// eslint-disable-next-line no-useless-catch
|
||||||
try {
|
try {
|
||||||
const response = await authAPI.profileUpdate(params);
|
const response = await authAPI.profileUpdate(params);
|
||||||
setUser(response.data, getHeaderExpiry(response));
|
commit(types.SET_CURRENT_USER, response.data);
|
||||||
commit(types.default.SET_CURRENT_USER);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
deleteAvatar: async ({ commit }) => {
|
deleteAvatar: async () => {
|
||||||
try {
|
try {
|
||||||
await authAPI.deleteAvatar();
|
await authAPI.deleteAvatar();
|
||||||
commit(types.default.SET_CURRENT_USER);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Ignore error
|
// Ignore error
|
||||||
}
|
}
|
||||||
|
@ -152,10 +141,9 @@ export const actions = {
|
||||||
|
|
||||||
updateUISettings: async ({ commit }, params) => {
|
updateUISettings: async ({ commit }, params) => {
|
||||||
try {
|
try {
|
||||||
commit(types.default.SET_CURRENT_USER_UI_SETTINGS, params);
|
commit(types.SET_CURRENT_USER_UI_SETTINGS, params);
|
||||||
const response = await authAPI.updateUISettings(params);
|
const response = await authAPI.updateUISettings(params);
|
||||||
setUser(response.data, getHeaderExpiry(response));
|
commit(types.SET_CURRENT_USER, response.data);
|
||||||
commit(types.default.SET_CURRENT_USER);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Ignore error
|
// Ignore error
|
||||||
}
|
}
|
||||||
|
@ -166,45 +154,32 @@ export const actions = {
|
||||||
const response = await authAPI.updateAvailability(params);
|
const response = await authAPI.updateAvailability(params);
|
||||||
const userData = response.data;
|
const userData = response.data;
|
||||||
const { id } = userData;
|
const { id } = userData;
|
||||||
setUser(userData, getHeaderExpiry(response));
|
commit(types.SET_CURRENT_USER, response.data);
|
||||||
commit(types.default.SET_CURRENT_USER);
|
|
||||||
dispatch('agents/updatePresence', { [id]: params.availability });
|
dispatch('agents/updatePresence', { [id]: params.availability });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Ignore error
|
// Ignore error
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
setCurrentAccountId({ commit }, accountId) {
|
|
||||||
commit(types.default.SET_CURRENT_ACCOUNT_ID, accountId);
|
|
||||||
},
|
|
||||||
|
|
||||||
setCurrentUserAvailability({ commit, state: $state }, data) {
|
setCurrentUserAvailability({ commit, state: $state }, data) {
|
||||||
if (data[$state.currentUser.id]) {
|
if (data[$state.currentUser.id]) {
|
||||||
commit(
|
commit(types.SET_CURRENT_USER_AVAILABILITY, data[$state.currentUser.id]);
|
||||||
types.default.SET_CURRENT_USER_AVAILABILITY,
|
|
||||||
data[$state.currentUser.id]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// mutations
|
// mutations
|
||||||
export const mutations = {
|
export const mutations = {
|
||||||
[types.default.SET_CURRENT_USER_AVAILABILITY](_state, availability) {
|
[types.SET_CURRENT_USER_AVAILABILITY](_state, availability) {
|
||||||
Vue.set(_state.currentUser, 'availability', availability);
|
Vue.set(_state.currentUser, 'availability', availability);
|
||||||
},
|
},
|
||||||
[types.default.CLEAR_USER](_state) {
|
[types.CLEAR_USER](_state) {
|
||||||
_state.currentUser.id = null;
|
_state.currentUser = initialState.currentUser;
|
||||||
},
|
},
|
||||||
[types.default.SET_CURRENT_USER](_state) {
|
[types.SET_CURRENT_USER](_state, currentUser) {
|
||||||
const currentUser = {
|
|
||||||
...authAPI.getAuthData(),
|
|
||||||
...authAPI.getCurrentUser(),
|
|
||||||
};
|
|
||||||
|
|
||||||
Vue.set(_state, 'currentUser', currentUser);
|
Vue.set(_state, 'currentUser', currentUser);
|
||||||
},
|
},
|
||||||
[types.default.SET_CURRENT_USER_UI_SETTINGS](_state, { uiSettings }) {
|
[types.SET_CURRENT_USER_UI_SETTINGS](_state, { uiSettings }) {
|
||||||
Vue.set(_state, 'currentUser', {
|
Vue.set(_state, 'currentUser', {
|
||||||
..._state.currentUser,
|
..._state.currentUser,
|
||||||
ui_settings: {
|
ui_settings: {
|
||||||
|
@ -213,13 +188,14 @@ export const mutations = {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[types.default.SET_CURRENT_ACCOUNT_ID](_state, accountId) {
|
|
||||||
Vue.set(_state, 'currentAccountId', Number(accountId));
|
[types.SET_CURRENT_USER_UI_FLAGS](_state, { isFetching }) {
|
||||||
|
Vue.set(_state, 'uiFlags', { isFetching });
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
state,
|
state: initialState,
|
||||||
getters,
|
getters,
|
||||||
actions,
|
actions,
|
||||||
mutations,
|
mutations,
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import authAPI from '../../../api/auth';
|
|
||||||
import { MESSAGE_TYPE } from 'shared/constants/messages';
|
import { MESSAGE_TYPE } from 'shared/constants/messages';
|
||||||
import { applyPageFilters } from './helpers';
|
import { applyPageFilters } from './helpers';
|
||||||
|
|
||||||
|
@ -40,8 +39,8 @@ const getters = {
|
||||||
|
|
||||||
return lastEmail;
|
return lastEmail;
|
||||||
},
|
},
|
||||||
getMineChats: _state => activeFilters => {
|
getMineChats: (_state, _, __, rootGetters) => activeFilters => {
|
||||||
const currentUserID = authAPI.getCurrentUser().id;
|
const currentUserID = rootGetters.getCurrentUser?.id;
|
||||||
|
|
||||||
return _state.allConversations.filter(conversation => {
|
return _state.allConversations.filter(conversation => {
|
||||||
const { assignee } = conversation.meta;
|
const { assignee } = conversation.meta;
|
||||||
|
|
|
@ -29,7 +29,9 @@ describe('#actions', () => {
|
||||||
});
|
});
|
||||||
await actions.validityCheck({ commit });
|
await actions.validityCheck({ commit });
|
||||||
expect(setUser).toHaveBeenCalledTimes(1);
|
expect(setUser).toHaveBeenCalledTimes(1);
|
||||||
expect(commit.mock.calls).toEqual([[types.default.SET_CURRENT_USER]]);
|
expect(commit.mock.calls).toEqual([
|
||||||
|
[types.default.SET_CURRENT_USER, { id: 1, name: 'John' }],
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
it('sends correct actions if API is error', async () => {
|
it('sends correct actions if API is error', async () => {
|
||||||
axios.get.mockRejectedValue({
|
axios.get.mockRejectedValue({
|
||||||
|
@ -47,8 +49,9 @@ describe('#actions', () => {
|
||||||
headers: { expiry: 581842904 },
|
headers: { expiry: 581842904 },
|
||||||
});
|
});
|
||||||
await actions.updateProfile({ commit }, { name: 'Pranav' });
|
await actions.updateProfile({ commit }, { name: 'Pranav' });
|
||||||
expect(setUser).toHaveBeenCalledTimes(1);
|
expect(commit.mock.calls).toEqual([
|
||||||
expect(commit.mock.calls).toEqual([[types.default.SET_CURRENT_USER]]);
|
[types.default.SET_CURRENT_USER, { id: 1, name: 'John' }],
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -57,7 +60,8 @@ describe('#actions', () => {
|
||||||
axios.post.mockResolvedValue({
|
axios.post.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
id: 1,
|
id: 1,
|
||||||
account_users: [{ account_id: 1, availability_status: 'offline' }],
|
name: 'John',
|
||||||
|
accounts: [{ account_id: 1, availability_status: 'offline' }],
|
||||||
},
|
},
|
||||||
headers: { expiry: 581842904 },
|
headers: { expiry: 581842904 },
|
||||||
});
|
});
|
||||||
|
@ -65,8 +69,16 @@ describe('#actions', () => {
|
||||||
{ commit, dispatch },
|
{ commit, dispatch },
|
||||||
{ availability: 'offline', account_id: 1 }
|
{ availability: 'offline', account_id: 1 }
|
||||||
);
|
);
|
||||||
expect(setUser).toHaveBeenCalledTimes(1);
|
expect(commit.mock.calls).toEqual([
|
||||||
expect(commit.mock.calls).toEqual([[types.default.SET_CURRENT_USER]]);
|
[
|
||||||
|
types.default.SET_CURRENT_USER,
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'John',
|
||||||
|
accounts: [{ account_id: 1, availability_status: 'offline' }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]);
|
||||||
expect(dispatch.mock.calls).toEqual([
|
expect(dispatch.mock.calls).toEqual([
|
||||||
['agents/updatePresence', { 1: 'offline' }],
|
['agents/updatePresence', { 1: 'offline' }],
|
||||||
]);
|
]);
|
||||||
|
@ -88,13 +100,20 @@ describe('#actions', () => {
|
||||||
{ commit, dispatch },
|
{ commit, dispatch },
|
||||||
{ uiSettings: { is_contact_sidebar_open: false } }
|
{ uiSettings: { is_contact_sidebar_open: false } }
|
||||||
);
|
);
|
||||||
expect(setUser).toHaveBeenCalledTimes(1);
|
|
||||||
expect(commit.mock.calls).toEqual([
|
expect(commit.mock.calls).toEqual([
|
||||||
[
|
[
|
||||||
types.default.SET_CURRENT_USER_UI_SETTINGS,
|
types.default.SET_CURRENT_USER_UI_SETTINGS,
|
||||||
{ uiSettings: { is_contact_sidebar_open: false } },
|
{ uiSettings: { is_contact_sidebar_open: false } },
|
||||||
],
|
],
|
||||||
[types.default.SET_CURRENT_USER],
|
[
|
||||||
|
types.default.SET_CURRENT_USER,
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'John',
|
||||||
|
availability_status: 'offline',
|
||||||
|
ui_settings: { is_contact_sidebar_open: true },
|
||||||
|
},
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -103,14 +122,17 @@ describe('#actions', () => {
|
||||||
it('sends correct actions if user is logged in', async () => {
|
it('sends correct actions if user is logged in', async () => {
|
||||||
Cookies.getJSON.mockImplementation(() => true);
|
Cookies.getJSON.mockImplementation(() => true);
|
||||||
actions.setUser({ commit, dispatch });
|
actions.setUser({ commit, dispatch });
|
||||||
expect(commit.mock.calls).toEqual([[types.default.SET_CURRENT_USER]]);
|
expect(commit.mock.calls).toEqual([]);
|
||||||
expect(dispatch.mock.calls).toEqual([['validityCheck']]);
|
expect(dispatch.mock.calls).toEqual([['validityCheck']]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sends correct actions if user is not logged in', async () => {
|
it('sends correct actions if user is not logged in', async () => {
|
||||||
Cookies.getJSON.mockImplementation(() => false);
|
Cookies.getJSON.mockImplementation(() => false);
|
||||||
actions.setUser({ commit, dispatch });
|
actions.setUser({ commit, dispatch });
|
||||||
expect(commit.mock.calls).toEqual([[types.default.CLEAR_USER]]);
|
expect(commit.mock.calls).toEqual([
|
||||||
|
[types.default.CLEAR_USER],
|
||||||
|
[types.default.SET_CURRENT_USER_UI_FLAGS, { isFetching: false }],
|
||||||
|
]);
|
||||||
expect(dispatch).toHaveBeenCalledTimes(0);
|
expect(dispatch).toHaveBeenCalledTimes(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,39 +4,74 @@ import '../../../../routes';
|
||||||
|
|
||||||
jest.mock('../../../../routes', () => {});
|
jest.mock('../../../../routes', () => {});
|
||||||
describe('#getters', () => {
|
describe('#getters', () => {
|
||||||
it('isLoggedIn', () => {
|
describe('#isLoggedIn', () => {
|
||||||
expect(getters.isLoggedIn({ currentUser: { id: null } })).toEqual(false);
|
it('return correct value if user data is available', () => {
|
||||||
expect(getters.isLoggedIn({ currentUser: { id: 1 } })).toEqual(true);
|
expect(getters.isLoggedIn({ currentUser: { id: null } })).toEqual(false);
|
||||||
|
expect(getters.isLoggedIn({ currentUser: { id: 1 } })).toEqual(true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('getCurrentUserID', () => {
|
describe('#getCurrentUser', () => {
|
||||||
expect(getters.getCurrentUserID({ currentUser: { id: 1 } })).toEqual(1);
|
it('returns current user id', () => {
|
||||||
});
|
expect(getters.getCurrentUserID({ currentUser: { id: 1 } })).toEqual(1);
|
||||||
it('getCurrentUser', () => {
|
});
|
||||||
expect(
|
|
||||||
getters.getCurrentUser({ currentUser: { id: 1, name: 'Pranav' } })
|
|
||||||
).toEqual({ id: 1, name: 'Pranav' });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('get', () => {
|
describe('#getCurrentUser', () => {
|
||||||
expect(
|
it('returns current user object', () => {
|
||||||
getters.getCurrentUserAvailability({
|
expect(
|
||||||
currentAccountId: 1,
|
getters.getCurrentUser({ currentUser: { id: 1, name: 'Pranav' } })
|
||||||
currentUser: {
|
).toEqual({ id: 1, name: 'Pranav' });
|
||||||
id: 1,
|
});
|
||||||
accounts: [{ id: 1, availability: 'busy' }],
|
|
||||||
},
|
|
||||||
})
|
|
||||||
).toEqual('busy');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('getUISettings', () => {
|
describe('#getCurrentRole', () => {
|
||||||
expect(
|
it('returns current role if account is available', () => {
|
||||||
getters.getUISettings({
|
expect(
|
||||||
currentUser: { ui_settings: { is_contact_sidebar_open: true } },
|
getters.getCurrentRole(
|
||||||
})
|
{ currentUser: { accounts: [{ id: 1, role: 'admin' }] } },
|
||||||
).toEqual({ is_contact_sidebar_open: true });
|
{ getCurrentAccountId: 1 }
|
||||||
|
)
|
||||||
|
).toEqual('admin');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns undefined if account is not available', () => {
|
||||||
|
expect(
|
||||||
|
getters.getCurrentRole(
|
||||||
|
{ currentUser: { accounts: [{ id: 1, role: 'admin' }] } },
|
||||||
|
{ getCurrentAccountId: 2 }
|
||||||
|
)
|
||||||
|
).toEqual(undefined);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('#getCurrentUserAvailability', () => {
|
||||||
|
it('returns correct availability status', () => {
|
||||||
|
expect(
|
||||||
|
getters.getCurrentUserAvailability(
|
||||||
|
{
|
||||||
|
currentAccountId: 1,
|
||||||
|
currentUser: {
|
||||||
|
id: 1,
|
||||||
|
accounts: [{ id: 1, availability: 'busy' }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ getCurrentAccountId: 1 }
|
||||||
|
)
|
||||||
|
).toEqual('busy');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#getUISettings', () => {
|
||||||
|
it('return correct UI Settings', () => {
|
||||||
|
expect(
|
||||||
|
getters.getUISettings({
|
||||||
|
currentUser: { ui_settings: { is_contact_sidebar_open: true } },
|
||||||
|
})
|
||||||
|
).toEqual({ is_contact_sidebar_open: true });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('#getMessageSignature', () => {
|
describe('#getMessageSignature', () => {
|
||||||
it('Return signature when signature is present', () => {
|
it('Return signature when signature is present', () => {
|
||||||
expect(
|
expect(
|
||||||
|
@ -46,11 +81,7 @@ describe('#getters', () => {
|
||||||
).toEqual('Thanks');
|
).toEqual('Thanks');
|
||||||
});
|
});
|
||||||
it('Return empty string when signature is not present', () => {
|
it('Return empty string when signature is not present', () => {
|
||||||
expect(
|
expect(getters.getMessageSignature({ currentUser: {} })).toEqual('');
|
||||||
getters.getMessageSignature({
|
|
||||||
currentUser: {},
|
|
||||||
})
|
|
||||||
).toEqual('');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -59,22 +90,23 @@ describe('#getters', () => {
|
||||||
expect(
|
expect(
|
||||||
getters.getCurrentAccount({
|
getters.getCurrentAccount({
|
||||||
currentUser: {},
|
currentUser: {},
|
||||||
currentAccountId: 1,
|
|
||||||
})
|
})
|
||||||
).toEqual({});
|
).toEqual({});
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
getters.getCurrentAccount({
|
getters.getCurrentAccount(
|
||||||
currentUser: {
|
{
|
||||||
accounts: [
|
currentUser: {
|
||||||
{
|
accounts: [
|
||||||
name: 'Chatwoot',
|
{
|
||||||
id: 1,
|
name: 'Chatwoot',
|
||||||
},
|
id: 1,
|
||||||
],
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
currentAccountId: 1,
|
||||||
},
|
},
|
||||||
currentAccountId: 1,
|
{ getCurrentAccountId: 1 }
|
||||||
})
|
)
|
||||||
).toEqual({
|
).toEqual({
|
||||||
name: 'Chatwoot',
|
name: 'Chatwoot',
|
||||||
id: 1,
|
id: 1,
|
||||||
|
@ -89,7 +121,6 @@ describe('#getters', () => {
|
||||||
currentUser: {},
|
currentUser: {},
|
||||||
})
|
})
|
||||||
).toEqual([]);
|
).toEqual([]);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
getters.getUserAccounts({
|
getters.getUserAccounts({
|
||||||
currentUser: {
|
currentUser: {
|
||||||
|
|
|
@ -18,4 +18,28 @@ describe('#mutations', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
describe('#SET_CURRENT_USER_UI_FLAGS', () => {
|
||||||
|
it('set auth ui flags', () => {
|
||||||
|
const state = {
|
||||||
|
uiFlags: { isFetching: false },
|
||||||
|
};
|
||||||
|
mutations[types.SET_CURRENT_USER_UI_FLAGS](state, { isFetching: true });
|
||||||
|
expect(state.uiFlags.isFetching).toEqual(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#CLEAR_USER', () => {
|
||||||
|
it('set auth ui flags', () => {
|
||||||
|
const state = {
|
||||||
|
currentUser: { id: 1 },
|
||||||
|
};
|
||||||
|
mutations[types.CLEAR_USER](state);
|
||||||
|
expect(state.currentUser).toEqual({
|
||||||
|
id: null,
|
||||||
|
account_id: null,
|
||||||
|
accounts: [],
|
||||||
|
email: null,
|
||||||
|
name: null,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,9 +2,9 @@ export default {
|
||||||
AUTHENTICATE: 'AUTHENTICATE',
|
AUTHENTICATE: 'AUTHENTICATE',
|
||||||
CLEAR_USER: 'LOGOUT',
|
CLEAR_USER: 'LOGOUT',
|
||||||
SET_CURRENT_USER: 'SET_CURRENT_USER',
|
SET_CURRENT_USER: 'SET_CURRENT_USER',
|
||||||
SET_CURRENT_ACCOUNT_ID: 'SET_CURRENT_ACCOUNT_ID',
|
|
||||||
SET_CURRENT_USER_AVAILABILITY: 'SET_CURRENT_USER_AVAILABILITY',
|
SET_CURRENT_USER_AVAILABILITY: 'SET_CURRENT_USER_AVAILABILITY',
|
||||||
SET_CURRENT_USER_UI_SETTINGS: 'SET_CURRENT_USER_UI_SETTINGS',
|
SET_CURRENT_USER_UI_SETTINGS: 'SET_CURRENT_USER_UI_SETTINGS',
|
||||||
|
SET_CURRENT_USER_UI_FLAGS: 'SET_CURRENT_USER_UI_FLAGS',
|
||||||
|
|
||||||
// Chat List
|
// Chat List
|
||||||
RECEIVE_CHAT_LIST: 'RECEIVE_CHAT_LIST',
|
RECEIVE_CHAT_LIST: 'RECEIVE_CHAT_LIST',
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
/* eslint no-param-reassign: 0 */
|
|
||||||
import fromUnixTime from 'date-fns/fromUnixTime';
|
import fromUnixTime from 'date-fns/fromUnixTime';
|
||||||
import differenceInDays from 'date-fns/differenceInDays';
|
import differenceInDays from 'date-fns/differenceInDays';
|
||||||
import Cookies from 'js-cookie';
|
import Cookies from 'js-cookie';
|
||||||
import { frontendURL } from '../../helper/URLHelper';
|
|
||||||
import {
|
import {
|
||||||
ANALYTICS_IDENTITY,
|
ANALYTICS_IDENTITY,
|
||||||
ANALYTICS_RESET,
|
ANALYTICS_RESET,
|
||||||
|
@ -17,14 +15,9 @@ export const setLoadingStatus = (state, status) => {
|
||||||
state.fetchAPIloadingStatus = status;
|
state.fetchAPIloadingStatus = status;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const setUser = (user, expiryDate, options = {}) => {
|
export const setUser = user => {
|
||||||
if (options && options.setUserInSDK) {
|
window.bus.$emit(CHATWOOT_SET_USER, { user });
|
||||||
window.bus.$emit(CHATWOOT_SET_USER, { user });
|
window.bus.$emit(ANALYTICS_IDENTITY, { user });
|
||||||
window.bus.$emit(ANALYTICS_IDENTITY, { user });
|
|
||||||
}
|
|
||||||
Cookies.set('user', user, {
|
|
||||||
expires: differenceInDays(expiryDate, new Date()),
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getHeaderExpiry = response =>
|
export const getHeaderExpiry = response =>
|
||||||
|
@ -32,13 +25,14 @@ export const getHeaderExpiry = response =>
|
||||||
|
|
||||||
export const setAuthCredentials = response => {
|
export const setAuthCredentials = response => {
|
||||||
const expiryDate = getHeaderExpiry(response);
|
const expiryDate = getHeaderExpiry(response);
|
||||||
Cookies.set('auth_data', response.headers, {
|
Cookies.set('cw_d_session_info', response.headers, {
|
||||||
expires: differenceInDays(expiryDate, new Date()),
|
expires: differenceInDays(expiryDate, new Date()),
|
||||||
});
|
});
|
||||||
setUser(response.data.data, expiryDate);
|
setUser(response.data.data, expiryDate);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const clearBrowserSessionCookies = () => {
|
export const clearBrowserSessionCookies = () => {
|
||||||
|
Cookies.remove('cw_d_session_info');
|
||||||
Cookies.remove('auth_data');
|
Cookies.remove('auth_data');
|
||||||
Cookies.remove('user');
|
Cookies.remove('user');
|
||||||
};
|
};
|
||||||
|
@ -48,7 +42,6 @@ export const clearCookiesOnLogout = () => {
|
||||||
window.bus.$emit(ANALYTICS_RESET);
|
window.bus.$emit(ANALYTICS_RESET);
|
||||||
clearBrowserSessionCookies();
|
clearBrowserSessionCookies();
|
||||||
const globalConfig = window.globalConfig || {};
|
const globalConfig = window.globalConfig || {};
|
||||||
const logoutRedirectLink =
|
const logoutRedirectLink = globalConfig.LOGOUT_REDIRECT_LINK || '/';
|
||||||
globalConfig.LOGOUT_REDIRECT_LINK || frontendURL('login');
|
|
||||||
window.location = logoutRedirectLink;
|
window.location = logoutRedirectLink;
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,14 +26,9 @@ import {
|
||||||
initOnEvents,
|
initOnEvents,
|
||||||
} from '../shared/helpers/AudioNotificationHelper';
|
} from '../shared/helpers/AudioNotificationHelper';
|
||||||
import { initFaviconSwitcher } from '../shared/helpers/faviconHelper';
|
import { initFaviconSwitcher } from '../shared/helpers/faviconHelper';
|
||||||
import router from '../dashboard/routes';
|
import router, { initalizeRouter } from '../dashboard/routes';
|
||||||
import store from '../dashboard/store';
|
import store from '../dashboard/store';
|
||||||
import vueActionCable from '../dashboard/helper/actionCable';
|
|
||||||
import constants from '../dashboard/constants';
|
import constants from '../dashboard/constants';
|
||||||
import {
|
|
||||||
verifyServiceWorkerExistence,
|
|
||||||
registerSubscription,
|
|
||||||
} from '../dashboard/helper/pushHelper';
|
|
||||||
import * as Sentry from '@sentry/vue';
|
import * as Sentry from '@sentry/vue';
|
||||||
import 'vue-easytable/libs/theme-default/index.css';
|
import 'vue-easytable/libs/theme-default/index.css';
|
||||||
import { Integrations } from '@sentry/tracing';
|
import { Integrations } from '@sentry/tracing';
|
||||||
|
@ -93,6 +88,7 @@ window.axios = createAxios(axios);
|
||||||
window.bus = new Vue();
|
window.bus = new Vue();
|
||||||
initializeChatwootEvents();
|
initializeChatwootEvents();
|
||||||
initializeAnalyticsEvents();
|
initializeAnalyticsEvents();
|
||||||
|
initalizeRouter();
|
||||||
|
|
||||||
window.onload = () => {
|
window.onload = () => {
|
||||||
window.WOOT = new Vue({
|
window.WOOT = new Vue({
|
||||||
|
@ -102,7 +98,6 @@ window.onload = () => {
|
||||||
components: { App },
|
components: { App },
|
||||||
template: '<App/>',
|
template: '<App/>',
|
||||||
}).$mount('#app');
|
}).$mount('#app');
|
||||||
vueActionCable.init();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const setupAudioListeners = () => {
|
const setupAudioListeners = () => {
|
||||||
|
@ -113,13 +108,6 @@ const setupAudioListeners = () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
window.addEventListener('load', () => {
|
window.addEventListener('load', () => {
|
||||||
verifyServiceWorkerExistence(registration =>
|
|
||||||
registration.pushManager.getSubscription().then(subscription => {
|
|
||||||
if (subscription) {
|
|
||||||
registerSubscription();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
window.playAudioAlert = () => {};
|
window.playAudioAlert = () => {};
|
||||||
initOnEvents.forEach(e => {
|
initOnEvents.forEach(e => {
|
||||||
document.addEventListener(e, setupAudioListeners, false);
|
document.addEventListener(e, setupAudioListeners, false);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue