fix: Allow users to login even if they have access to more than 15 accounts (#4475)

This commit is contained in:
Pranav Raj S 2022-04-14 20:54:26 +05:30 committed by GitHub
parent 80e5d6d7a0
commit 0319b78eac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 368 additions and 350 deletions

View file

@ -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;
}
}, },
}, },
}; };

View file

@ -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

View file

@ -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;
}, },

View file

@ -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,

View file

@ -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;

View file

@ -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;
}, },
}; };

View file

@ -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)
); );

View file

@ -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/');
}); });
}); });

View file

@ -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);

View file

@ -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;

View file

@ -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();
});
});

View file

@ -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,

View file

@ -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;

View file

@ -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);
}); });
}); });

View file

@ -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: {

View file

@ -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,
});
});
});
}); });

View file

@ -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',

View file

@ -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;
}; };

View file

@ -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);