UNPKG

forest-express

Version:

Official package for all Forest Express Lianas

443 lines (442 loc) 23 kB
"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;