Skip to content

Commit

Permalink
Merge pull request #724 from rocket-admin/backend_actions_rework
Browse files Browse the repository at this point in the history
refactor: Add validation for action method in create and update actio…
  • Loading branch information
Artuomka authored Jul 4, 2024
2 parents 46f7ced + 61912c3 commit c791ba7
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ import { SentryInterceptor } from '../../../interceptors/sentry.interceptor.js';
import { ConnectionEditGuard } from '../../../guards/connection-edit.guard.js';
import { UseCaseType } from '../../../common/data-injection.tokens.js';
import { SlugUuid } from '../../../decorators/slug-uuid.decorator.js';
import { CreateTableActionRuleBodyDTO } from './application/dto/create-action-rules-with-actions-and-events-body.dto.js';
import {
CreateActionEventDTO,
CreateTableActionRuleBodyDTO,
} from './application/dto/create-action-rules-with-actions-and-events-body.dto.js';
import { InTransactionEnum } from '../../../enums/in-transaction.enum.js';
import { CreateActionRuleDS } from './application/data-structures/create-action-rules.ds.js';
import { UserId } from '../../../decorators/user-id.decorator.js';
Expand All @@ -42,6 +45,8 @@ import { ActivatedTableActionsDTO } from './application/dto/activated-table-acti
import { ActivateEventActionsDS } from './application/data-structures/activate-rule-actions.ds.js';
import { Messages } from '../../../exceptions/text/messages.js';
import { FoundTableActionRulesRoDTO } from './application/dto/found-table-action-rules.ro.dto.js';
import { validateStringWithEnum } from '../../../helpers/validators/validate-string-with-enum.js';
import { TableActionEventEnum } from '../../../enums/table-action-event-enum.js';

@UseInterceptors(SentryInterceptor)
@Controller()
Expand Down Expand Up @@ -106,6 +111,7 @@ export class ActionRulesController {
action_emails: action.emails,
})),
};
this.validateEventsDataOrThrowException(tableRuleData.events);
return await this.createTableActionRuleUseCase.execute(inputData, InTransactionEnum.ON);
}

Expand Down Expand Up @@ -219,6 +225,7 @@ export class ActionRulesController {
action_id: action.id,
})),
};
this.validateEventsDataOrThrowException(tableRuleData.events);
return await this.updateTableActionRuleUseCase.execute(inputData, InTransactionEnum.ON);
}

Expand Down Expand Up @@ -258,4 +265,12 @@ export class ActionRulesController {
};
return await this.activateTableActionsInRuleUseCase.execute(inputData);
}

