"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.RulesController = void 0;
var database_controller_1 = require("./database.controller");
var database_factory_1 = require("../factory/database.factory");
var auth_factory_1 = require("../factory/auth.factory");
var auth_controller_1 = require("./auth.controller");
var security_controller_1 = require("./security.controller");
var email_factory_1 = require("../factory/email.factory");
var storage_controller_1 = require("./storage.controller");
var s3_storage_factory_1 = require("../factory/s3-storage.factory");
var grid_fs_storage_factory_1 = require("../factory/grid-fs-storage.factory");
var databaseController;
var auth;
var authController;
var email;
var fileAdapter;
var storageController;
var messageController;
var RulesController = (function () {
    function RulesController(updateRuleController, _messageController, config) {
        this.updateRuleController = updateRuleController;
        this._messageController = _messageController;
        this.config = config;
        databaseController = new database_controller_1.DatabaseController((config.adapters && config.adapters.database) ?
            this.config.adapters.database(config) : new database_factory_1.DatabaseFactory(config), new security_controller_1.SecurityController(config));
        email = (config && config.adapters && config.adapters.email)
            ? config.adapters.email(config)
            : new email_factory_1.EmailFactory();
        auth = (config && config.adapters && config.adapters.auth)
            ? config.adapters.auth(config)
            : new auth_factory_1.AuthFactory(databaseController, new security_controller_1.SecurityController(config));
        authController = new auth_controller_1.AuthController(auth, databaseController);
        fileAdapter = (config && config.adapters && config.adapters.s3Storage)
            ? new s3_storage_factory_1.S3StorageFactory(config)
            : new grid_fs_storage_factory_1.GridFsStorageFactory(config, config.mongoDbUri);
        storageController = new storage_controller_1.StorageController(fileAdapter, new security_controller_1.SecurityController(config), config);
        messageController = this._messageController;
    }
    RulesController.prototype.getRulesKey = function (rules) {
        if (rules) {
            return Object.keys(rules);
        }
        return Object.keys({});
    };
    RulesController.prototype.handleAuthenticationRule = function (rules, ruleResponse) {
        return __awaiter(this, void 0, void 0, function () {
            var authenticationRules, authenticationRule, authRule, _i, _a, action, data, _b, _c, _d, e_1, e_2;
            return __generator(this, function (_e) {
                switch (_e.label) {
                    case 0:
                        _e.trys.push([0, 12, , 13]);
                        authenticationRules = this.getRulesKey(rules).filter(function (rule) { return rule.startsWith('auth'); });
                        if (authenticationRules.length === 0) {
                            return [2, ruleResponse];
                        }
                        authenticationRule = authenticationRules[0];
                        authRule = rules[authenticationRule];
                        _i = 0, _a = Object.keys(authRule);
                        _e.label = 1;
                    case 1:
                        if (!(_i < _a.length)) return [3, 11];
                        action = _a[_i];
                        data = authRule[action];
                        _e.label = 2;
                    case 2:
                        _e.trys.push([2, 9, , 10]);
                        if (!(action === 'signUp')) return [3, 4];
                        ruleResponse.auth = {};
                        _b = ruleResponse.auth;
                        return [4, authController.signUp(data, rules.context)];
                    case 3:
                        _b.signUp = _e.sent();
                        return [3, 8];
                    case 4:
                        if (!(action === 'signIn')) return [3, 6];
                        ruleResponse.auth = {};
                        _c = ruleResponse.auth;
                        return [4, authController.signIn(data, rules.context)];
                    case 5:
                        _c.signIn = _e.sent();
                        return [3, 8];
                    case 6:
                        if (!(action === 'reset')) return [3, 8];
                        ruleResponse.auth = {};
                        _d = ruleResponse.auth;
                        return [4, authController.resetPassword(data.email ? data.email : data)];
                    case 7:
                        _d.resetPassword = _e.sent();
                        _e.label = 8;
                    case 8: return [3, 10];
                    case 9:
                        e_1 = _e.sent();
                        messageController.print(e_1);
                        ruleResponse.errors["auth." + action] = {
                            message: e_1.message ? e_1.message : e_1.toString(),
                            path: "auth." + action,
                            data: data
                        };
                        return [3, 10];
                    case 10:
                        _i++;
                        return [3, 1];
                    case 11: return [2, ruleResponse];
                    case 12:
                        e_2 = _e.sent();
                        messageController.print(e_2);
                        ruleResponse.errors.auth = {
                            message: e_2.message ? e_2.message : e_2.toString(),
                            path: 'auth',
                            data: null
                        };
                        return [2, ruleResponse];
                    case 13: return [2];
                }
            });
        });
    };
    RulesController.prototype.handleAuthorizationRule = function (rules, ruleResponse) {
        return __awaiter(this, void 0, void 0, function () {
            var policyRules, authorizationRule, policy, _i, _a, action, data, authorizationResults, _b, _c, rule, _d, _e, _f, _g, _h, _j, e_3, e_4;
            return __generator(this, function (_k) {
                switch (_k.label) {
                    case 0:
                        _k.trys.push([0, 15, , 16]);
                        policyRules = this.getRulesKey(rules).filter(function (rule) { return rule.startsWith('policy'); });
                        if (policyRules.length === 0) {
                            return [2, ruleResponse];
                        }
                        if (!(rules.context && rules.context.useMasterKey === true)) {
                            ruleResponse.errors.policy = {
                                message: 'policy rule require masterKey',
                                path: 'policy',
                                data: null
                            };
                            return [2, ruleResponse];
                        }
                        authorizationRule = policyRules[0];
                        policy = rules[authorizationRule];
                        _i = 0, _a = Object.keys(policy);
                        _k.label = 1;
                    case 1:
                        if (!(_i < _a.length)) return [3, 14];
                        action = _a[_i];
                        data = policy[action];
                        _k.label = 2;
                    case 2:
                        _k.trys.push([2, 12, , 13]);
                        if (!(action === 'add' && typeof data === 'object')) return [3, 7];
                        authorizationResults = {};
                        _b = 0, _c = Object.keys(data);
                        _k.label = 3;
                    case 3:
                        if (!(_b < _c.length)) return [3, 6];
                        rule = _c[_b];
                        _d = authorizationResults;
                        _e = rule;
                        return [4, authController.addPolicyRule(rule, data[rule], rules.context)];
                    case 4:
                        _d[_e] = _k.sent();
                        _k.label = 5;
                    case 5:
                        _b++;
                        return [3, 3];
                    case 6:
                        ruleResponse.policy = {};
                        ruleResponse.policy[action] = authorizationResults;
                        return [3, 11];
                    case 7:
                        if (!(action === 'list' && typeof data === 'object')) return [3, 9];
                        ruleResponse.policy = {};
                        _f = ruleResponse.policy;
                        _g = action;
                        return [4, databaseController.query('_Policy', {
                                filter: {},
                                return: []
                            }, rules.context, {
                                bypassDomainVerification: true
                            })];
                    case 8:
                        _f[_g] = _k.sent();
                        return [3, 11];
                    case 9:
                        if (!(action === 'remove' && typeof data === 'object')) return [3, 11];
                        ruleResponse.policy = {};
                        _h = ruleResponse.policy;
                        _j = action;
                        return [4, databaseController.delete('_Policy', {
                                filter: {
                                    ruleId: data.ruleId
                                },
                                return: [],
                            }, rules.context, {
                                bypassDomainVerification: true
                            })];
                    case 10:
                        _h[_j] = _k.sent();
                        _k.label = 11;
                    case 11: return [3, 13];
                    case 12:
                        e_3 = _k.sent();
                        messageController.print(e_3);
                        ruleResponse.errors["policy." + action] = {
                            message: e_3.message ? e_3.message : e_3.toString(),
                            path: "policy." + action,
                            data: data
                        };
                        return [3, 13];
                    case 13:
                        _i++;
                        return [3, 1];
                    case 14: return [2, ruleResponse];
                    case 15:
                        e_4 = _k.sent();
                        messageController.print(e_4);
                        ruleResponse.errors.policy = {
                            message: e_4.message ? e_4.message : e_4.toString(),
                            path: 'policy',
                            data: null
                        };
                        return [2, ruleResponse];
                    case 16: return [2];
                }
            });
        });
    };
    RulesController.prototype.handleIndexesRule = function (rules, ruleResponse) {
        var _a;
        return __awaiter(this, void 0, void 0, function () {
            var indexRules, _i, indexRules_1, indexRuleElement, domain, indexRuleBlock, _b, _c, action, data, _d, _e, _f, _g, _h, _j, e_5, e_6;
            return __generator(this, function (_k) {
                switch (_k.label) {
                    case 0:
                        _k.trys.push([0, 14, , 15]);
                        indexRules = this.getRulesKey(rules).filter(function (rule) { return rule.startsWith('index'); });
                        if (indexRules.length === 0) {
                            return [2, ruleResponse];
                        }
                        if (!((rules === null || rules === void 0 ? void 0 : rules.context) && ((_a = rules === null || rules === void 0 ? void 0 : rules.context) === null || _a === void 0 ? void 0 : _a.useMasterKey) === true)) {
                            ruleResponse.errors.index = {
                                message: 'index rule require masterKey',
                                path: 'index',
                                data: null
                            };
                            return [2, ruleResponse];
                        }
                        _i = 0, indexRules_1 = indexRules;
                        _k.label = 1;
                    case 1:
                        if (!(_i < indexRules_1.length)) return [3, 13];
                        indexRuleElement = indexRules_1[_i];
                        domain = this.extractDomain(indexRuleElement, 'index');
                        indexRuleBlock = rules[indexRuleElement];
                        _b = 0, _c = Object.keys(indexRuleBlock);
                        _k.label = 2;
                    case 2:
                        if (!(_b < _c.length)) return [3, 12];
                        action = _c[_b];
                        data = indexRuleBlock[action];
                        _k.label = 3;
                    case 3:
                        _k.trys.push([3, 10, , 11]);
                        ruleResponse[indexRuleElement] = {};
                        if (!(action === 'add' && Array.isArray(data))) return [3, 5];
                        _d = ruleResponse[indexRuleElement];
                        _e = action;
                        return [4, databaseController.addIndexes(domain, data)];
                    case 4:
                        _d[_e] = _k.sent();
                        return [3, 9];
                    case 5:
                        if (!(action === 'list' && typeof data === 'object')) return [3, 7];
                        _f = ruleResponse[indexRuleElement];
                        _g = action;
                        return [4, databaseController.listIndexes(domain)];
                    case 6:
                        _f[_g] = _k.sent();
                        return [3, 9];
                    case 7:
                        if (!(action === 'remove' && typeof data === 'object')) return [3, 9];
                        _h = ruleResponse[indexRuleElement];
                        _j = action;
                        return [4, databaseController.removeIndexes(domain)];
                    case 8:
                        _h[_j] = _k.sent();
                        _k.label = 9;
                    case 9: return [3, 11];
                    case 10:
                        e_5 = _k.sent();
                        messageController.print(e_5);
                        ruleResponse.errors["index." + domain + "." + action] = {
                            message: e_5.message ? e_5.message : e_5.toString(),
                            path: "index." + domain + "." + action,
                            data: data
                        };
                        return [3, 11];
                    case 11:
                        _b++;
                        return [3, 2];
                    case 12:
                        _i++;
                        return [3, 1];
                    case 13: return [2, ruleResponse];
                    case 14:
                        e_6 = _k.sent();
                        messageController.print(e_6);
                        ruleResponse.errors.index = {
                            message: e_6.message ? e_6.message : e_6.toString(),
                            path: 'index',
                            data: null
                        };
                        return [2, ruleResponse];
                    case 15: return [2];
                }
            });
        });
    };
    RulesController.prototype.handleCreateRules = function (rules, ruleResponse, transactionSession) {
        var _a, _b;
        return __awaiter(this, void 0, void 0, function () {
            var createRules, _i, createRules_1, createRule, domain, createRuleRequest, allowed, result, e_7, e_8;
            return __generator(this, function (_c) {
                switch (_c.label) {
                    case 0:
                        _c.trys.push([0, 11, , 12]);
                        createRules = this.getRulesKey(rules).filter(function (rule) { return rule.startsWith('create'); });
                        if (createRules.length === 0) {
                            return [2, ruleResponse];
                        }
                        _i = 0, createRules_1 = createRules;
                        _c.label = 1;
                    case 1:
                        if (!(_i < createRules_1.length)) return [3, 10];
                        createRule = createRules_1[_i];
                        domain = this.extractDomain(createRule, 'create');
                        createRuleRequest = rules[createRule];
                        return [4, authController.hasPermission("create." + domain, rules === null || rules === void 0 ? void 0 : rules.context)];
                    case 2:
                        allowed = _c.sent();
                        if (allowed !== true) {
                            ruleResponse.errors[(transactionSession ? 'transaction.' : '') + "create." + domain] = {
                                message: 'You have insufficient permission to this resource',
                                path: (transactionSession ? 'transaction.' : '') + "create." + domain,
                                data: createRuleRequest
                            };
                            return [2, ruleResponse];
                        }
                        _c.label = 3;
                    case 3:
                        _c.trys.push([3, 8, , 9]);
                        result = void 0;
                        if (!(createRuleRequest && Array.isArray(createRuleRequest))) return [3, 5];
                        return [4, databaseController.writeMany(domain, createRuleRequest, rules === null || rules === void 0 ? void 0 : rules.context, {
                                bypassDomainVerification: ((_a = rules === null || rules === void 0 ? void 0 : rules.context) === null || _a === void 0 ? void 0 : _a.useMasterKey) === true,
                                transaction: transactionSession
                            })];
                    case 4:
                        result = _c.sent();
                        return [3, 7];
                    case 5: return [4, databaseController.writeOne(domain, createRuleRequest, rules === null || rules === void 0 ? void 0 : rules.context, {
                            bypassDomainVerification: ((_b = rules === null || rules === void 0 ? void 0 : rules.context) === null || _b === void 0 ? void 0 : _b.useMasterKey) === true,
                            transaction: transactionSession
                        })];
                    case 6:
                        result = _c.sent();
                        _c.label = 7;
                    case 7:
                        ruleResponse[createRule] = result;
                        return [3, 9];
                    case 8:
                        e_7 = _c.sent();
                        messageController.print(e_7);
                        ruleResponse.errors[(transactionSession ? 'transaction.' : '') + "create." + domain] = {
                            message: e_7.message ? e_7.message : e_7.toString(),
                            path: (transactionSession ? 'transaction.' : '') + "create." + domain,
                            data: createRuleRequest
                        };
                        if (transactionSession) {
                            throw e_7;
                        }
                        return [3, 9];
                    case 9:
                        _i++;
                        return [3, 1];
                    case 10: return [2, ruleResponse];
                    case 11:
                        e_8 = _c.sent();
                        messageController.print(e_8);
                        ruleResponse.errors[(transactionSession ? 'transaction.' : '') + "create"] = {
                            message: e_8.message ? e_8.message : e_8.toString(),
                            path: (transactionSession ? 'transaction.' : '') + "create",
                            data: null
                        };
                        if (transactionSession) {
                            throw e_8;
                        }
                        return [2, ruleResponse];
                    case 12: return [2];
                }
            });
        });
    };
    RulesController.prototype.handleDeleteRules = function (rulesBlockModel, ruleResultModel, transactionSession) {
        var _a, _b, _c;
        return __awaiter(this, void 0, void 0, function () {
            var deleteRules, _i, deleteRules_1, deleteRule, domain, rulesBlockModelElement, allowed, filter, _d, _e, query, deleteResults, _f, query_1, value, result, e_9, e_10;
            return __generator(this, function (_g) {
                switch (_g.label) {
                    case 0:
                        _g.trys.push([0, 15, , 16]);
                        deleteRules = this.getRulesKey(rulesBlockModel).filter(function (rule) { return rule.startsWith('delete'); });
                        if (deleteRules.length === 0) {
                            return [2, ruleResultModel];
                        }
                        _i = 0, deleteRules_1 = deleteRules;
                        _g.label = 1;
                    case 1:
                        if (!(_i < deleteRules_1.length)) return [3, 14];
                        deleteRule = deleteRules_1[_i];
                        domain = this.extractDomain(deleteRule, 'delete');
                        rulesBlockModelElement = rulesBlockModel[deleteRule];
                        return [4, authController.hasPermission("delete." + domain, rulesBlockModel === null || rulesBlockModel === void 0 ? void 0 : rulesBlockModel.context)];
                    case 2:
                        allowed = _g.sent();
                        if (allowed !== true) {
                            ruleResultModel.errors[(transactionSession ? 'transaction.' : '') + "delete." + domain] = {
                                message: 'You have insufficient permission to this resource',
                                path: (transactionSession ? 'transaction.' : '') + "delete." + domain,
                                data: rulesBlockModelElement
                            };
                            return [2, ruleResultModel];
                        }
                        _g.label = 3;
                    case 3:
                        _g.trys.push([3, 12, , 13]);
                        if (!(rulesBlockModelElement === null || rulesBlockModelElement === void 0 ? void 0 : rulesBlockModelElement.id)) return [3, 5];
                        filter = {};
                        delete rulesBlockModelElement.filter;
                        filter._id = rulesBlockModelElement.id;
                        rulesBlockModelElement.filter = filter;
                        _d = ruleResultModel;
                        _e = deleteRule;
                        return [4, databaseController.delete(domain, rulesBlockModelElement, rulesBlockModel === null || rulesBlockModel === void 0 ? void 0 : rulesBlockModel.context, {
                                bypassDomainVerification: ((_a = rulesBlockModel === null || rulesBlockModel === void 0 ? void 0 : rulesBlockModel.context) === null || _a === void 0 ? void 0 : _a.useMasterKey) === true,
                                transaction: transactionSession
                            })];
                    case 4:
                        _d[_e]
                            = _g.sent();
                        return [3, 11];
                    case 5:
                        if (!(rulesBlockModelElement === null || rulesBlockModelElement === void 0 ? void 0 : rulesBlockModelElement.filter)) {
                            throw new Error('filter field is required if you dont supply id field');
                        }
                        if ((rulesBlockModelElement === null || rulesBlockModelElement === void 0 ? void 0 : rulesBlockModelElement.filter) && Object.keys(rulesBlockModelElement === null || rulesBlockModelElement === void 0 ? void 0 : rulesBlockModelElement.filter).length === 0) {
                            throw new Error('Empty filter map is not supported in delete rule');
                        }
                        return [4, databaseController.query(domain, rulesBlockModelElement, rulesBlockModel === null || rulesBlockModel === void 0 ? void 0 : rulesBlockModel.context, {
                                bypassDomainVerification: ((_b = rulesBlockModel === null || rulesBlockModel === void 0 ? void 0 : rulesBlockModel.context) === null || _b === void 0 ? void 0 : _b.useMasterKey) === true,
                                transaction: transactionSession
                            })];
                    case 6:
                        query = _g.sent();
                        deleteResults = [];
                        if (!(query && Array.isArray(query))) return [3, 10];
                        _f = 0, query_1 = query;
                        _g.label = 7;
                    case 7:
                        if (!(_f < query_1.length)) return [3, 10];
                        value = query_1[_f];
                        rulesBlockModelElement.filter = {
                            _id: value.id
                        };
                        return [4, databaseController.delete(domain, rulesBlockModelElement, rulesBlockModel === null || rulesBlockModel === void 0 ? void 0 : rulesBlockModel.context, {
                                bypassDomainVerification: ((_c = rulesBlockModel === null || rulesBlockModel === void 0 ? void 0 : rulesBlockModel.context) === null || _c === void 0 ? void 0 : _c.useMasterKey) === true,
                                transaction: transactionSession
                            })];
                    case 8:
                        result = _g.sent();
                        deleteResults.push(result);
                        _g.label = 9;
                    case 9:
                        _f++;
                        return [3, 7];
                    case 10:
                        ruleResultModel[deleteRule] = deleteResults;
                        _g.label = 11;
                    case 11: return [3, 13];
                    case 12:
                        e_9 = _g.sent();
                        messageController.print(e_9);
                        ruleResultModel.errors[(transactionSession ? 'transaction.' : '') + "delete." + domain] = {
                            message: e_9.message ? e_9.message : e_9.toString(),
                            path: (transactionSession ? 'transaction.' : '') + "delete." + domain,
                            data: rulesBlockModelElement
                        };
                        if (transactionSession) {
                            throw e_9;
                        }
                        return [3, 13];
                    case 13:
                        _i++;
                        return [3, 1];
                    case 14: return [2, ruleResultModel];
                    case 15:
                        e_10 = _g.sent();
                        messageController.print(e_10);
                        ruleResultModel.errors[(transactionSession ? 'transaction.' : '') + "delete"] = {
                            message: e_10.message ? e_10.message : e_10.toString(),
                            path: (transactionSession ? 'transaction.' : '') + "delete",
                            data: null
                        };
                        if (transactionSession) {
                            throw e_10;
                        }
                        return [2, ruleResultModel];
                    case 16: return [2];
                }
            });
        });
    };
    RulesController.prototype.handleQueryRules = function (rulesBlockModel, ruleResultModel, transactionSession) {
        var _a;
        return __awaiter(this, void 0, void 0, function () {
            var queryRules, _i, queryRules_1, queryRule, domain, rulesBlockModelElement, allowed, _b, _c, e_11, e_12;
            return __generator(this, function (_d) {
                switch (_d.label) {
                    case 0:
                        _d.trys.push([0, 10, , 11]);
                        queryRules = this.getRulesKey(rulesBlockModel).filter(function (rule) { return rule.startsWith('query'); });
                        if (queryRules.length === 0) {
                            return [2, ruleResultModel];
                        }
                        _i = 0, queryRules_1 = queryRules;
                        _d.label = 1;
                    case 1:
                        if (!(_i < queryRules_1.length)) return [3, 9];
                        queryRule = queryRules_1[_i];
                        domain = this.extractDomain(queryRule, 'query');
                        rulesBlockModelElement = rulesBlockModel[queryRule];
                        return [4, authController.hasPermission("query." + domain, rulesBlockModel === null || rulesBlockModel === void 0 ? void 0 : rulesBlockModel.context)];
                    case 2:
                        allowed = _d.sent();
                        if (allowed !== true) {
                            ruleResultModel.errors[(transactionSession ? 'transactionSession.' : '') + "query." + domain] = {
                                message: 'You have insufficient permission to this resource',
                                path: (transactionSession ? 'transactionSession.' : '') + "query." + domain,
                                data: rulesBlockModelElement
                            };
                            return [2, ruleResultModel];
                        }
                        _d.label = 3;
                    case 3:
                        _d.trys.push([3, 7, , 8]);
                        if (!(rulesBlockModelElement && Array.isArray(rulesBlockModelElement))) return [3, 4];
                        ruleResultModel.errors[queryRule] = {
                            message: 'query data must be a map',
                            path: queryRule,
                            data: rulesBlockModelElement,
                        };
                        return [3, 6];
                    case 4:
                        _b = ruleResultModel;
                        _c = queryRule;
                        return [4, databaseController.query(domain, rulesBlockModelElement, rulesBlockModel === null || rulesBlockModel === void 0 ? void 0 : rulesBlockModel.context, {
                                bypassDomainVerification: ((_a = rulesBlockModel === null || rulesBlockModel === void 0 ? void 0 : rulesBlockModel.context) === null || _a === void 0 ? void 0 : _a.useMasterKey) === true,
                                transaction: transactionSession
                            })];
                    case 5:
                        _b[_c]
                            = _d.sent();
                        _d.label = 6;
                    case 6: return [3, 8];
                    case 7:
                        e_11 = _d.sent();
                        messageController.print(e_11);
                        ruleResultModel.errors[(transactionSession ? 'transactionSession.' : '') + "query." + domain] = {
                            message: e_11.message ? e_11.message : e_11.toString(),
                            path: (transactionSession ? 'transactionSession.' : '') + "query." + domain,
                            data: rulesBlockModelElement
                        };
                        if (transactionSession) {
                            throw e_11;
                        }
                        return [3, 8];
                    case 8:
                        _i++;
                        return [3, 1];
                    case 9: return [2, ruleResultModel];
                    case 10:
                        e_12 = _d.sent();
                        messageController.print(e_12);
                        ruleResultModel.errors[(transactionSession ? 'transactionSession.' : '') + "query"] = {
                            message: e_12.message ? e_12.message : e_12.toString(),
                            path: (transactionSession ? 'transactionSession.' : '') + "query",
                            data: null
                        };
                        if (transactionSession) {
                            throw e_12;
                        }
                        return [2, ruleResultModel];
                    case 11: return [2];
                }
            });
        });
    };
    RulesController.prototype.handleTransactionRule = function (rulesBlockModel, ruleResultModel) {
        return __awaiter(this, void 0, void 0, function () {
            var transactionRules, transactionRule, transaction, transactionOperationRules_1, resultObject_1, e_13;
            var _this = this;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        _a.trys.push([0, 2, , 3]);
                        transactionRules = this.getRulesKey(rulesBlockModel).filter(function (rule) { return rule.startsWith('transaction'); });
                        if (transactionRules.length === 0) {
                            return [2, ruleResultModel];
                        }
                        transactionRule = transactionRules[0];
                        transaction = rulesBlockModel[transactionRule];
                        transactionOperationRules_1 = transaction.commit;
                        resultObject_1 = { errors: {} };
                        return [4, databaseController.transaction(function (session) { return __awaiter(_this, void 0, void 0, function () {
                                return __generator(this, function (_a) {
                                    switch (_a.label) {
                                        case 0: return [4, this.handleCreateRules(transactionOperationRules_1, resultObject_1, session)];
                                        case 1:
                                            _a.sent();
                                            return [4, this.handleUpdateRules(transactionOperationRules_1, resultObject_1, session)];
                                        case 2:
                                            _a.sent();
                                            return [4, this.handleQueryRules(transactionOperationRules_1, resultObject_1, session)];
                                        case 3:
                                            _a.sent();
                                            return [4, this.handleDeleteRules(transactionOperationRules_1, resultObject_1, session)];
                                        case 4:
                                            _a.sent();
                                            return [2];
                                    }
                                });
                            }); })];
                    case 1:
                        _a.sent();
                        ruleResultModel.transaction = { commit: resultObject_1 };
                        return [2, ruleResultModel];
                    case 2:
                        e_13 = _a.sent();
                        messageController.print(e_13);
                        ruleResultModel.errors.transaction = {
                            message: e_13.message ? e_13.message : e_13.toString(),
                            path: 'transaction',
                            data: null
                        };
                        return [2, ruleResultModel];
                    case 3: return [2];
                }
            });
        });
    };
    RulesController.prototype.handleUpdateRules = function (rules, ruleResponse, transactionSession) {
        return __awaiter(this, void 0, void 0, function () {
            var updateRules, _i, updateRules_1, updateRule, domain, updateRuleRequests, allowed, partialResults, _a, updateRuleRequests_1, value, response, _b, _c, e_14, e_15;
            return __generator(this, function (_d) {
                switch (_d.label) {
                    case 0:
                        _d.trys.push([0, 14, , 15]);
                        updateRules = this.getRulesKey(rules).filter(function (rule) { return rule.startsWith('update'); });
                        if (updateRules.length === 0) {
                            return [2, ruleResponse];
                        }
                        _i = 0, updateRules_1 = updateRules;
                        _d.label = 1;
                    case 1:
                        if (!(_i < updateRules_1.length)) return [3, 13];
                        updateRule = updateRules_1[_i];
                        domain = this.extractDomain(updateRule, 'update');
                        updateRuleRequests = rules[updateRule];
                        return [4, authController.hasPermission("update." + domain, rules.context)];
                    case 2:
                        allowed = _d.sent();
                        if (allowed !== true) {
                            ruleResponse.errors[(transactionSession ? 'transaction.' : '') + "update." + domain] = {
                                message: 'You have insufficient permission to this resource',
                                path: (transactionSession ? 'transaction.' : '') + "update." + domain,
                                data: updateRuleRequests
                            };
                            return [2, ruleResponse];
                        }
                        _d.label = 3;
                    case 3:
                        _d.trys.push([3, 11, , 12]);
                        if (!(updateRuleRequests && Array.isArray(updateRuleRequests))) return [3, 8];
                        partialResults = [];
                        _a = 0, updateRuleRequests_1 = updateRuleRequests;
                        _d.label = 4;
                    case 4:
                        if (!(_a < updateRuleRequests_1.length)) return [3, 7];
                        value = updateRuleRequests_1[_a];
                        return [4, this.updateRuleController.update({
                                updateRuleRequest: value,
                                rules: rules,
                                databaseController: databaseController,
                                domain: domain,
                                transactionSession: transactionSession
                            })];
                    case 5:
                        response = _d.sent();
                        partialResults.push(response);
                        _d.label = 6;
                    case 6:
                        _a++;
                        return [3, 4];
                    case 7:
                        ruleResponse[updateRule] = partialResults;
                        return [3, 10];
                    case 8:
                        _b = ruleResponse;
                        _c = updateRule;
                        return [4, this.updateRuleController.update({
                                updateRuleRequest: updateRuleRequests,
                                rules: rules,
                                databaseController: databaseController,
                                domain: domain,
                                transactionSession: transactionSession
                            })];
                    case 9:
                        _b[_c] = _d.sent();
                        _d.label = 10;
                    case 10: return [3, 12];
                    case 11:
                        e_14 = _d.sent();
                        messageController.print(e_14);
                        ruleResponse.errors[(transactionSession ? 'transaction.' : '') + "update." + domain] = {
                            message: e_14.message ? e_14.message : e_14.toString(),
                            path: (transactionSession ? 'transaction.' : '') + "update." + domain,
                            data: updateRuleRequests
                        };
                        if (transactionSession) {
                            throw e_14;
                        }
                        return [3, 12];
                    case 12:
                        _i++;
                        return [3, 1];
                    case 13: return [2, ruleResponse];
                    case 14:
                        e_15 = _d.sent();
                        messageController.print(e_15);
                        ruleResponse.errors[(transactionSession ? 'transaction.' : '') + "update"] = {
                            message: e_15.message ? e_15.message : e_15.toString(),
                            path: (transactionSession ? 'transaction.' : '') + "update",
                            data: null
                        };
                        if (transactionSession) {
                            throw e_15;
                        }
                        return [2, ruleResponse];
                    case 15: return [2];
                }
            });
        });
    };
    RulesController.prototype.handleAggregationRules = function (rulesBlockModel, ruleResultModel, transactionSession) {
        return __awaiter(this, void 0, void 0, function () {
            var aggregateRules, _i, aggregateRules_1, aggregateRule, domain, allowed, data, _a, _b, _c, _d, e_16, e_17;
            return __generator(this, function (_e) {
                switch (_e.label) {
                    case 0:
                        _e.trys.push([0, 12, , 13]);
                        aggregateRules = this.getRulesKey(rulesBlockModel).filter(function (rule) { return rule.startsWith('aggregate'); });
                        if (aggregateRules.length === 0) {
                            return [2, ruleResultModel];
                        }
                        _i = 0, aggregateRules_1 = aggregateRules;
                        _e.label = 1;
                    case 1:
                        if (!(_i < aggregateRules_1.length)) return [3, 11];
                        aggregateRule = aggregateRules_1[_i];
                        domain = this.extractDomain(aggregateRule, 'aggregate');
                        return [4, authController.hasPermission("aggregate." + domain, rulesBlockModel === null || rulesBlockModel === void 0 ? void 0 : rulesBlockModel.context)];
                    case 2:
                        allowed = _e.sent();
                        if (allowed !== true) {
                            ruleResultModel.errors[(transactionSession ? 'transactionSession.' : '') + "query." + domain] = {
                                message: 'You have insufficient permission to this resource',
                                path: (transactionSession ? 'transactionSession.' : '') + "query." + domain,
                                data: rulesBlockModel[aggregateRule]
                            };
                            return [2, ruleResultModel];
                        }
                        data = rulesBlockModel[aggregateRule];
                        _e.label = 3;
                    case 3:
                        _e.trys.push([3, 9, , 10]);
                        if (!(data
                            && data.hashes
                            && data.pipelines
                            && Array.isArray(data.pipelines)
                            && Array.isArray(data.hashes))) return [3, 5];
                        _a = ruleResultModel;
                        _b = aggregateRule;
                        return [4, databaseController.aggregate(domain, data.pipelines, data.hashes, rulesBlockModel === null || rulesBlockModel === void 0 ? void 0 : rulesBlockModel.context, { bypassDomainVerification: true, transaction: transactionSession })];
                    case 4:
                        _a[_b] = _e.sent();
                        return [3, 8];
                    case 5:
                        if (!(data && Array.isArray(data))) return [3, 7];
                        _c = ruleResultModel;
                        _d = aggregateRule;
                        return [4, databaseController.aggregate(domain, data, [], rulesBlockModel === null || rulesBlockModel === void 0 ? void 0 : rulesBlockModel.context, { bypassDomainVerification: true, transaction: transactionSession })];
                    case 6:
                        _c[_d] = _e.sent();
                        return [3, 8];
                    case 7: throw { message: 'A pipeline must be of any[] or {hashes:string[],pipelines: any[]}' };
                    case 8: return [3, 10];
                    case 9:
                        e_16 = _e.sent();
                        messageController.print(e_16);
                        ruleResultModel.errors[(transactionSession ? 'transaction.' : '') + "aggregate." + domain] = {
                            message: e_16.message ? e_16.message : e_16.toString(),
                            path: (transactionSession ? 'transaction.' : '') + "aggregate." + domain,
                            data: data
                        };
                        if (transactionSession) {
                            throw e_16;
                        }
                        return [3, 10];
                    case 10:
                        _i++;
                        return [3, 1];
                    case 11: return [2, ruleResultModel];
                    case 12:
                        e_17 = _e.sent();
                        messageController.print(e_17);
                        ruleResultModel.errors[(transactionSession ? 'transaction.' : '') + "aggregate"] = {
                            message: e_17.message ? e_17.message : e_17.toString(),
                            path: (transactionSession ? 'transaction.' : '') + "aggregate",
                            data: null
                        };
                        if (transactionSession) {
                            throw e_17;
                        }
                        return [2, ruleResultModel];
                    case 13: return [2];
                }
            });
        });
    };
    RulesController.prototype.handleStorageRule = function (rulesBlockModel, ruleResultModel) {
        return __awaiter(this, void 0, void 0, function () {
            var fileRules, fileRule, file, _i, _a, action, data, allowed, _b, allowed, _c, allowed, _d, e_18, e_19;
            return __generator(this, function (_e) {
                switch (_e.label) {
                    case 0:
                        _e.trys.push([0, 20, , 21]);
                        fileRules = this.getRulesKey(rulesBlockModel).filter(function (rule) { return rule.startsWith('files'); });
                        if (fileRules.length === 0) {
                            return [2, ruleResultModel];
                        }
                        fileRule = fileRules[0];
                        file = rulesBlockModel[fileRule];
                        _i = 0, _a = Object.keys(file);
                        _e.label = 1;
                    case 1:
                        if (!(_i < _a.length)) return [3, 19];
                        action = _a[_i];
                        data = file[action];
                        _e.label = 2;
                    case 2:
                        _e.trys.push([2, 17, , 18]);
                        if (!(action === 'save')) return [3, 7];
                        return [4, authController.hasPermission("files.save", rulesBlockModel.context)];
                    case 3:
                        allowed = _e.sent();
                        if (!(allowed !== true)) return [3, 4];
                        ruleResultModel.errors["files.save"] = {
                            message: 'You have insufficient permission to save file',
                            path: "files.save",
                            data: data
                        };
                        return [3, 6];
                    case 4:
                        ruleResultModel.files = {};
                        _b = ruleResultModel.files;
                        return [4, storageController.save(data, rulesBlockModel.context)];
                    case 5:
                        _b.save = _e.sent();
                        _e.label = 6;
                    case 6: return [3, 16];
                    case 7:
                        if (!(action === 'delete')) return [3, 12];
                        return [4, authController.hasPermission("files.delete", rulesBlockModel.context)];
                    case 8:
                        allowed = _e.sent();
                        if (!(allowed !== true)) return [3, 9];
                        ruleResultModel.errors["files.delete"] = {
                            message: 'You have insufficient permission delete file',
                            path: "files.delete",
                            data: data
                        };
                        return [3, 11];
                    case 9:
                        ruleResultModel.files = {};
                        _c = ruleResultModel.files;
                        return [4, storageController.delete(data, rulesBlockModel.context)];
                    case 10:
                        _c.delete = _e.sent();
                        _e.label = 11;
                    case 11: return [3, 16];
                    case 12:
                        if (!(action === 'list')) return [3, 16];
                        return [4, authController.hasPermission("files.list", rulesBlockModel.context)];
                    case 13:
                        allowed = _e.sent();
                        if (!(allowed !== true)) return [3, 14];
                        ruleResultModel.errors["files.list"] = {
                            message: 'You have insufficient permission list files',
                            path: "files.delete",
                            data: data
                        };
                        return [3, 16];
                    case 14:
                        ruleResultModel.files = {};
                        _d = ruleResultModel.files;
                        return [4, storageController.listFiles({
                                prefix: data && data.prefix ? data.prefix : '',
                                size: data && data.size ? data.size : 20,
                                after: data.after,
                                skip: data && data.skip ? data.skip : 0
                            })];
                    case 15:
                        _d.list = _e.sent();
                        _e.label = 16;
                    case 16: return [3, 18];
                    case 17:
                        e_18 = _e.sent();
                        messageController.print(e_18);
                        ruleResultModel.errors["files." + action] = {
                            message: e_18.message ? e_18.message : e_18.toString(),
                            path: "files." + action,
                            data: data
                        };
                        return [3, 18];
                    case 18:
                        _i++;
                        return [3, 1];
                    case 19: return [2, ruleResultModel];
                    case 20:
                        e_19 = _e.sent();
                        messageController.print(e_19);
                        ruleResultModel.errors.files = {
                            message: e_19.message ? e_19.message : e_19.toString(),
                            path: 'files',
                            data: null
                        };
                        return [2, ruleResultModel];
                    case 21: return [2];
                }
            });
        });
    };
    RulesController.prototype.extractDomain = function (rule, remove) {
        if ((remove === 'create' || remove === 'query' || remove === 'update' || remove === 'index'
            || remove === 'delete' || remove === 'aggregate') && rule.startsWith(remove)) {
            return rule.trim().replace(remove, '');
        }
        else {
            return null;
        }
    };
    return RulesController;
}());
exports.RulesController = RulesController;
