chore: Allow super admin to suspend an account (#5174)
This commit is contained in:
51
app/javascript/dashboard/helper/routeHelpers.js
Normal file
51
app/javascript/dashboard/helper/routeHelpers.js
Normal file
@@ -0,0 +1,51 @@
|
||||
export const getCurrentAccount = ({ accounts } = {}, accountId) => {
|
||||
return accounts.find(account => account.id === accountId);
|
||||
};
|
||||
|
||||
export const getUserRole = ({ accounts } = {}, accountId) => {
|
||||
const currentAccount = getCurrentAccount({ accounts }, accountId) || {};
|
||||
return currentAccount.role || null;
|
||||
};
|
||||
|
||||
export const routeIsAccessibleFor = (route, role, roleWiseRoutes) => {
|
||||
return roleWiseRoutes[role].includes(route);
|
||||
};
|
||||
|
||||
const validateActiveAccountRoutes = (to, user, roleWiseRoutes) => {
|
||||
// If the current account is active, then check for the route permissions
|
||||
const accountDashboardURL = `accounts/${to.params.accountId}/dashboard`;
|
||||
|
||||
// If the user is trying to access suspended route, redirect them to dashboard
|
||||
if (to.name === 'account_suspended') {
|
||||
return accountDashboardURL;
|
||||
}
|
||||
|
||||
const userRole = getUserRole(user, Number(to.params.accountId));
|
||||
const isAccessible = routeIsAccessibleFor(to.name, userRole, roleWiseRoutes);
|
||||
// If the route is not accessible for the user, return to dashboard screen
|
||||
return isAccessible ? null : accountDashboardURL;
|
||||
};
|
||||
|
||||
export const validateLoggedInRoutes = (to, user, roleWiseRoutes) => {
|
||||
const currentAccount = getCurrentAccount(user, Number(to.params.accountId));
|
||||
|
||||
// If current account is missing, either user does not have
|
||||
// access to the account or the account is deleted, return to login screen
|
||||
if (!currentAccount) {
|
||||
return `app/login`;
|
||||
}
|
||||
|
||||
const isCurrentAccountActive = currentAccount.status === 'active';
|
||||
|
||||
if (isCurrentAccountActive) {
|
||||
return validateActiveAccountRoutes(to, user, roleWiseRoutes);
|
||||
}
|
||||
|
||||
// If the current account is not active, then redirect the user to the suspended screen
|
||||
if (to.name !== 'account_suspended') {
|
||||
return `accounts/${to.params.accountId}/suspended`;
|
||||
}
|
||||
|
||||
// Proceed to the route if none of the above conditions are met
|
||||
return null;
|
||||
};
|
||||
96
app/javascript/dashboard/helper/specs/routeHelpers.spec.js
Normal file
96
app/javascript/dashboard/helper/specs/routeHelpers.spec.js
Normal file
@@ -0,0 +1,96 @@
|
||||
import {
|
||||
getCurrentAccount,
|
||||
getUserRole,
|
||||
routeIsAccessibleFor,
|
||||
validateLoggedInRoutes,
|
||||
} from '../routeHelpers';
|
||||
|
||||
describe('#getCurrentAccount', () => {
|
||||
it('should return the current account', () => {
|
||||
expect(getCurrentAccount({ accounts: [{ id: 1 }] }, 1)).toEqual({ id: 1 });
|
||||
expect(getCurrentAccount({ accounts: [] }, 1)).toEqual(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getUserRole', () => {
|
||||
it('should return the current role', () => {
|
||||
expect(
|
||||
getUserRole({ accounts: [{ id: 1, role: 'administrator' }] }, 1)
|
||||
).toEqual('administrator');
|
||||
expect(getUserRole({ accounts: [] }, 1)).toEqual(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#routeIsAccessibleFor', () => {
|
||||
it('should return the correct access', () => {
|
||||
const roleWiseRoutes = { agent: ['conversations'], admin: ['billing'] };
|
||||
expect(routeIsAccessibleFor('billing', 'agent', roleWiseRoutes)).toEqual(
|
||||
false
|
||||
);
|
||||
expect(routeIsAccessibleFor('billing', 'admin', roleWiseRoutes)).toEqual(
|
||||
true
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#validateLoggedInRoutes', () => {
|
||||
describe('when account access is missing', () => {
|
||||
it('should return the login route', () => {
|
||||
expect(
|
||||
validateLoggedInRoutes(
|
||||
{ params: { accountId: 1 } },
|
||||
{ accounts: [] },
|
||||
{}
|
||||
)
|
||||
).toEqual(`app/login`);
|
||||
});
|
||||
});
|
||||
describe('when account access is available', () => {
|
||||
describe('when account is suspended', () => {
|
||||
it('return suspended route', () => {
|
||||
expect(
|
||||
validateLoggedInRoutes(
|
||||
{ name: 'conversations', params: { accountId: 1 } },
|
||||
{ accounts: [{ id: 1, role: 'agent', status: 'suspended' }] },
|
||||
{ agent: ['conversations'] }
|
||||
)
|
||||
).toEqual(`accounts/1/suspended`);
|
||||
});
|
||||
});
|
||||
describe('when account is active', () => {
|
||||
describe('when route is accessible', () => {
|
||||
it('returns null (no action required)', () => {
|
||||
expect(
|
||||
validateLoggedInRoutes(
|
||||
{ name: 'conversations', params: { accountId: 1 } },
|
||||
{ accounts: [{ id: 1, role: 'agent', status: 'active' }] },
|
||||
{ agent: ['conversations'] }
|
||||
)
|
||||
).toEqual(null);
|
||||
});
|
||||
});
|
||||
describe('when route is not accessible', () => {
|
||||
it('returns dashboard url', () => {
|
||||
expect(
|
||||
validateLoggedInRoutes(
|
||||
{ name: 'conversations', params: { accountId: 1 } },
|
||||
{ accounts: [{ id: 1, role: 'agent', status: 'active' }] },
|
||||
{ admin: ['conversations'], agent: [] }
|
||||
)
|
||||
).toEqual(`accounts/1/dashboard`);
|
||||
});
|
||||
});
|
||||
describe('when route is suspended route', () => {
|
||||
it('returns dashboard url', () => {
|
||||
expect(
|
||||
validateLoggedInRoutes(
|
||||
{ name: 'account_suspended', params: { accountId: 1 } },
|
||||
{ accounts: [{ id: 1, role: 'agent', status: 'active' }] },
|
||||
{ agent: ['account_suspended'] }
|
||||
)
|
||||
).toEqual(`accounts/1/dashboard`);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -120,7 +120,11 @@
|
||||
"APP_GLOBAL": {
|
||||
"TRIAL_MESSAGE": "days trial remaining.",
|
||||
"TRAIL_BUTTON": "Buy Now",
|
||||
"DELETED_USER": "Deleted User"
|
||||
"DELETED_USER": "Deleted User",
|
||||
"ACCOUNT_SUSPENDED": {
|
||||
"TITLE": "Account Suspended",
|
||||
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
|
||||
}
|
||||
},
|
||||
"COMPONENTS": {
|
||||
"CODE": {
|
||||
@@ -199,7 +203,7 @@
|
||||
},
|
||||
"BILLING_SETTINGS": {
|
||||
"TITLE": "Billing",
|
||||
"CURRENT_PLAN" : {
|
||||
"CURRENT_PLAN": {
|
||||
"TITLE": "Current Plan",
|
||||
"PLAN_NOTE": "You are currently subscribed to the **%{plan}** plan with **%{quantity}** licenses"
|
||||
},
|
||||
|
||||
@@ -6,6 +6,8 @@ import { routes as notificationRoutes } from './notifications/routes';
|
||||
import { frontendURL } from '../../helper/URLHelper';
|
||||
import helpcenterRoutes from './helpcenter/helpcenter.routes';
|
||||
|
||||
const Suspended = () => import('./suspended/Index');
|
||||
|
||||
export default {
|
||||
routes: [
|
||||
...helpcenterRoutes.routes,
|
||||
@@ -19,5 +21,11 @@ export default {
|
||||
...notificationRoutes,
|
||||
],
|
||||
},
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/suspended'),
|
||||
name: 'account_suspended',
|
||||
roles: ['administrator', 'agent'],
|
||||
component: Suspended,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<template>
|
||||
<div class="suspended-page">
|
||||
<empty-state
|
||||
:title="$t('APP_GLOBAL.ACCOUNT_SUSPENDED.TITLE')"
|
||||
:message="$t('APP_GLOBAL.ACCOUNT_SUSPENDED.MESSAGE')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import EmptyState from 'dashboard/components/widgets/EmptyState';
|
||||
export default {
|
||||
components: { EmptyState },
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.suspended-page {
|
||||
align-items: center;
|
||||
background: var(--s-50);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -6,6 +6,7 @@ import authRoute from './auth/auth.routes';
|
||||
import dashboard from './dashboard/dashboard.routes';
|
||||
import login from './login/login.routes';
|
||||
import store from '../store';
|
||||
import { validateLoggedInRoutes } from '../helper/routeHelpers';
|
||||
|
||||
const routes = [...login.routes, ...dashboard.routes, ...authRoute.routes];
|
||||
|
||||
@@ -14,11 +15,6 @@ window.roleWiseRoutes = {
|
||||
administrator: [],
|
||||
};
|
||||
|
||||
const getUserRole = ({ accounts } = {}, accountId) => {
|
||||
const currentAccount = accounts.find(account => account.id === accountId);
|
||||
return currentAccount ? currentAccount.role : null;
|
||||
};
|
||||
|
||||
// generateRoleWiseRoute - updates window object with agent/admin route
|
||||
const generateRoleWiseRoute = route => {
|
||||
route.forEach(element => {
|
||||
@@ -47,10 +43,6 @@ const authIgnoreRoutes = [
|
||||
'auth_password_edit',
|
||||
];
|
||||
|
||||
function routeIsAccessibleFor(route, role) {
|
||||
return window.roleWiseRoutes[role].includes(route);
|
||||
}
|
||||
|
||||
const routeValidators = [
|
||||
{
|
||||
protected: false,
|
||||
@@ -68,12 +60,8 @@ const routeValidators = [
|
||||
{
|
||||
protected: true,
|
||||
loggedIn: true,
|
||||
handler: (to, getters) => {
|
||||
const user = getters.getCurrentUser;
|
||||
const userRole = getUserRole(user, Number(to.params.accountId));
|
||||
const isAccessible = routeIsAccessibleFor(to.name, userRole);
|
||||
return isAccessible ? null : `accounts/${to.params.accountId}/dashboard`;
|
||||
},
|
||||
handler: (to, getters) =>
|
||||
validateLoggedInRoutes(to, getters.getCurrentUser, window.roleWiseRoutes),
|
||||
},
|
||||
{
|
||||
protected: false,
|
||||
|
||||
@@ -26,7 +26,7 @@ describe('#validateAuthenticateRoutePermission', () => {
|
||||
getCurrentUser: {
|
||||
account_id: 1,
|
||||
id: 1,
|
||||
accounts: [{ id: 1, role: 'admin' }],
|
||||
accounts: [{ id: 1, role: 'admin', status: 'active' }],
|
||||
},
|
||||
};
|
||||
validateAuthenticateRoutePermission(to, from, next, { getters });
|
||||
@@ -72,7 +72,7 @@ describe('#validateAuthenticateRoutePermission', () => {
|
||||
getCurrentUser: {
|
||||
account_id: 1,
|
||||
id: 1,
|
||||
accounts: [{ id: 1, role: 'agent' }],
|
||||
accounts: [{ id: 1, role: 'agent', status: 'active' }],
|
||||
},
|
||||
};
|
||||
validateAuthenticateRoutePermission(to, from, next, { getters });
|
||||
@@ -90,7 +90,7 @@ describe('#validateAuthenticateRoutePermission', () => {
|
||||
getCurrentUser: {
|
||||
account_id: 1,
|
||||
id: 1,
|
||||
accounts: [{ id: 1, role: 'agent' }],
|
||||
accounts: [{ id: 1, role: 'agent', status: 'active' }],
|
||||
},
|
||||
};
|
||||
validateAuthenticateRoutePermission(to, from, next, { getters });
|
||||
|
||||
Reference in New Issue
Block a user