private validateEventsDataOrThrowException(createEventsData: Array<CreateActionEventDTO>) {
createEventsData.forEach(({ event }) => {
if (!validateStringWithEnum(event, TableActionEventEnum)) {
throw new BadRequestException(Messages.INVALID_EVENT_TYPE(event));
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { ValidationHelper } from '../../../../helpers/validators/validation-help
import { buildTableActionWithRule } from '../../table-actions-module/utils/build-table-action-with-rule.util.js';
import { buildActionEventWithRule } from '../../table-action-events-module/utils/build-action-event-with-rule.util.js';
import { buildFoundActionRulesWithActionsAndEventsDTO } from '../utils/build-found-action-rules-with-actions-and-events-dto.util.js';
import { validateStringWithEnum } from '../../../../helpers/validators/validate-string-with-enum.js';

@Injectable({ scope: Scope.REQUEST })
export class CreateActionRuleUseCase
Expand Down Expand Up @@ -114,6 +115,9 @@ export class CreateActionRuleUseCase
throw new BadRequestException(Messages.SLACK_URL_MISSING);
}
}
if (!validateStringWithEnum(action.action_method, TableActionMethodEnum)) {
throw new BadRequestException(Messages.INVALID_ACTION_METHOD(action.action_method));
}
if (action.action_method === TableActionMethodEnum.URL) {
if (process.env.NODE_ENV === 'test') {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { CreateTableActionData } from '../application/data-structures/create-act
import { buildTableActionWithRule } from '../../table-actions-module/utils/build-table-action-with-rule.util.js';
import { buildActionEventWithRule } from '../../table-action-events-module/utils/build-action-event-with-rule.util.js';
import { buildFoundActionRulesWithActionsAndEventsDTO } from '../utils/build-found-action-rules-with-actions-and-events-dto.util.js';
import { validateStringWithEnum } from '../../../../helpers/validators/validate-string-with-enum.js';

@Injectable({ scope: Scope.REQUEST })
export class UpdateRuleUseCase
Expand Down Expand Up @@ -177,6 +178,11 @@ export class UpdateRuleUseCase
throw new BadRequestException(Messages.SLACK_URL_MISSING);
}
}

if (!validateStringWithEnum(action.action_method, TableActionMethodEnum)) {
throw new BadRequestException(Messages.INVALID_ACTION_METHOD(action.action_method));
}

if (action.action_method === TableActionMethodEnum.URL) {
if (!action.action_url || !ValidationHelper.isValidUrl(action.action_url)) {
throw new BadRequestException(Messages.URL_INVALID);
Expand Down
6 changes: 6 additions & 0 deletions backend/src/exceptions/text/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import { toPrettyErrorsMsg } from '../../helpers/index.js';
import { enumToString } from '../../helpers/enum-to-string.js';
import { UserRoleEnum } from '../../entities/user/enums/user-role.enum.js';
import { ConnectionTypesEnum } from '@rocketadmin/shared-code/dist/src/data-access-layer/shared/enums/connection-types-enum.js';
import { TableActionMethodEnum } from '../../enums/table-action-method-enum.js';
import { TableActionEventEnum } from '../../enums/table-action-event-enum.js';
export const Messages = {
ACCOUNT_SUSPENDED:
'Your account has been suspended. Please reach out to your company administrator for assistance or contact our support team for further help',
Expand Down Expand Up @@ -333,4 +335,8 @@ export const Messages = {
NOTHING_TO_REVOKE: `Nothing to revoke`,
NO_USERS_FOUND_TO_UPDATE_ROLES: `No users found to update roles`,
USER_ROLES_UPDATE_FAILED: `Failed to update user roles`,
INVALID_ACTION_METHOD: (method: string) =>
`Invalid action method ${method}, supported methods are ${enumToString(TableActionMethodEnum)}`,
INVALID_EVENT_TYPE: (type: string) =>
`Invalid event type ${type}, supported types are ${enumToString(TableActionEventEnum)}`,
};
118 changes: 117 additions & 1 deletion backend/test/ava-tests/saas-tests/action-rules-e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,123 @@ test(`${currentTest} should return created table rule with action and events`, a
t.deepEqual(createdSingleAction.emails, []);
});

test(`${currentTest} throw validation exceptions when create dto includes null values`, async (t) => {
const { token } = await registerUserAndReturnUserInfo(app);
const createConnectionResult = await request(app.getHttpServer())
.post('/connection')
.send(newConnection)
.set('Cookie', token)
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');

const createConnectionRO = JSON.parse(createConnectionResult.text);
t.is(createConnectionResult.status, 201);

const tableRuleDTO: CreateTableActionRuleBodyDTO = {
title: 'Test rule',
table_name: testTableName,
events: [
null,
{
event: TableActionEventEnum.ADD_ROW,
title: undefined,
icon: null,
require_confirmation: true,
},
],
table_actions: [
{
type: TableActionTypeEnum.multiple,
url: faker.internet.url(),
method: 'wrong-method' as any,
slack_url: undefined,
emails: [faker.internet.email()],
},
{
type: TableActionTypeEnum.single,
url: undefined,
method: TableActionMethodEnum.SLACK,
slack_url: faker.internet.url(),
emails: undefined,
},
null,
],
};

const createTableRuleResult = await request(app.getHttpServer())
.post(`/action/rule/${createConnectionRO.id}`)
.send(tableRuleDTO)
.set('Cookie', token)
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');

const createTableRuleRO = JSON.parse(createTableRuleResult.text);
console.log('🚀 ~ test ~ createTableRuleRO:', createTableRuleRO);
t.is(createTableRuleResult.status, 400);
const { message } = createTableRuleRO;
t.truthy(message);
t.truthy(message.includes('each value in table_actions must be an object'));
t.truthy(message.includes('each value in events must be an object'));
t.truthy(message.includes('each value in events should not be empty'));
t.truthy(message.includes('each value in table_actions should not be empty'));
});

test(`${currentTest} throw validation exceptions when create dto includes wrong values`, async (t) => {
const { token } = await registerUserAndReturnUserInfo(app);
const createConnectionResult = await request(app.getHttpServer())
.post('/connection')
.send(newConnection)
.set('Cookie', token)
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');

const createConnectionRO = JSON.parse(createConnectionResult.text);
t.is(createConnectionResult.status, 201);

const tableRuleDTO: CreateTableActionRuleBodyDTO = {
title: 'Test rule',
table_name: testTableName,
events: [
{
event: TableActionEventEnum.ADD_ROW,
title: undefined,
icon: null,
require_confirmation: true,
},
],
table_actions: [
{
type: TableActionTypeEnum.multiple,
url: faker.internet.url(),
method: 'wrong-method' as any,
slack_url: undefined,
emails: [faker.internet.email()],
},
{
type: TableActionTypeEnum.single,
url: undefined,
method: TableActionMethodEnum.SLACK,
slack_url: faker.internet.url(),
emails: undefined,
},
],
};

const createTableRuleResult = await request(app.getHttpServer())
.post(`/action/rule/${createConnectionRO.id}`)
.send(tableRuleDTO)
.set('Cookie', token)
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');

const createTableRuleRO = JSON.parse(createTableRuleResult.text);
console.log('🚀 ~ test ~ createTableRuleRO:', createTableRuleRO);
t.is(createTableRuleResult.status, 400);
const { message } = createTableRuleRO;
t.truthy(message);
t.truthy(message.includes('Invalid action method wrong-method'));
});

currentTest = `GET /action/rules/:connectionId`;

test(`${currentTest} should return found table rules with action and events`, async (t) => {
Expand Down Expand Up @@ -971,7 +1088,6 @@ test(`${currentTest} should create impersonate action`, async (t) => {
.set('Accept', 'application/json');

const createTableRuleRO: FoundActionRulesWithActionsAndEventsDTO = JSON.parse(createTableRuleResult.text);
console.log('🚀 ~ test.only ~ createTableRuleRO:', createTableRuleRO);
t.is(createTableRuleResult.status, 201);

//get second user id from jwt token
Expand Down

0 comments on commit c791ba7

Please sign in to comment.