Skip to content

Commit

Permalink
Merge pull request #1334 from betagouv/fix/1326-town-filter
Browse files Browse the repository at this point in the history
Town filter
  • Loading branch information
nmrgt authored Apr 29, 2021
2 parents 2a9e0ff + ec56252 commit cb8e040
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ import { ContextType, ForbiddenException } from '@ilos/common';
import { HasPermissionByScopeMiddleware } from './HasPermissionByScopeMiddleware';

const test = anyTest as TestInterface<{
mockConnectedUser: any;
mockSuperAdmin: any;
mockTerritoryAdmin: any;
mockCreateUserParameters: any;
mockAllStatsParams: any;
mockTownStatsParams: any;
contextFactory: Function;
middlewareConfig: any;
middlewareConfigUserCreate: any;
middlewareConfigTripStats: any;
middleware: HasPermissionByScopeMiddleware;
}>;

Expand All @@ -16,7 +20,7 @@ test.before((t) => {
return {
call: {
user: {
...t.context.mockConnectedUser,
...t.context.mockSuperAdmin,
...params,
},
},
Expand All @@ -26,15 +30,28 @@ test.before((t) => {
};
};

t.context.mockConnectedUser = {
t.context.mockSuperAdmin = {
_id: '1ab',
email: '[email protected]',
firstname: 'john',
lastname: 'schmidt',
phone: '0624857425',
group: 'registry',
role: 'admin',
permissions: ['user.create'],
permissions: ['registry.user.create'],
};

t.context.mockTerritoryAdmin = {
_id: 2,
email: '[email protected]',
firstname: 'john',
lastname: 'schmidt',
phone: '0624857425',
group: 'territories',
role: 'admin',
territory_id: 42,
permissions: ['territory.trip.stats'],
authorizedTerritories: [42, 43, 44, 45],
};

t.context.mockCreateUserParameters = {
Expand All @@ -43,26 +60,45 @@ test.before((t) => {
lastname: 'nelson',
phone: '+33622222233',
role: 'admin',
territory: 42,
territory_id: 42,
};

t.context.middlewareConfig = [
'user.create',
t.context.middlewareConfigUserCreate = [
'registry.user.create',
[
['territory.users.add', 'call.user.territory', 'territory'],
['operator.users.add', 'call.user.operator', 'operator'],
['territory.users.add', 'call.user.territory_id', 'territory_id'],
['operator.users.add', 'call.user.operator_id', 'operator_id'],
],
];

t.context.middlewareConfigTripStats = [
'registry.trip.stats',
[
['territory.trip.stats', 'call.user.authorizedTerritories', 'territory_id'],
['operator.trip.stats', 'call.user.operator_id', 'operator_id'],
],
];

t.context.mockAllStatsParams = {
date: { start: new Date('2020-01-01T00:00:00+0100') },
tz: 'Europe/Paris',
};

t.context.mockTownStatsParams = {
date: { start: new Date('2020-01-01T00:00:00+0100') },
territory_id: [43],
tz: 'Europe/Paris',
};

t.context.middleware = new HasPermissionByScopeMiddleware();
});

test('Middleware Scopetoself: has permission to create user', async (t) => {
const result = await t.context.middleware.process(
t.context.mockCreateUserParameters,
t.context.contextFactory({ permissions: ['user.create'] }),
t.context.contextFactory({ permissions: ['registry.user.create'] }),
() => 'next() called',
t.context.middlewareConfig,
t.context.middlewareConfigUserCreate,
);

t.is(result, 'next() called');
Expand All @@ -73,10 +109,10 @@ test('Middleware Scopetoself: has permission to create territory user', async (t
t.context.mockCreateUserParameters,
t.context.contextFactory({
permissions: ['territory.users.add'],
territory: t.context.mockCreateUserParameters.territory,
territory_id: t.context.mockCreateUserParameters.territory_id,
}),
() => 'next() called',
t.context.middlewareConfig,
t.context.middlewareConfigUserCreate,
);

t.is(result, 'next() called');
Expand All @@ -88,7 +124,7 @@ test('Middleware Scopetoself: territory admin - has no permission to create terr
t.context.mockCreateUserParameters,
t.context.contextFactory({ permissions: [], territory: t.context.mockCreateUserParameters.territory }),
() => {},
t.context.middlewareConfig,
t.context.middlewareConfigUserCreate,
),
{ instanceOf: ForbiddenException },
);
Expand All @@ -100,8 +136,61 @@ test('Middleware Scopetoself: registry admin - wrong territory', async (t) => {
t.context.mockCreateUserParameters,
t.context.contextFactory({ permissions: ['territory.users.add'], territory: 0 }),
() => {},
t.context.middlewareConfig,
t.context.middlewareConfigUserCreate,
),
{ instanceOf: ForbiddenException },
);
});

test('Middleware Scopetoself: super-admin can trip.stats', async (t) => {
const result = await t.context.middleware.process(
t.context.mockAllStatsParams,
t.context.contextFactory({ permissions: ['registry.trip.stats'] }),
() => 'next() called',
t.context.middlewareConfigTripStats,
);

t.is(result, 'next() called');
});

test('Middleware Scopetoself: super-admin can trip.stats with town filter', async (t) => {
const result = await t.context.middleware.process(
t.context.mockTownStatsParams,
t.context.contextFactory({ permissions: ['registry.trip.stats'] }),
() => 'next() called',
t.context.middlewareConfigTripStats,
);

t.is(result, 'next() called');
});

test('Middleware Scopetoself: territory-admin can trip.stats', async (t) => {
// mock territory_id being added by copy.from_context middleware
const params = { ...t.context.mockAllStatsParams, territory_id: t.context.mockTerritoryAdmin.territory_id };

const context = t.context.contextFactory(t.context.mockTerritoryAdmin);

const result = await t.context.middleware.process(
params,
context,
() => 'next() called',
t.context.middlewareConfigTripStats,
);

t.is(result, 'next() called');
});

test('Middleware Scopetoself: territory-admin can trip.stats w/ town filter', async (t) => {
// mock territory_id being added by copy.from_context middleware
const params = t.context.mockTownStatsParams;
const context = t.context.contextFactory(t.context.mockTerritoryAdmin);

const result = await t.context.middleware.process(
params,
context,
() => 'next() called',
t.context.middlewareConfigTripStats,
);

t.is(result, 'next() called');
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
InvalidParamsException,
ForbiddenException,
} from '@ilos/common';
import { get } from 'lodash';
import { get, includes } from 'lodash';
import { ConfiguredMiddleware } from '../interfaces';

/**
Expand Down Expand Up @@ -43,7 +43,7 @@ export class HasPermissionByScopeMiddleware implements MiddlewareInterface<HasPe
}
for (const [scopedPermission, contextPath, paramsPath] of permissionScopes) {
if (
get(context, contextPath, Symbol()) === get(params, paramsPath, Symbol()) &&
this.belongsTo(get(params, paramsPath, Symbol()), get(context, contextPath, Symbol())) &&
permissions.indexOf(scopedPermission) > -1
) {
return next(params, context);
Expand All @@ -52,6 +52,12 @@ export class HasPermissionByScopeMiddleware implements MiddlewareInterface<HasPe

throw new ForbiddenException('Invalid permissions');
}

private belongsTo(value: any | any[], list: any | any[]): boolean {
const val = Array.isArray(value) ? value : [value];
const lst = Array.isArray(list) ? list : [list];
return val.reduce((p, c) => p && includes(lst, c), true);
}
}

export type ScopeAndPermission = [string, string, string];
Expand Down
12 changes: 7 additions & 5 deletions api/services/trip/src/actions/ExportAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { get } from 'lodash';

import { Action } from '@ilos/core';
import { handler, ContextType, KernelInterfaceResolver, InvalidParamsException } from '@ilos/common';
import { copyGroupIdAndApplyGroupPermissionMiddlewares, validateDateMiddleware } from '@pdc/provider-middleware';
import { copyGroupIdFromContextMiddlewares, validateDateMiddleware } from '@pdc/provider-middleware';

import { TripRepositoryProviderInterfaceResolver } from '../interfaces';
import { handlerConfig, ParamsInterface, ResultInterface } from '../shared/trip/export.contract';
Expand All @@ -12,14 +12,16 @@ import {
ParamsInterface as BuildParamsInterface,
} from '../shared/trip/buildExport.contract';
import * as middlewareConfig from '../config/middlewares';
import { groupPermissionMiddlewaresHelper } from '../middleware/groupPermissionMiddlewaresHelper';

@handler({
...handlerConfig,
middlewares: [
...copyGroupIdAndApplyGroupPermissionMiddlewares({
territory: 'territory.trip.export',
operator: 'operator.trip.export',
registry: 'registry.trip.export',
...copyGroupIdFromContextMiddlewares(['territory_id', 'operator_id'], null, true),
...groupPermissionMiddlewaresHelper({
territory: 'territory.trip.stats',
operator: 'operator.trip.stats',
registry: 'registry.trip.stats',
}),
['validate', alias],
validateDateMiddleware({
Expand Down
6 changes: 4 additions & 2 deletions api/services/trip/src/actions/FinancialStatsAction.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import { Action } from '@ilos/core';
import { handler, ContextType } from '@ilos/common';
import { copyGroupIdAndApplyGroupPermissionMiddlewares, validateDateMiddleware } from '@pdc/provider-middleware';
import { copyGroupIdFromContextMiddlewares, validateDateMiddleware } from '@pdc/provider-middleware';

import { handlerConfig, ParamsInterface, ResultInterface } from '../shared/trip/financialStats.contract';
import { TripRepositoryProvider } from '../providers/TripRepositoryProvider';
import { alias } from '../shared/trip/stats.schema';
import { StatCacheRepositoryProviderInterfaceResolver } from '../interfaces/StatCacheRepositoryProviderInterface';
import * as middlewareConfig from '../config/middlewares';
import { groupPermissionMiddlewaresHelper } from '../middleware/groupPermissionMiddlewaresHelper';

@handler({
...handlerConfig,
middlewares: [
...copyGroupIdAndApplyGroupPermissionMiddlewares({
...copyGroupIdFromContextMiddlewares(['territory_id', 'operator_id'], null, true),
...groupPermissionMiddlewaresHelper({
territory: 'territory.trip.stats',
operator: 'operator.trip.stats',
registry: 'registry.trip.stats',
Expand Down
16 changes: 9 additions & 7 deletions api/services/trip/src/actions/ListAction.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
import { Action } from '@ilos/core';
import { handler, ContextType } from '@ilos/common';
import { get } from 'lodash';
import { copyGroupIdAndApplyGroupPermissionMiddlewares, validateDateMiddleware } from '@pdc/provider-middleware';
import { copyGroupIdFromContextMiddlewares, validateDateMiddleware } from '@pdc/provider-middleware';

import { handlerConfig, ParamsInterface, ResultInterface } from '../shared/trip/list.contract';
import { TripRepositoryProvider } from '../providers/TripRepositoryProvider';
import { alias } from '../shared/trip/list.schema';
import * as middlewareConfig from '../config/middlewares';
import { TripRepositoryProvider } from '../providers/TripRepositoryProvider';
import { handlerConfig, ParamsInterface, ResultInterface } from '../shared/trip/list.contract';
import { groupPermissionMiddlewaresHelper } from '../middleware/groupPermissionMiddlewaresHelper';

// TODO
@handler({
...handlerConfig,
middlewares: [
...copyGroupIdAndApplyGroupPermissionMiddlewares({
territory: 'territory.trip.list',
operator: 'operator.trip.list',
registry: 'registry.trip.list',
...copyGroupIdFromContextMiddlewares(['territory_id', 'operator_id'], null, true),
...groupPermissionMiddlewaresHelper({
territory: 'territory.trip.stats',
operator: 'operator.trip.stats',
registry: 'registry.trip.stats',
}),
['validate', alias],
validateDateMiddleware({
Expand Down
16 changes: 9 additions & 7 deletions api/services/trip/src/actions/SearchCountAction.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import { Action } from '@ilos/core';
import { handler, ContextType, KernelInterfaceResolver } from '@ilos/common';
import { copyGroupIdAndApplyGroupPermissionMiddlewares, validateDateMiddleware } from '@pdc/provider-middleware';
import { copyGroupIdFromContextMiddlewares, validateDateMiddleware } from '@pdc/provider-middleware';

import { handlerConfig, ParamsInterface, ResultInterface } from '../shared/trip/searchcount.contract';
import { TripRepositoryProvider } from '../providers/TripRepositoryProvider';
import { alias } from '../shared/trip/searchcount.schema';
import * as middlewareConfig from '../config/middlewares';
import { TripRepositoryProvider } from '../providers/TripRepositoryProvider';
import { handlerConfig, ParamsInterface, ResultInterface } from '../shared/trip/searchcount.contract';
import { groupPermissionMiddlewaresHelper } from '../middleware/groupPermissionMiddlewaresHelper';

@handler({
...handlerConfig,
middlewares: [
...copyGroupIdAndApplyGroupPermissionMiddlewares({
territory: 'territory.trip.list',
operator: 'operator.trip.list',
registry: 'registry.trip.list',
...copyGroupIdFromContextMiddlewares(['territory_id', 'operator_id'], null, true),
...groupPermissionMiddlewaresHelper({
territory: 'territory.trip.stats',
operator: 'operator.trip.stats',
registry: 'registry.trip.stats',
}),
['validate', alias],
validateDateMiddleware({
Expand Down
12 changes: 7 additions & 5 deletions api/services/trip/src/actions/StatsAction.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import { Action } from '@ilos/core';
import { handler, ContextType } from '@ilos/common';
import { copyGroupIdAndApplyGroupPermissionMiddlewares, validateDateMiddleware } from '@pdc/provider-middleware';
import { copyGroupIdFromContextMiddlewares, validateDateMiddleware } from '@pdc/provider-middleware';

import { handlerConfig, ParamsInterface, ResultInterface } from '../shared/trip/stats.contract';
import { TripRepositoryProvider } from '../providers/TripRepositoryProvider';
import { alias } from '../shared/trip/stats.schema';
import { StatCacheRepositoryProviderInterfaceResolver } from '../interfaces/StatCacheRepositoryProviderInterface';
import * as middlewareConfig from '../config/middlewares';
import { TripRepositoryProvider } from '../providers/TripRepositoryProvider';
import { handlerConfig, ParamsInterface, ResultInterface } from '../shared/trip/stats.contract';
import { groupPermissionMiddlewaresHelper } from '../middleware/groupPermissionMiddlewaresHelper';
import { StatCacheRepositoryProviderInterfaceResolver } from '../interfaces/StatCacheRepositoryProviderInterface';

@handler({
...handlerConfig,
middlewares: [
...copyGroupIdAndApplyGroupPermissionMiddlewares({
...copyGroupIdFromContextMiddlewares(['territory_id', 'operator_id'], null, true),
...groupPermissionMiddlewaresHelper({
territory: 'territory.trip.stats',
operator: 'operator.trip.stats',
registry: 'registry.trip.stats',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import {
hasPermissionByScopeMiddleware,
HasPermissionByScopeMiddlewareParams,
ListOfConfiguredMiddlewares,
} from '@pdc/provider-middleware';

//
// Custom groupPermissionMiddlewares() using authorizedTerritories in place of territory_id
//
export function groupPermissionMiddlewaresHelper(groups: {
territory: string;
operator: string;
registry: string;
}): ListOfConfiguredMiddlewares<HasPermissionByScopeMiddlewareParams> {
const middlewareParameters = [];
const { territory: territoryPermission, operator: operatorPermission, registry: registryPermission } = groups;

middlewareParameters.push([territoryPermission, 'call.user.authorizedTerritories', 'territory_id']);
middlewareParameters.push([operatorPermission, 'call.user.operator_id', 'operator_id']);

return [hasPermissionByScopeMiddleware(registryPermission, ...middlewareParameters)];
}

0 comments on commit cb8e040

Please sign in to comment.