UNPKG

@discipl/law-reg

Version:

Discipl Law and Regulation Compliance Library

215 lines (177 loc) 6.98 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ActionService = void 0; var _defaultFactResolver = require("../defaultFactResolver"); var _identity_util = _interopRequireDefault(require("../utils/identity_util")); var _index = require("../index"); var _logging_util = require("../utils/logging_util"); var _abundanceService = require("@discipl/abundance-service"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // Improve intelisense // eslint-disable-next-line no-unused-vars class ActionService { /** * Create an ActionService * @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 link utils * @return {LinkUtil} * @private */ _getLinkUtils() { return this.serviceProvider.linkUtil; } /** * Get action checker * @return {ActionChecker} * @private */ _getActionChecker() { return this.serviceProvider.actionChecker; } /** * Returns all the actions that have been taken in a case so far * * @param {string} caseLink - Link to the last action in the case * @param {ssid} ssid - Identity used to get access to information * @returns {Promise<ActionInformation[]>} */ async getActions(caseLink, ssid) { const core = this._getAbundanceService().getCoreAPI(); let actionLink = caseLink; const acts = []; while (actionLink != null) { const lastAction = await core.get(actionLink, ssid); const actLink = lastAction.data[_index.DISCIPL_FLINT_ACT_TAKEN]; if (actLink != null) { const act = await core.get(actLink, ssid); if (typeof act.data[_index.DISCIPL_FLINT_ACT].act === 'string') { acts.unshift({ 'act': act.data[_index.DISCIPL_FLINT_ACT].act, 'link': actionLink }); } } actionLink = lastAction.data[_index.DISCIPL_FLINT_PREVIOUS_CASE]; } return acts; } /** * Denotes a given act in the context of a case as taken, if it is possible. See {@link ActionChecker.checkAction} is used to check the conditions * * @param {ssid} ssid - Identity of the actor * @param {string} caseLink - Link to the case, which is either an earlier action, or a need * @param {string} act - description of the act to be taken * @param {function} factResolver - Function used to resolve facts to fall back on if no other method is available. Defaults to always false * @returns {Promise<string>} Link to a verifiable claim that holds that taken actions */ async take(ssid, caseLink, act, factResolver = () => false) { const { core, modelLink, actLink, firstCaseLink } = await this._getModelAndActFromCase(caseLink, ssid, act); const factsSupplied = {}; const defaultFactResolver = (0, _defaultFactResolver.wrapWithDefault)(factResolver, factsSupplied); this.logger.debug('Checking if action', act, 'is possible from perspective of', ssid.did); const checkActionInfo = await this._getActionChecker().checkAction(modelLink, actLink, ssid, { 'factResolver': defaultFactResolver, 'caseLink': caseLink, 'factsSupplied': factsSupplied }, true); if (checkActionInfo.valid) { this.logger.info('Registering act', actLink); return core.claim(ssid, { [_index.DISCIPL_FLINT_ACT_TAKEN]: actLink, [_index.DISCIPL_FLINT_GLOBAL_CASE]: firstCaseLink, [_index.DISCIPL_FLINT_PREVIOUS_CASE]: caseLink, [_index.DISCIPL_FLINT_FACTS_SUPPLIED]: await this._addActorIsExpression(actLink, factsSupplied, ssid) }); } throw new Error('Action ' + act + ' is not allowed due to ' + checkActionInfo.invalidReasons); } /** * Add actor IS expression to supplied facts * * @param {string} actLink - Link to the particular act * @param {ssid} ssid - Identity of the actor * @param {object} factsSupplied - The supplied facts * @returns {Promise<object>} The supplied facts * @private */ async _addActorIsExpression(actLink, factsSupplied, ssid) { const core = this._getAbundanceService().getCoreAPI(); const actReference = await core.get(actLink, ssid); const actor = actReference.data[_index.DISCIPL_FLINT_ACT].actor; factsSupplied[actor] = _identity_util.default.identityExpression(ssid.did); return factsSupplied; } /** * Add the result of an action to the explanation part of the context. {@link ActionChecker.checkAction} is used to check the conditions. * * @param {ssid} ssid - Identity of the actor * @param {string} caseLink - Link to the case, which is either an earlier action, or a need * @param {string} act - description of the act to explain * @param {function} factResolver - Function used to resolve facts to fall back on if no other method is available. Defaults to always false * @returns {Promise<Explanation>} Explanation object from the context with the action result as value */ async explain(ssid, caseLink, act, factResolver) { const { modelLink, actLink } = await this._getModelAndActFromCase(caseLink, ssid, act); const defaultFactResolver = (0, _defaultFactResolver.wrapWithDefault)(factResolver, {}); const context = { 'factResolver': defaultFactResolver, 'caseLink': caseLink, explanation: {} }; this.logger.debug('Checking if action is possible from perspective of', ssid.did); const checkActionResult = await this._getActionChecker().checkAction(modelLink, actLink, ssid, context, true); context.explanation.value = checkActionResult.valid; return context.explanation; } /** * Get model and act from case link, actor ssid and act * @param {string} caseLink * @param {ssid} ssid * @param {string} act * @return {Promise<{core: DisciplCore, modelLink: *, actLink: *, firstCaseLink: *}>} * @private */ async _getModelAndActFromCase(caseLink, ssid, act) { const core = this._getAbundanceService().getCoreAPI(); const firstCaseLink = await this._getLinkUtils().getFirstCaseLink(caseLink, ssid); const modelLink = await this._getLinkUtils().getModelLink(firstCaseLink, ssid); const model = await core.get(modelLink, ssid); const actLink = await model.data[_index.DISCIPL_FLINT_MODEL].acts.filter(actWithLink => { return Object.keys(actWithLink).includes(act); }).map(actWithLink => Object.values(actWithLink)[0])[0]; if (actLink == null) { throw new Error('Act not found ' + act); } return { core, modelLink, actLink, firstCaseLink }; } } exports.ActionService = ActionService;