"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.DBHelper = void 0;
var Crypt_1 = require("./Crypt");
var openflow_api_1 = require("@openiap/openflow-api");
var Config_1 = require("./Config");
var Logger_1 = require("./Logger");
var DBHelper = /** @class */ (function () {
    function DBHelper() {
    }
    DBHelper.FindByUsername = function (username, jwt, parent) {
        if (jwt === void 0) { jwt = null; }
        return __awaiter(this, void 0, void 0, function () {
            var span, byuser, byid, q, items, result, error_1;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        span = Logger_1.Logger.otel.startSubSpan("dbhelper.FindByUsername", parent);
                        _a.label = 1;
                    case 1:
                        _a.trys.push([1, 4, 5, 6]);
                        byuser = { username: new RegExp(["^", username, "$"].join(""), "i") };
                        byid = { federationids: new RegExp(["^", username, "$"].join(""), "i") };
                        q = { $or: [byuser, byid] };
                        if (jwt === null || jwt == undefined || jwt == "") {
                            jwt = Crypt_1.Crypt.rootToken();
                        }
                        return [4 /*yield*/, Config_1.Config.db.query(q, null, 1, 0, null, "users", jwt, undefined, undefined, span)];
                    case 2:
                        items = _a.sent();
                        if (items === null || items === undefined || items.length === 0) {
                            return [2 /*return*/, null];
                        }
                        result = openflow_api_1.User.assign(items[0]);
                        return [4 /*yield*/, this.DecorateWithRoles(result, span)];
                    case 3:
                        _a.sent();
                        return [2 /*return*/, result];
                    case 4:
                        error_1 = _a.sent();
                        span.recordException(error_1);
                        throw error_1;
                    case 5:
                        Logger_1.Logger.otel.endSpan(span);
                        return [7 /*endfinally*/];
                    case 6: return [2 /*return*/];
                }
            });
        });
    };
    DBHelper.FindById = function (_id, jwt, parent) {
        if (jwt === void 0) { jwt = null; }
        return __awaiter(this, void 0, void 0, function () {
            var span, items, result, error_2;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        span = Logger_1.Logger.otel.startSubSpan("dbhelper.FindById", parent);
                        _a.label = 1;
                    case 1:
                        _a.trys.push([1, 4, 5, 6]);
                        if (jwt === null || jwt == undefined || jwt == "") {
                            jwt = Crypt_1.Crypt.rootToken();
                        }
                        return [4 /*yield*/, Config_1.Config.db.query({ _id: _id }, null, 1, 0, null, "users", jwt, undefined, undefined, span)];
                    case 2:
                        items = _a.sent();
                        if (items === null || items === undefined || items.length === 0) {
                            return [2 /*return*/, null];
                        }
                        result = openflow_api_1.User.assign(items[0]);
                        return [4 /*yield*/, this.DecorateWithRoles(result, span)];
                    case 3:
                        _a.sent();
                        return [2 /*return*/, result];
                    case 4:
                        error_2 = _a.sent();
                        span.recordException(error_2);
                        throw error_2;
                    case 5:
                        Logger_1.Logger.otel.endSpan(span);
                        return [7 /*endfinally*/];
                    case 6: return [2 /*return*/];
                }
            });
        });
    };
    DBHelper.FindByUsernameOrId = function (username, id, parent) {
        return __awaiter(this, void 0, void 0, function () {
            var span, items, result, error_3;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        span = Logger_1.Logger.otel.startSubSpan("dbhelper.FindByUsernameOrId", parent);
                        _a.label = 1;
                    case 1:
                        _a.trys.push([1, 4, 5, 6]);
                        return [4 /*yield*/, Config_1.Config.db.query({ $or: [{ username: new RegExp(["^", username, "$"].join(""), "i") }, { _id: id }] }, null, 1, 0, null, "users", Crypt_1.Crypt.rootToken(), undefined, undefined, span)];
                    case 2:
                        items = _a.sent();
                        if (items === null || items === undefined || items.length === 0) {
                            return [2 /*return*/, null];
                        }
                        result = openflow_api_1.User.assign(items[0]);
                        return [4 /*yield*/, this.DecorateWithRoles(result, span)];
                    case 3:
                        _a.sent();
                        return [2 /*return*/, result];
                    case 4:
                        error_3 = _a.sent();
                        span.recordException(error_3);
                        throw error_3;
                    case 5:
                        Logger_1.Logger.otel.endSpan(span);
                        return [7 /*endfinally*/];
                    case 6: return [2 /*return*/];
                }
            });
        });
    };
    DBHelper.FindByUsernameOrFederationid = function (username, parent) {
        return __awaiter(this, void 0, void 0, function () {
            var span, byuser, byid, q, items, result, error_4;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        span = Logger_1.Logger.otel.startSubSpan("dbhelper.FindByUsernameOrFederationid", parent);
                        _a.label = 1;
                    case 1:
                        _a.trys.push([1, 4, 5, 6]);
                        byuser = { username: new RegExp(["^", username, "$"].join(""), "i") };
                        byid = { federationids: new RegExp(["^", username, "$"].join(""), "i") };
                        q = { $or: [byuser, byid] };
                        return [4 /*yield*/, Config_1.Config.db.query(q, null, 1, 0, null, "users", Crypt_1.Crypt.rootToken(), undefined, undefined, span)];
                    case 2:
                        items = _a.sent();
                        if (items === null || items === undefined || items.length === 0) {
                            return [2 /*return*/, null];
                        }
                        result = openflow_api_1.User.assign(items[0]);
                        return [4 /*yield*/, this.DecorateWithRoles(result, span)];
                    case 3:
                        _a.sent();
                        return [2 /*return*/, result];
                    case 4:
                        error_4 = _a.sent();
                        span.recordException(error_4);
                        throw error_4;
                    case 5:
                        Logger_1.Logger.otel.endSpan(span);
                        return [7 /*endfinally*/];
                    case 6: return [2 /*return*/];
                }
            });
        });
    };
    DBHelper.GetRoles = function (_id, ident, parent) {
        return __awaiter(this, void 0, void 0, function () {
            var span, result, query, ids, _roles, i, role, _subroles, y, subrole, error_5;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        span = Logger_1.Logger.otel.startSubSpan("dbhelper.GetRoles", parent);
                        span.setAttribute("_id", _id);
                        span.setAttribute("ident", ident);
                        _a.label = 1;
                    case 1:
                        _a.trys.push([1, 7, 8, 9]);
                        if (ident > Config_1.Config.max_recursive_group_depth)
                            return [2 /*return*/, []];
                        result = [];
                        query = { "members": { "$elemMatch": { _id: _id } } };
                        ids = [];
                        return [4 /*yield*/, Config_1.Config.db.query(query, null, Config_1.Config.expected_max_roles, 0, null, "users", Crypt_1.Crypt.rootToken(), undefined, undefined, span)];
                    case 2:
                        _roles = _a.sent();
                        i = 0;
                        _a.label = 3;
                    case 3:
                        if (!(i < _roles.length)) return [3 /*break*/, 6];
                        role = _roles[i];
                        if (!(ids.indexOf(role._id) == -1)) return [3 /*break*/, 5];
                        ids.push(role._id);
                        result.push(role);
                        return [4 /*yield*/, this.GetRoles(role._id, ident + 1, span)];
                    case 4:
                        _subroles = _a.sent();
                        for (y = 0; y < _subroles.length; y++) {
                            subrole = _subroles[y];
                            if (ids.indexOf(subrole._id) == -1) {
                                ids.push(subrole._id);
                                result.push(subrole);
                            }
                        }
                        _a.label = 5;
                    case 5:
                        i++;
                        return [3 /*break*/, 3];
                    case 6: return [2 /*return*/, result];
                    case 7:
                        error_5 = _a.sent();
                        span.recordException(error_5);
                        throw error_5;
                    case 8:
                        Logger_1.Logger.otel.endSpan(span);
                        return [7 /*endfinally*/];
                    case 9: return [2 /*return*/];
                }
            });
        });
    };
    DBHelper.DecorateWithRoles = function (user, parent) {
        return __awaiter(this, void 0, void 0, function () {
            var span, roles, end, seconds, query, _a, foundone_1, error_6;
            var _this = this;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        span = Logger_1.Logger.otel.startSubSpan("dbhelper.DecorateWithRoles", parent);
                        _b.label = 1;
                    case 1:
                        _b.trys.push([1, 7, 8, 9]);
                        if (!!Config_1.Config.decorate_roles_fetching_all_roles) return [3 /*break*/, 3];
                        return [4 /*yield*/, this.GetRoles(user._id, 0, span)];
                    case 2:
                        roles = _b.sent();
                        user.roles = [];
                        roles.forEach(function (role) {
                            user.roles.push(new openflow_api_1.Rolemember(role.name, role._id));
                        });
                        return [3 /*break*/, 6];
                    case 3:
                        end = new Date().getTime();
                        seconds = Math.round((end - this.cached_at.getTime()) / 1000);
                        if (seconds > Config_1.Config.roles_cached_in_seconds || Config_1.Config.roles_cached_in_seconds <= 0) {
                            this.cached_roles = [];
                        }
                        if (!(this.cached_roles.length == 0)) return [3 /*break*/, 5];
                        query = { _type: "role" };
                        _a = this;
                        return [4 /*yield*/, Config_1.Config.db.query(query, { "name": 1, "members": 1 }, Config_1.Config.expected_max_roles, 0, null, "users", Crypt_1.Crypt.rootToken(), undefined, undefined, span)];
                    case 4:
                        _a.cached_roles = _b.sent();
                        this.cached_at = new Date();
                        _b.label = 5;
                    case 5:
                        if (this.cached_roles.length === 0 && user.username !== "root") {
                            throw new Error("System has no roles !!!!!!");
                        }
                        user.roles = [];
                        this.cached_roles.forEach(function (role) {
                            var isMember = -1;
                            if (role.members !== undefined) {
                                isMember = role.members.map(function (e) { return e._id; }).indexOf(user._id);
                            }
                            var beenAdded = user.roles.map(function (e) { return e._id; }).indexOf(user._id);
                            if (isMember > -1 && beenAdded === -1) {
                                user.roles.push(new openflow_api_1.Rolemember(role.name, role._id));
                            }
                        });
                        foundone_1 = true;
                        while (foundone_1) {
                            foundone_1 = false;
                            user.roles.forEach(function (userrole) {
                                _this.cached_roles.forEach(function (role) {
                                    var isMember = -1;
                                    if (role.members !== undefined) {
                                        isMember = role.members.map(function (e) { return e._id; }).indexOf(userrole._id);
                                    }
                                    var beenAdded = user.roles.map(function (e) { return e._id; }).indexOf(role._id);
                                    if (isMember > -1 && beenAdded === -1) {
                                        user.roles.push(new openflow_api_1.Rolemember(role.name, role._id));
                                        foundone_1 = true;
                                    }
                                });
                            });
                        }
                        _b.label = 6;
                    case 6: return [3 /*break*/, 9];
                    case 7:
                        error_6 = _b.sent();
                        span.recordException(error_6);
                        throw error_6;
                    case 8:
                        Logger_1.Logger.otel.endSpan(span);
                        return [7 /*endfinally*/];
                    case 9: return [2 /*return*/];
                }
            });
        });
    };
    DBHelper.FindRoleByName = function (name, parent) {
        return __awaiter(this, void 0, void 0, function () {
            var items, result;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, Config_1.Config.db.query({ name: name }, null, 1, 0, null, "users", Crypt_1.Crypt.rootToken(), undefined, undefined, parent)];
                    case 1:
                        items = _a.sent();
                        if (items === null || items === undefined || items.length === 0) {
                            return [2 /*return*/, null];
                        }
                        result = openflow_api_1.Role.assign(items[0]);
                        return [2 /*return*/, result];
                }
            });
        });
    };
    DBHelper.FindRoleByNameOrId = function (name, id, parent) {
        return __awaiter(this, void 0, void 0, function () {
            var jwt, items, result;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        jwt = Crypt_1.Crypt.rootToken();
                        return [4 /*yield*/, Config_1.Config.db.query({ $or: [{ name: name }, { _id: id }] }, null, 1, 0, null, "users", jwt, undefined, undefined, parent)];
                    case 1:
                        items = _a.sent();
                        if (items === null || items === undefined || items.length === 0) {
                            return [2 /*return*/, null];
                        }
                        result = openflow_api_1.Role.assign(items[0]);
                        return [2 /*return*/, result];
                }
            });
        });
    };
    DBHelper.Save = function (item, jwt, parent) {
        return __awaiter(this, void 0, void 0, function () {
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, Config_1.Config.db._UpdateOne(null, item, "users", 0, false, jwt, parent)];
                    case 1:
                        _a.sent();
                        return [2 /*return*/];
                }
            });
        });
    };
    DBHelper.EnsureRole = function (jwt, name, id, parent) {
        return __awaiter(this, void 0, void 0, function () {
            var span, role, error_7;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        span = Logger_1.Logger.otel.startSubSpan("dbhelper.EnsureRole", parent);
                        _a.label = 1;
                    case 1:
                        _a.trys.push([1, 7, 8, 9]);
                        return [4 /*yield*/, this.FindRoleByNameOrId(name, id, span)];
                    case 2:
                        role = _a.sent();
                        if (role !== null && (role._id === id || id === null)) {
                            return [2 /*return*/, role];
                        }
                        if (!(role !== null && !openflow_api_1.NoderedUtil.IsNullEmpty(role._id))) return [3 /*break*/, 4];
                        return [4 /*yield*/, Config_1.Config.db.DeleteOne(role._id, "users", jwt)];
                    case 3:
                        _a.sent();
                        _a.label = 4;
                    case 4:
                        role = new openflow_api_1.Role();
                        role.name = name;
                        role._id = id;
                        return [4 /*yield*/, Config_1.Config.db.InsertOne(role, "users", 0, false, jwt, span)];
                    case 5:
                        role = _a.sent();
                        role = openflow_api_1.Role.assign(role);
                        openflow_api_1.Base.addRight(role, openflow_api_1.WellknownIds.admins, "admins", [openflow_api_1.Rights.full_control]);
                        openflow_api_1.Base.addRight(role, role._id, role.name, [openflow_api_1.Rights.full_control]);
                        openflow_api_1.Base.removeRight(role, role._id, [openflow_api_1.Rights.delete]);
                        return [4 /*yield*/, this.Save(role, jwt, span)];
                    case 6:
                        _a.sent();
                        return [2 /*return*/, openflow_api_1.Role.assign(role)];
                    case 7:
                        error_7 = _a.sent();
                        span.recordException(error_7);
                        throw error_7;
                    case 8:
                        Logger_1.Logger.otel.endSpan(span);
                        return [7 /*endfinally*/];
                    case 9: return [2 /*return*/];
                }
            });
        });
    };
    DBHelper.ensureUser = function (jwt, name, username, id, password, parent) {
        return __awaiter(this, void 0, void 0, function () {
            var span, user, users, name_1, noderedadmins, error_8;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        span = Logger_1.Logger.otel.startSubSpan("dbhelper.ensureUser", parent);
                        _a.label = 1;
                    case 1:
                        _a.trys.push([1, 17, 18, 19]);
                        return [4 /*yield*/, this.FindByUsernameOrId(username, id, span)];
                    case 2:
                        user = _a.sent();
                        if (user !== null && (user._id === id || id === null)) {
                            return [2 /*return*/, user];
                        }
                        if (!(user !== null && id !== null)) return [3 /*break*/, 4];
                        return [4 /*yield*/, Config_1.Config.db.DeleteOne(user._id, "users", jwt)];
                    case 3:
                        _a.sent();
                        _a.label = 4;
                    case 4:
                        user = new openflow_api_1.User();
                        user._id = id;
                        user.name = name;
                        user.username = username;
                        if (!(password !== null && password !== undefined && password !== "")) return [3 /*break*/, 6];
                        return [4 /*yield*/, Crypt_1.Crypt.SetPassword(user, password, span)];
                    case 5:
                        _a.sent();
                        return [3 /*break*/, 8];
                    case 6: return [4 /*yield*/, Crypt_1.Crypt.SetPassword(user, Math.random().toString(36).substr(2, 9), span)];
                    case 7:
                        _a.sent();
                        _a.label = 8;
                    case 8: return [4 /*yield*/, Config_1.Config.db.InsertOne(user, "users", 0, false, jwt, span)];
                    case 9:
                        user = _a.sent();
                        user = openflow_api_1.User.assign(user);
                        openflow_api_1.Base.addRight(user, openflow_api_1.WellknownIds.admins, "admins", [openflow_api_1.Rights.full_control]);
                        openflow_api_1.Base.addRight(user, user._id, user.name, [openflow_api_1.Rights.full_control]);
                        openflow_api_1.Base.removeRight(user, user._id, [openflow_api_1.Rights.delete]);
                        return [4 /*yield*/, this.Save(user, jwt, span)];
                    case 10:
                        _a.sent();
                        return [4 /*yield*/, this.FindRoleByName("users", span)];
                    case 11:
                        users = _a.sent();
                        users.AddMember(user);
                        if (!Config_1.Config.auto_create_personal_nodered_group) return [3 /*break*/, 14];
                        name_1 = user.username;
                        name_1 = name_1.split("@").join("").split(".").join("");
                        name_1 = name_1.toLowerCase();
                        return [4 /*yield*/, this.EnsureRole(jwt, name_1 + "noderedadmins", null, span)];
                    case 12:
                        noderedadmins = _a.sent();
                        openflow_api_1.Base.addRight(noderedadmins, user._id, user.username, [openflow_api_1.Rights.full_control]);
                        openflow_api_1.Base.removeRight(noderedadmins, user._id, [openflow_api_1.Rights.delete]);
                        noderedadmins.AddMember(user);
                        return [4 /*yield*/, this.Save(noderedadmins, jwt, span)];
                    case 13:
                        _a.sent();
                        _a.label = 14;
                    case 14: return [4 /*yield*/, this.Save(users, jwt, span)];
                    case 15:
                        _a.sent();
                        return [4 /*yield*/, this.DecorateWithRoles(user, span)];
                    case 16:
                        _a.sent();
                        return [2 /*return*/, user];
                    case 17:
                        error_8 = _a.sent();
                        span.recordException(error_8);
                        throw error_8;
                    case 18:
                        Logger_1.Logger.otel.endSpan(span);
                        return [7 /*endfinally*/];
                    case 19: return [2 /*return*/];
                }
            });
        });
    };
    DBHelper.cached_roles = [];
    DBHelper.cached_at = new Date();
    return DBHelper;
}());
exports.DBHelper = DBHelper;
//# sourceMappingURL=DBHelper.js.map