@discipl/law-reg
Version:
Discipl Law and Regulation Compliance Library
215 lines (177 loc) • 6.98 kB
JavaScript
;
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;