forest-express
Version:
Official package for all Forest Express Lianas
443 lines (442 loc) • 23 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _toArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toArray"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _objectHash = _interopRequireDefault(require("object-hash"));
var _badRequestError = _interopRequireDefault(require("../../utils/errors/bad-request-error"));
var _recordsCounter = _interopRequireDefault(require("../exposed/records-counter"));
var _approvalNotAllowedError = _interopRequireDefault(require("./errors/approval-not-allowed-error"));
var _customActionRequiresApprovalError = _interopRequireDefault(require("./errors/custom-action-requires-approval-error"));
var _customActionTriggerForbiddenError = _interopRequireDefault(require("./errors/custom-action-trigger-forbidden-error"));
var _invalidActionConditionError = _interopRequireDefault(require("./errors/invalid-action-condition-error"));
var _unsupportedConditionalError = _interopRequireDefault(require("./errors/unsupported-conditional-error"));
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
var ActionAuthorizationService = /*#__PURE__*/function () {
function ActionAuthorizationService(_ref) {
var forestAdminClient = _ref.forestAdminClient;
(0, _classCallCheck2["default"])(this, ActionAuthorizationService);
(0, _defineProperty2["default"])(this, "forestAdminClient", void 0);
this.forestAdminClient = forestAdminClient;
}
(0, _createClass2["default"])(ActionAuthorizationService, [{
key: "verifySignedActionParameters",
value: function verifySignedActionParameters(signedToken) {
try {
return this.forestAdminClient.verifySignedActionParameters(signedToken);
} catch (error) {
throw new _badRequestError["default"]('Invalid signed action parameters');
}
}
}, {
key: "assertCanTriggerCustomAction",
value: function () {
var _assertCanTriggerCustomAction = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee(_ref2) {
var userId, collectionName, customActionName, filterForCaller, recordsCounterParams, canTrigger, triggerRequiresApproval, roleIdsAllowedToApprove;
return _regenerator["default"].wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
userId = _ref2.user.id, collectionName = _ref2.collectionName, customActionName = _ref2.customActionName, filterForCaller = _ref2.filterForCaller, recordsCounterParams = _ref2.recordsCounterParams;
_context.next = 3;
return this.canTriggerCustomAction(userId, customActionName, collectionName, filterForCaller, recordsCounterParams);
case 3:
canTrigger = _context.sent;
if (canTrigger) {
_context.next = 6;
break;
}
throw new _customActionTriggerForbiddenError["default"]();
case 6:
_context.next = 8;
return this.doesTriggerCustomActionRequiresApproval(userId, customActionName, collectionName, filterForCaller, recordsCounterParams);
case 8:
triggerRequiresApproval = _context.sent;
if (!triggerRequiresApproval) {
_context.next = 14;
break;
}
_context.next = 12;
return this.getRoleIdsAllowedToApprove(recordsCounterParams, customActionName, collectionName, filterForCaller);
case 12:
roleIdsAllowedToApprove = _context.sent;
throw new _customActionRequiresApprovalError["default"](roleIdsAllowedToApprove);
case 14:
case "end":
return _context.stop();
}
}, _callee, this);
}));
function assertCanTriggerCustomAction(_x) {
return _assertCanTriggerCustomAction.apply(this, arguments);
}
return assertCanTriggerCustomAction;
}()
}, {
key: "assertCanApproveCustomAction",
value: function () {
var _assertCanApproveCustomAction = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2(_ref3) {
var userId, collectionName, customActionName, recordsCounterParams, filterForCaller, requesterId, canApprove, roleIdsAllowedToApprove;
return _regenerator["default"].wrap(function _callee2$(_context2) {
while (1) switch (_context2.prev = _context2.next) {
case 0:
userId = _ref3.user.id, collectionName = _ref3.collectionName, customActionName = _ref3.customActionName, recordsCounterParams = _ref3.recordsCounterParams, filterForCaller = _ref3.filterForCaller, requesterId = _ref3.requesterId;
_context2.next = 3;
return this.canApproveCustomAction(userId, customActionName, collectionName, filterForCaller, recordsCounterParams, requesterId);
case 3:
canApprove = _context2.sent;
if (canApprove) {
_context2.next = 9;
break;
}
_context2.next = 7;
return this.getRoleIdsAllowedToApprove(recordsCounterParams, customActionName, collectionName, filterForCaller);
case 7:
roleIdsAllowedToApprove = _context2.sent;
throw new _approvalNotAllowedError["default"](roleIdsAllowedToApprove);
case 9:
case "end":
return _context2.stop();
}
}, _callee2, this);
}));
function assertCanApproveCustomAction(_x2) {
return _assertCanApproveCustomAction.apply(this, arguments);
}
return assertCanApproveCustomAction;
}()
}, {
key: "canTriggerCustomAction",
value: function () {
var _canTriggerCustomAction = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee3(userId, customActionName, collectionName, filterForCaller, recordsCounterParams) {
var canTrigger, triggerConditionPlainTree;
return _regenerator["default"].wrap(function _callee3$(_context3) {
while (1) switch (_context3.prev = _context3.next) {
case 0:
_context3.next = 2;
return this.forestAdminClient.permissionService.canTriggerCustomAction({
userId: userId,
customActionName: customActionName,
collectionName: collectionName
});
case 2:
canTrigger = _context3.sent;
if (canTrigger) {
_context3.next = 5;
break;
}
return _context3.abrupt("return", false);
case 5:
_context3.next = 7;
return this.forestAdminClient.permissionService.getConditionalTriggerCondition({
userId: userId,
customActionName: customActionName,
collectionName: collectionName
});
case 7:
triggerConditionPlainTree = _context3.sent;
return _context3.abrupt("return", ActionAuthorizationService.canPerformConditionalCustomAction(recordsCounterParams, filterForCaller, triggerConditionPlainTree));
case 9:
case "end":
return _context3.stop();
}
}, _callee3, this);
}));
function canTriggerCustomAction(_x3, _x4, _x5, _x6, _x7) {
return _canTriggerCustomAction.apply(this, arguments);
}
return canTriggerCustomAction;
}()
}, {
key: "doesTriggerCustomActionRequiresApproval",
value: function () {
var _doesTriggerCustomActionRequiresApproval = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee4(userId, customActionName, collectionName, filterForCaller, recordsCounterParams) {
var doesTriggerRequiresApproval, requiresConditionApprovalPlainTree, matchingRecordsCount;
return _regenerator["default"].wrap(function _callee4$(_context4) {
while (1) switch (_context4.prev = _context4.next) {
case 0:
_context4.next = 2;
return this.forestAdminClient.permissionService.doesTriggerCustomActionRequiresApproval({
userId: userId,
customActionName: customActionName,
collectionName: collectionName
});
case 2:
doesTriggerRequiresApproval = _context4.sent;
if (doesTriggerRequiresApproval) {
_context4.next = 5;
break;
}
return _context4.abrupt("return", false);
case 5:
_context4.next = 7;
return this.forestAdminClient.permissionService.getConditionalRequiresApprovalCondition({
userId: userId,
customActionName: customActionName,
collectionName: collectionName
});
case 7:
requiresConditionApprovalPlainTree = _context4.sent;
if (!requiresConditionApprovalPlainTree) {
_context4.next = 14;
break;
}
_context4.next = 11;
return ActionAuthorizationService.aggregateCountConditionIntersection(recordsCounterParams, filterForCaller, requiresConditionApprovalPlainTree);
case 11:
matchingRecordsCount = _context4.sent;
if (!(matchingRecordsCount === 0)) {
_context4.next = 14;
break;
}
return _context4.abrupt("return", false);
case 14:
return _context4.abrupt("return", true);
case 15:
case "end":
return _context4.stop();
}
}, _callee4, this);
}));
function doesTriggerCustomActionRequiresApproval(_x8, _x9, _x10, _x11, _x12) {
return _doesTriggerCustomActionRequiresApproval.apply(this, arguments);
}
return doesTriggerCustomActionRequiresApproval;
}()
}, {
key: "canApproveCustomAction",
value: function () {
var _canApproveCustomAction = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee5(userId, customActionName, collectionName, filterForCaller, recordsCounterParams, requesterId) {
var canApprove, approveConditionPlainTree;
return _regenerator["default"].wrap(function _callee5$(_context5) {
while (1) switch (_context5.prev = _context5.next) {
case 0:
_context5.next = 2;
return this.forestAdminClient.permissionService.canApproveCustomAction({
userId: userId,
customActionName: customActionName,
collectionName: collectionName,
requesterId: requesterId
});
case 2:
canApprove = _context5.sent;
if (canApprove) {
_context5.next = 5;
break;
}
return _context5.abrupt("return", false);
case 5:
_context5.next = 7;
return this.forestAdminClient.permissionService.getConditionalApproveCondition({
userId: userId,
customActionName: customActionName,
collectionName: collectionName
});
case 7:
approveConditionPlainTree = _context5.sent;
return _context5.abrupt("return", ActionAuthorizationService.canPerformConditionalCustomAction(recordsCounterParams, filterForCaller, approveConditionPlainTree));
case 9:
case "end":
return _context5.stop();
}
}, _callee5, this);
}));
function canApproveCustomAction(_x13, _x14, _x15, _x16, _x17, _x18) {
return _canApproveCustomAction.apply(this, arguments);
}
return canApproveCustomAction;
}()
}, {
key: "getRoleIdsAllowedToApprove",
value: function () {
var _getRoleIdsAllowedToApprove = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee6(recordsCounterParams, customActionName, collectionName, filterForCaller) {
var actionConditionsByRoleId, roleIdsAllowedToApproveWithoutConditions, rolesIdsGroupByConditions, _yield$Promise$all, _yield$Promise$all2, requestRecordsCount, conditionRecordsCounts;
return _regenerator["default"].wrap(function _callee6$(_context6) {
while (1) switch (_context6.prev = _context6.next) {
case 0:
_context6.next = 2;
return this.forestAdminClient.permissionService.getConditionalApproveConditions({
customActionName: customActionName,
collectionName: collectionName
});
case 2:
actionConditionsByRoleId = _context6.sent;
_context6.next = 5;
return this.forestAdminClient.permissionService.getRoleIdsAllowedToApproveWithoutConditions({
customActionName: customActionName,
collectionName: collectionName
});
case 5:
roleIdsAllowedToApproveWithoutConditions = _context6.sent;
// Optimization - We groupBy conditions to only make the aggregate count once when possible
rolesIdsGroupByConditions = ActionAuthorizationService.transformToRolesIdsGroupByConditions(actionConditionsByRoleId);
if (rolesIdsGroupByConditions.length) {
_context6.next = 9;
break;
}
return _context6.abrupt("return", roleIdsAllowedToApproveWithoutConditions);
case 9:
_context6.next = 11;
return Promise.all([ActionAuthorizationService.aggregateCountConditionIntersection(_objectSpread(_objectSpread({}, recordsCounterParams), {}, {
excludesScope: true
}), filterForCaller)].concat((0, _toConsumableArray2["default"])(rolesIdsGroupByConditions.map(function (_ref4) {
var conditionPlainTree = _ref4.condition;
return ActionAuthorizationService.aggregateCountConditionIntersection(_objectSpread(_objectSpread({}, recordsCounterParams), {}, {
excludesScope: true
}), filterForCaller, conditionPlainTree);
}))));
case 11:
_yield$Promise$all = _context6.sent;
_yield$Promise$all2 = (0, _toArray2["default"])(_yield$Promise$all);
requestRecordsCount = _yield$Promise$all2[0];
conditionRecordsCounts = _yield$Promise$all2.slice(1);
return _context6.abrupt("return", rolesIdsGroupByConditions.reduce(function (roleIdsAllowedToApprove, _ref5, currentIndex) {
var roleIds = _ref5.roleIds;
if (requestRecordsCount === conditionRecordsCounts[currentIndex]) {
roleIdsAllowedToApprove.push.apply(roleIdsAllowedToApprove, (0, _toConsumableArray2["default"])(roleIds));
}
return roleIdsAllowedToApprove;
},
// Roles with userApprovalEnabled excluding the one with conditions
// are allowed to approve by default
roleIdsAllowedToApproveWithoutConditions));
case 16:
case "end":
return _context6.stop();
}
}, _callee6, this);
}));
function getRoleIdsAllowedToApprove(_x19, _x20, _x21, _x22) {
return _getRoleIdsAllowedToApprove.apply(this, arguments);
}
return getRoleIdsAllowedToApprove;
}()
}], [{
key: "canPerformConditionalCustomAction",
value: function () {
var _canPerformConditionalCustomAction = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee7(recordsCounterParams, requestFilterPlainTree, conditionPlainTree) {
var _yield$Promise$all3, _yield$Promise$all4, requestRecordsCount, matchingRecordsCount;
return _regenerator["default"].wrap(function _callee7$(_context7) {
while (1) switch (_context7.prev = _context7.next) {
case 0:
if (!conditionPlainTree) {
_context7.next = 8;
break;
}
_context7.next = 3;
return Promise.all([ActionAuthorizationService.aggregateCountConditionIntersection(recordsCounterParams, requestFilterPlainTree), ActionAuthorizationService.aggregateCountConditionIntersection(recordsCounterParams, requestFilterPlainTree, conditionPlainTree)]);
case 3:
_yield$Promise$all3 = _context7.sent;
_yield$Promise$all4 = (0, _slicedToArray2["default"])(_yield$Promise$all3, 2);
requestRecordsCount = _yield$Promise$all4[0];
matchingRecordsCount = _yield$Promise$all4[1];
return _context7.abrupt("return", matchingRecordsCount === requestRecordsCount);
case 8:
return _context7.abrupt("return", true);
case 9:
case "end":
return _context7.stop();
}
}, _callee7);
}));
function canPerformConditionalCustomAction(_x23, _x24, _x25) {
return _canPerformConditionalCustomAction.apply(this, arguments);
}
return canPerformConditionalCustomAction;
}()
}, {
key: "aggregateCountConditionIntersection",
value: function () {
var _aggregateCountConditionIntersection = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee8(recordsCounterParams, requestFilterPlainTree, conditionPlainTree) {
var _recordsCounterParams, rawFilter, conditionalFilterFormatted, recordsCounter;
return _regenerator["default"].wrap(function _callee8$(_context8) {
while (1) switch (_context8.prev = _context8.next) {
case 0:
if (recordsCounterParams.model) {
_context8.next = 2;
break;
}
throw new _unsupportedConditionalError["default"]();
case 2:
_context8.prev = 2;
// Perform intersection when conditionPlainTree is defined
rawFilter = conditionPlainTree ? {
aggregator: 'and',
conditions: [requestFilterPlainTree, conditionPlainTree]
} : requestFilterPlainTree; // Build filter with the right format
conditionalFilterFormatted = JSON.stringify(rawFilter);
recordsCounter = new _recordsCounter["default"](recordsCounterParams.model, recordsCounterParams.user, {
filters: conditionalFilterFormatted,
timezone: recordsCounterParams.timezone
}); // Support aggregate count without user scope (used by getRoleIdsAllowedToApprove)
recordsCounter.excludesScope = (_recordsCounterParams = recordsCounterParams.excludesScope) !== null && _recordsCounterParams !== void 0 ? _recordsCounterParams : false;
_context8.next = 9;
return recordsCounter.count();
case 9:
return _context8.abrupt("return", _context8.sent);
case 12:
_context8.prev = 12;
_context8.t0 = _context8["catch"](2);
throw new _invalidActionConditionError["default"]();
case 15:
case "end":
return _context8.stop();
}
}, _callee8, null, [[2, 12]]);
}));
function aggregateCountConditionIntersection(_x26, _x27, _x28) {
return _aggregateCountConditionIntersection.apply(this, arguments);
}
return aggregateCountConditionIntersection;
}()
/**
* Given a map it groups keys based on their hash values
*/
}, {
key: "transformToRolesIdsGroupByConditions",
value: function transformToRolesIdsGroupByConditions(actionConditionsByRoleId) {
if (!actionConditionsByRoleId) {
return [];
}
var rolesIdsGroupByConditions = Array.from(actionConditionsByRoleId, function (_ref6) {
var _ref7 = (0, _slicedToArray2["default"])(_ref6, 2),
roleId = _ref7[0],
condition = _ref7[1];
return {
roleId: roleId,
condition: condition,
conditionHash: (0, _objectHash["default"])(condition, {
respectType: false
})
};
}).reduce(function (acc, current) {
var roleId = current.roleId,
condition = current.condition,
conditionHash = current.conditionHash;
if (acc.has(conditionHash)) {
var _acc$get;
// We don't need nullish operator but our TS config might be wrong since it's required
(_acc$get = acc.get(conditionHash)) === null || _acc$get === void 0 ? void 0 : _acc$get.roleIds.push(roleId);
} else {
acc.set(conditionHash, {
roleIds: [roleId],
condition: condition
});
}
return acc;
}, new Map());
return Array.from(rolesIdsGroupByConditions.values());
}
}]);
return ActionAuthorizationService;
}();
exports["default"] = ActionAuthorizationService;