Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev #49

Merged
merged 20 commits into from
Oct 28, 2024
Merged

Dev #49

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
9774881
Init server-side search and filter.
brysonjbest Oct 9, 2024
2b1e0e5
Add server-side search to rule data.
brysonjbest Oct 10, 2024
7ec5f62
Add alphabetical sort to categories.
brysonjbest Oct 11, 2024
24bfb0e
Draft decision validation error checks.
brysonjbest Oct 15, 2024
af09bf1
Revert "Draft decision validation error checks."
brysonjbest Oct 15, 2024
1f2953d
Added functionality to sync rules from the db with Klamm, Added funct…
timwekkenbc Oct 16, 2024
1c042ce
Reorganize onModuleInit flow.
brysonjbest Oct 16, 2024
7c7f167
Merge pull request #41 from bcgov/feature/search-functions
brysonjbest Oct 16, 2024
b58284d
Minor fixes to klamm sync updates
timwekkenbc Oct 17, 2024
acade0e
Revert "Revert "Draft decision validation error checks.""
brysonjbest Oct 17, 2024
c965676
Merge pull request #44 from bcgov/feature/klamm-sync
timwekkenbc Oct 17, 2024
02f7e70
Fix practical issues with klamm sync
timwekkenbc Oct 17, 2024
fea68d5
Add error field in csv generation, with multi-error handling.
brysonjbest Oct 17, 2024
300033f
Fix deletion handling in admin page.
brysonjbest Oct 21, 2024
13d848f
Rename validation error.
brysonjbest Oct 21, 2024
3e14cfd
Merge pull request #45 from bcgov/feature/validation-errors
brysonjbest Oct 21, 2024
6c25c85
Removed mapping for functions as it is not needed
timwekkenbc Oct 21, 2024
445a29c
Merge pull request #46 from bcgov/fix/remove-functions-mapping
timwekkenbc Oct 22, 2024
82c76e6
Fix eslint in pipeline
timwekkenbc Oct 24, 2024
be351e6
Merge pull request #47 from bcgov/fix/eslint
timwekkenbc Oct 24, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions .github/workflows/eslint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,3 @@ jobs:

- name: Run ESLint
run: npm run lint:pipeline
continue-on-error: true

- name: Upload ESLint report
uses: actions/upload-artifact@v4
with:
name: eslint-report
path: eslint-report.html
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Before running your application locally, you'll need some environment variables.

- MONGODB_URL: The URL for connecting to the MongoDB instance you created in the previous step. Set it to something like mongodb://localhost/nest.
- FRONTEND_URI: The URI for the frontend application. Set it to http://localhost:8080.
- GITHUB_RULES_BRANCH: Specifies which branch Klamm is syncing with
- GITHUB_TOKEN: Optional github token to mitigate issues with rate limiting
- GITHUB_APP_CLIENT_ID
- GITHUB_APP_CLIENT_SECRET
- KLAMM_API_URL: The base URL of your Klamm API
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"lint:pipeline": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix --format=html --output-file=eslint-report.html",
"lint:pipeline": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix --max-warnings=0",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
Expand Down
7 changes: 6 additions & 1 deletion src/api/decisions/decisions.controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Controller, Post, Query, Body, HttpException, HttpStatus } from '@nestjs/common';
import { DecisionsService } from './decisions.service';
import { EvaluateDecisionDto, EvaluateDecisionWithContentDto } from './dto/evaluate-decision.dto';
import { ValidationError } from './validations/validation.error';

@Controller('api/decisions')
export class DecisionsController {
Expand All @@ -11,7 +12,11 @@ export class DecisionsController {
try {
return await this.decisionsService.runDecisionByContent(ruleContent, context, { trace });
} catch (error) {
throw new HttpException(error.message, HttpStatus.INTERNAL_SERVER_ERROR);
if (error instanceof ValidationError) {
throw new HttpException(error.message, HttpStatus.BAD_REQUEST);
} else {
throw new HttpException(error.message, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}

Expand Down
6 changes: 5 additions & 1 deletion src/api/decisions/decisions.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ConfigService } from '@nestjs/config';
import { Test, TestingModule } from '@nestjs/testing';
import { ZenEngine, ZenDecision, ZenEvaluateOptions } from '@gorules/zen-engine';
import { DecisionsService } from './decisions.service';
import { ValidationService } from './validations/validations.service';
import { readFileSafely } from '../../utils/readFile';

jest.mock('../../utils/readFile', () => ({
Expand All @@ -11,6 +12,7 @@ jest.mock('../../utils/readFile', () => ({

describe('DecisionsService', () => {
let service: DecisionsService;
let validationService: ValidationService;
let mockEngine: Partial<ZenEngine>;
let mockDecision: Partial<ZenDecision>;

Expand All @@ -23,11 +25,13 @@ describe('DecisionsService', () => {
};

const module: TestingModule = await Test.createTestingModule({
providers: [ConfigService, DecisionsService, { provide: ZenEngine, useValue: mockEngine }],
providers: [ConfigService, DecisionsService, ValidationService, { provide: ZenEngine, useValue: mockEngine }],
}).compile();

service = module.get<DecisionsService>(DecisionsService);
validationService = module.get<ValidationService>(ValidationService);
service.engine = mockEngine as ZenEngine;
jest.spyOn(validationService, 'validateInputs').mockImplementation(() => {});
});

describe('runDecision', () => {
Expand Down
13 changes: 11 additions & 2 deletions src/api/decisions/decisions.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { ZenEngine, ZenEvaluateOptions } from '@gorules/zen-engine';
import { ConfigService } from '@nestjs/config';
import { RuleContent } from '../ruleMapping/ruleMapping.interface';
import { readFileSafely, FileNotFoundError } from '../../utils/readFile';
import { ValidationService } from './validations/validations.service';
import { ValidationError } from './validations/validation.error';

@Injectable()
export class DecisionsService {
Expand All @@ -16,12 +18,19 @@ export class DecisionsService {
}

async runDecisionByContent(ruleContent: RuleContent, context: object, options: ZenEvaluateOptions) {
const validator = new ValidationService();
const ruleInputs = ruleContent?.nodes?.filter((node) => node.type === 'inputNode')[0]?.content;
try {
validator.validateInputs(ruleInputs, context);
const decision = this.engine.createDecision(ruleContent);
return await decision.evaluate(context, options);
} catch (error) {
console.error(error.message);
throw new Error(`Failed to run decision: ${error.message}`);
if (error instanceof ValidationError) {
throw new ValidationError(`Invalid input: ${error.message}`);
} else {
console.error(error.message);
throw new Error(`Failed to run decision: ${error.message}`);
}
}
}

Expand Down
19 changes: 19 additions & 0 deletions src/api/decisions/validations/validation.error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export class ValidationError extends Error {
constructor(message: string) {
super(message);
this.name = 'ValidationError';
Object.setPrototypeOf(this, ValidationError.prototype);
}

getErrorCode(): string {
return 'VALIDATION_ERROR';
}

toJSON(): object {
return {
name: this.name,
message: this.message,
code: this.getErrorCode(),
};
}
}
Loading