UNPKG

@discipl/law-reg

Version:

Discipl Law and Regulation Compliance Library

184 lines (145 loc) 5.64 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ActionChecker = void 0; var _index = require("../index"); var _logging_util = require("../utils/logging_util"); var _abundanceService = require("@discipl/abundance-service"); var _array_util = require("../utils/array_util"); // Improve intelisense // eslint-disable-next-line no-unused-vars class ActionChecker { /** * Create an ActionChecker * @param {ServiceProvider} serviceProvider */ constructor(serviceProvider) { this.logger = (0, _logging_util.getDiscplLogger)(); this.serviceProvider = serviceProvider; } /** * Get abundance service * @return {AbundanceService} * @private */ _getAbundanceService() { return this.serviceProvider.abundanceService; } /** * Get fact checker * @return {FactChecker} * @private */ _getFactChecker() { return this.serviceProvider.factChecker; } /** * Get context explainer * @return {ContextExplainer} * @private */ _getContextExplainer() { return this.serviceProvider.contextExplainer; } /** * Checks if an action is allowed by checking if: * 1. The ssid can be the relevant actor * 2. The object exists * 3. The interested party exists * 4. The pre-conditions are fulfilled * * @param {string} modelLink - Link to a published FLINT model * @param {string} actLink - Link to the respective act * @param {ssid} ssid - Identity of intended actor * @param {Context} context - Context of the action * @param {boolean} earlyEscape - If true, will return a result as soon as one of the flint items is determined to be false * @returns {Promise<CheckActionResult>} */ async checkAction(modelLink, actLink, ssid, context, earlyEscape = false) { this.logger.debug('Checking action', actLink); const core = this._getAbundanceService().getCoreAPI(); const modelReference = await core.get(modelLink, ssid); this.logger.debug('Obtained modelReference', modelReference); const actReference = await core.get(actLink, ssid); const factReference = (0, _array_util.arrayToObject)(modelReference.data[_index.DISCIPL_FLINT_MODEL].facts); this.logger.debug('Fact reference obtained from model', factReference); const actor = actReference.data[_index.DISCIPL_FLINT_ACT].actor; const invalidReasons = []; const actorContext = this._getContextExplainer().extendContextWithExplanation(context); this.logger.info('Checking if', actor, 'is', ssid.did); const checkedActor = await this._getFactChecker().checkFact(actor, ssid, { ...actorContext, 'facts': factReference, 'myself': true }); if (!checkedActor) { invalidReasons.push('actor'); if (earlyEscape) { return { 'valid': false, 'invalidReasons': invalidReasons }; } } const object = actReference.data[_index.DISCIPL_FLINT_ACT].object; this.logger.debug('Original object', object); const objectContext = this._getContextExplainer().extendContextWithExplanation(context); const checkedObject = await this._getFactChecker().checkFact(object, ssid, { ...objectContext, 'facts': factReference }); if (!checkedObject) { invalidReasons.push('object'); if (earlyEscape) { return { 'valid': false, 'invalidReasons': invalidReasons }; } } const recipient = actReference.data[_index.DISCIPL_FLINT_ACT].recipient; this.logger.debug('Original recipient', recipient); const interestedPartyContext = this._getContextExplainer().extendContextWithExplanation(context); const checkedInterestedParty = await this._getFactChecker().checkFact(recipient, ssid, { ...interestedPartyContext, 'facts': factReference }); if (!checkedInterestedParty) { invalidReasons.push('recipient'); if (earlyEscape) { return { 'valid': false, 'invalidReasons': invalidReasons }; } } const preconditions = actReference.data['DISCIPL_FLINT_ACT'].preconditions; this.logger.debug('Original preconditions', preconditions); // Empty string, null, undefined are all explictly interpreted as no preconditions, hence the action can proceed const preconditionContext = this._getContextExplainer().extendContextWithExplanation(context); const checkedPreConditions = preconditions !== '[]' && preconditions != null && preconditions !== '' ? await this._getFactChecker().checkFact(preconditions, ssid, { ...preconditionContext, 'facts': factReference }) : true; if (!checkedPreConditions) { invalidReasons.push('preconditions'); if (earlyEscape) { return { 'valid': false, 'invalidReasons': invalidReasons }; } } if (checkedActor && checkedPreConditions && checkedObject && checkedInterestedParty) { this.logger.info('Prerequisites for act', actLink, 'have been verified'); return { 'valid': true, 'invalidReasons': [] }; } const definitivelyNotPossible = checkedActor === false || checkedObject === false || checkedInterestedParty === false || checkedPreConditions === false; const validity = definitivelyNotPossible ? false : undefined; this.logger.info('Pre-act check failed due to', invalidReasons, definitivelyNotPossible ? 'It is impossible.' : 'It might work with more information'); return { 'valid': validity, 'invalidReasons': invalidReasons }; } } exports.ActionChecker = ActionChecker;