💄(frontend) redirect home according to abilities
We try to detect the landing page according to user permissions (abilities) instead of just the configuration setting. This will be improved when the homepage is developed
This commit is contained in:
@@ -10,6 +10,7 @@ and this project adheres to
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- 💄(frontend) redirect home according to abilities #588
|
||||||
- ✨(maildomain_access) add API endpoint to search users #508
|
- ✨(maildomain_access) add API endpoint to search users #508
|
||||||
|
|
||||||
## [1.8.0] - 2024-12-12
|
## [1.8.0] - 2024-12-12
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import '@testing-library/jest-dom';
|
|||||||
import { render } from '@testing-library/react';
|
import { render } from '@testing-library/react';
|
||||||
|
|
||||||
import { useConfigStore } from '@/core';
|
import { useConfigStore } from '@/core';
|
||||||
|
import { useAuthStore } from '@/core/auth';
|
||||||
import { AppWrapper } from '@/tests/utils';
|
import { AppWrapper } from '@/tests/utils';
|
||||||
|
|
||||||
import Page from '../pages';
|
import Page from '../pages';
|
||||||
@@ -20,6 +21,20 @@ describe('Page', () => {
|
|||||||
afterEach(() => jest.clearAllMocks());
|
afterEach(() => jest.clearAllMocks());
|
||||||
|
|
||||||
it('checks Page rendering with team feature', () => {
|
it('checks Page rendering with team feature', () => {
|
||||||
|
useAuthStore.setState({
|
||||||
|
authenticated: true,
|
||||||
|
userData: {
|
||||||
|
id: '1',
|
||||||
|
email: 'test@example.com',
|
||||||
|
name: 'Test User',
|
||||||
|
abilities: {
|
||||||
|
contacts: { can_view: false },
|
||||||
|
teams: { can_view: false },
|
||||||
|
mailboxes: { can_view: false },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
useConfigStore.setState({
|
useConfigStore.setState({
|
||||||
config: {
|
config: {
|
||||||
RELEASE: '1.0.0',
|
RELEASE: '1.0.0',
|
||||||
@@ -35,6 +50,20 @@ describe('Page', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('checks Page rendering without team feature', () => {
|
it('checks Page rendering without team feature', () => {
|
||||||
|
useAuthStore.setState({
|
||||||
|
authenticated: true,
|
||||||
|
userData: {
|
||||||
|
id: '1',
|
||||||
|
email: 'test@example.com',
|
||||||
|
name: 'Test User',
|
||||||
|
abilities: {
|
||||||
|
contacts: { can_view: false },
|
||||||
|
teams: { can_view: false },
|
||||||
|
mailboxes: { can_view: false },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
useConfigStore.setState({
|
useConfigStore.setState({
|
||||||
config: {
|
config: {
|
||||||
RELEASE: '1.0.0',
|
RELEASE: '1.0.0',
|
||||||
@@ -48,4 +77,62 @@ describe('Page', () => {
|
|||||||
|
|
||||||
expect(mockedPush).toHaveBeenCalledWith('/mail-domains/');
|
expect(mockedPush).toHaveBeenCalledWith('/mail-domains/');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('checks Page rendering with team permission', () => {
|
||||||
|
useAuthStore.setState({
|
||||||
|
authenticated: true,
|
||||||
|
userData: {
|
||||||
|
id: '1',
|
||||||
|
email: 'test@example.com',
|
||||||
|
name: 'Test User',
|
||||||
|
abilities: {
|
||||||
|
contacts: { can_view: false },
|
||||||
|
teams: { can_view: true },
|
||||||
|
mailboxes: { can_view: false },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
useConfigStore.setState({
|
||||||
|
config: {
|
||||||
|
RELEASE: '1.0.0',
|
||||||
|
COMMIT: 'NA',
|
||||||
|
FEATURES: { TEAMS_DISPLAY: false },
|
||||||
|
LANGUAGES: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
render(<Page />, { wrapper: AppWrapper });
|
||||||
|
|
||||||
|
expect(mockedPush).toHaveBeenCalledWith('/teams/');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('checks Page rendering with mailbox permission', () => {
|
||||||
|
useAuthStore.setState({
|
||||||
|
authenticated: true,
|
||||||
|
userData: {
|
||||||
|
id: '1',
|
||||||
|
email: 'test@example.com',
|
||||||
|
name: 'Test User',
|
||||||
|
abilities: {
|
||||||
|
contacts: { can_view: false },
|
||||||
|
teams: { can_view: false },
|
||||||
|
mailboxes: { can_view: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
useConfigStore.setState({
|
||||||
|
config: {
|
||||||
|
RELEASE: '1.0.0',
|
||||||
|
COMMIT: 'NA',
|
||||||
|
FEATURES: { TEAMS_DISPLAY: true },
|
||||||
|
LANGUAGES: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
render(<Page />, { wrapper: AppWrapper });
|
||||||
|
|
||||||
|
expect(mockedPush).toHaveBeenCalledWith('/mail-domains/');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,16 +1,36 @@
|
|||||||
import { useRouter as useNavigate } from 'next/navigation';
|
import { useRouter as useNavigate } from 'next/navigation';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
import { useAuthStore } from '@/core/auth';
|
||||||
import { useConfigStore } from '@/core/config';
|
import { useConfigStore } from '@/core/config';
|
||||||
import { NextPageWithLayout } from '@/types/next';
|
import { NextPageWithLayout } from '@/types/next';
|
||||||
|
|
||||||
const Page: NextPageWithLayout = () => {
|
const Page: NextPageWithLayout = () => {
|
||||||
const { config } = useConfigStore();
|
const { config } = useConfigStore();
|
||||||
|
const { userData } = useAuthStore();
|
||||||
const router = useNavigate();
|
const router = useNavigate();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!userData) {
|
||||||
|
router.push('/authenticate/');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. The user can see teams
|
||||||
|
if (userData.abilities?.teams?.can_view) {
|
||||||
|
router.push('/teams/');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. The user can see mailboxes
|
||||||
|
if (userData.abilities?.mailboxes?.can_view) {
|
||||||
|
router.push('/mail-domains/');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to the default route according to global config
|
||||||
router.push(config?.FEATURES.TEAMS_DISPLAY ? '/teams/' : '/mail-domains/');
|
router.push(config?.FEATURES.TEAMS_DISPLAY ? '/teams/' : '/mail-domains/');
|
||||||
}, [config?.FEATURES.TEAMS_DISPLAY, router]);
|
}, [config?.FEATURES.TEAMS_DISPLAY, userData, router]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -32,14 +32,40 @@ test.describe('Config', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('it checks that the config can deactivate the feature "teams"', async ({
|
test('it checks that the user abilities display mail domains', async ({
|
||||||
|
page,
|
||||||
|
browserName,
|
||||||
|
}) => {
|
||||||
|
await page.goto('/');
|
||||||
|
await keyCloakSignIn(page, browserName, 'mail-member');
|
||||||
|
|
||||||
|
await expect(page.locator('menu')).toBeHidden();
|
||||||
|
|
||||||
|
await expect(page.getByText('Mail Domains')).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('it checks that the user abilities display teams', async ({
|
||||||
page,
|
page,
|
||||||
browserName,
|
browserName,
|
||||||
}) => {
|
}) => {
|
||||||
await page.goto('/');
|
await page.goto('/');
|
||||||
// Login with a user who has the visibility on the groups
|
|
||||||
await keyCloakSignIn(page, browserName, 'team-member');
|
await keyCloakSignIn(page, browserName, 'team-member');
|
||||||
|
|
||||||
|
await expect(page.locator('menu')).toBeHidden();
|
||||||
|
|
||||||
|
await expect(page.getByText('Groups')).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('it checks that the config does not deactivate the feature "teams"', async ({
|
||||||
|
page,
|
||||||
|
browserName,
|
||||||
|
}) => {
|
||||||
|
await page.goto('/');
|
||||||
|
// Login with a user who has the visibility on the groups should see groups
|
||||||
|
// It's now the backend that decides if the user can see the group menu and they
|
||||||
|
// should be redirected to the groups page in such case
|
||||||
|
await keyCloakSignIn(page, browserName, 'team-administrator');
|
||||||
|
|
||||||
await page.route('**/api/v1.0/config/', async (route) => {
|
await page.route('**/api/v1.0/config/', async (route) => {
|
||||||
const request = route.request();
|
const request = route.request();
|
||||||
if (request.method().includes('GET')) {
|
if (request.method().includes('GET')) {
|
||||||
@@ -59,12 +85,6 @@ test.describe('Config', () => {
|
|||||||
|
|
||||||
await expect(page.locator('menu')).toBeHidden();
|
await expect(page.locator('menu')).toBeHidden();
|
||||||
|
|
||||||
await expect(
|
await expect(page.getByText('Groups')).toBeVisible();
|
||||||
page.getByRole('button', {
|
|
||||||
name: 'Create a new team',
|
|
||||||
}),
|
|
||||||
).toBeHidden();
|
|
||||||
|
|
||||||
await expect(page.getByText('Mail Domains')).toBeVisible();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -75,7 +75,11 @@ test.describe('Mail domains', () => {
|
|||||||
test.describe('checks all the elements are visible', () => {
|
test.describe('checks all the elements are visible', () => {
|
||||||
test.beforeEach(async ({ page, browserName }) => {
|
test.beforeEach(async ({ page, browserName }) => {
|
||||||
await page.goto('/');
|
await page.goto('/');
|
||||||
await keyCloakSignIn(page, browserName, 'mail-member');
|
// The user is a team administrator, so they land on the team page
|
||||||
|
// This allows to prevent the redirection to the mail domains page
|
||||||
|
// to make the '/api/v1.0/mail-domains/?page=1&ordering=created_at'
|
||||||
|
// query at login, which will be cached and not called afterward in tests.
|
||||||
|
await keyCloakSignIn(page, browserName, 'team-administrator-mail-member');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('checks the sort button', async ({ page }) => {
|
test('checks the sort button', async ({ page }) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user