/*! meta-admin/modules/users */
/*jslint
browser, long
*/
/*global
Blob, confirm
*/
/**
* users component.
*
* @module meta-admin/modules/component/users
*/
import ko from "knockout";
import Logger from "js-logger";
import objects from "meta-client/modules/objects";
import protocol from "meta-core/modules/protocol";
import model from "meta-core/modules/model";
import template from "./users.html";
import _ from "underscore";
import dates from "util-web/modules/dates";
import i18next from "util-web/modules/i18next";
import nav from "util-web/modules/nav";
import ui from "util-web/modules/ui";
const LOG = Logger.get("meta-admin/users");
const DEFAULT_GRANTS = Object.freeze(function () {
const grants = {};
Object.keys(model.metaGrantKeys).forEach(function (key) {
grants[model.metaGrantKeys[key]] = 0;
});
return grants;
}());
const GRANT_LIST = Object.keys(model.metaGrantKeys).map(function (grantKey) {
return {
key: grantKey,
value: model.metaGrantKeys[grantKey]
};
});
const PERMISSION_LIST = Object.keys(model.metaGrantPermission).map(function (grantPermission) {
return grantPermission + " = " + model.metaGrantPermission[grantPermission];
}).join("\n");
export default Object.freeze({
template,
viewModel: {
createViewModel: function ({viewmodel}) {
const vm = {};
vm.metaGrants = GRANT_LIST;
vm.metaGrantsList = GRANT_LIST.map((metaGrant) => metaGrant.key + " = " + metaGrant.value).join("\n");
vm.permissionList = PERMISSION_LIST;
vm.viewmodel = viewmodel;
vm.activeTab = ko.observable();
vm.userSearcher = objects({
searchReplyObjectsPath: "users",
sort: viewmodel.sortByName,
toVm: (user) => vm.viewmodel.userToVm(model.metaUser(user))
});
vm.groupSearcher = objects({
searchReplyObjectsPath: "groups",
sort: viewmodel.sortByName,
toVm: (group) => vm.viewmodel.groupToVm(model.metaUserGroup(group))
});
vm.configSearcher = objects({
searchReplyObjectsPath: "configs",
toVm: (userConfig) => vm.viewmodel.userConfigToVm(model.metaUserConfig(userConfig))
});
vm.editedUser = ko.observable();
vm.removeOtp = ko.observable(false);
vm.removeWebauthn = ko.observable(false);
vm.isSavingUser = ko.observable(false);
vm.editedGroup = ko.observable();
vm.isSavingGroup = ko.observable(false);
vm.editedConfig = ko.observable();
vm.isSavingConfig = ko.observable(false);
vm.saveSuccess = ko.observable();
vm.errorReply = ko.observable();
vm.cancel = function () {
vm.editedUser(undefined);
vm.editedGroup(undefined);
vm.editedConfig(undefined);
};
vm.newUser = function (optionalUser) {
const user = optionalUser || model.metaUser({
grants: DEFAULT_GRANTS,
name: "user" + dates.now().toMillis()
});
const userVm = vm.viewmodel.userToVm(user);
LOG.debug("newUser");
userVm.isNew(true);
vm.editUser(userVm);
vm.navigateToTab(vm.viewmodel.USERS_TABS.USERS);
};
vm.cloneUser = function () {
const userVm = vm.editedUser();
const user = vm.viewmodel.vmToUser(userVm);
user.name = user.name + "clone";
vm.newUser(user);
};
vm.userQuery = ko.observable();
vm.searchUsersInternal = function (limit, clearSearch) {
LOG.debug("searchUsersInternal");
if (clearSearch) {
vm.userSearcher.clear();
}
return vm.userSearcher.processSearch(vm.viewmodel.client.userSearch(protocol.userSearchRequest({
cursor: vm.userSearcher.searchCursor(),
limit,
query: vm.userQuery()
}))).then(function () {
vm.errorReply(undefined);
}, function (exc) {
LOG.warn("searchUsersInternal failed", exc);
vm.errorReply(JSON.stringify(exc, undefined, 4));
});
};
vm.searchUsers = function (form) {
if (ui.validateForm(form) === false) {
return;
}
LOG.debug("searchUsers");
return vm.searchUsersInternal(100, true).then(function () {
ui.resetForm(form);
});
};
vm.loadMoreUsers = function () {
LOG.debug("loadMoreUsers");
return vm.searchUsersInternal(100, false);
};
vm.loadAllUsers = function () {
LOG.debug("loadAllUsers");
return vm.searchUsersInternal(0, false);
};
vm.editUser = function (user) {
LOG.debug(`editUser, user=${user.name()}`);
vm.cancel();
vm.editedUser(user);
};
vm.insertGrant = function (id, value) {
const textAreaId = (
vm.editedUser()
? "userGrants"
: "groupGrants"
);
ui.insertText("#" + textAreaId, `\n "${id}": ${value},`);
};
vm.selectedMetaGrant = ko.observable();
vm.selectedMetaGrant.subscribe(function (metaGrant) {
if (Boolean(metaGrant) === false) {
return;
}
LOG.debug(`selectedMetaGrant, metaGrant=${metaGrant}`);
vm.insertGrant(metaGrant, String(model.metaGrantPermission.ALLOW));
vm.selectedMetaGrant(undefined);
});
vm.selectedTypeGrant = ko.observable();
vm.selectedTypeGrant.subscribe(function (type) {
if (Boolean(type) === false) {
return;
}
LOG.debug(`selectedTypeGrant, type=${type}`);
vm.insertGrant(type, String(model.metaGrantPermission.ALLOW));
vm.selectedTypeGrant(undefined);
});
vm.selectedActionGrant = ko.observable();
vm.selectedActionGrant.subscribe(function (action) {
if (Boolean(action) === false) {
return;
}
LOG.debug(`selectedActionGrant, action=${action}`);
vm.insertGrant(action, String(model.metaGrantPermission.ALLOW));
vm.selectedActionGrant(undefined);
});
vm.saveUser = function (form) {
const userVm = vm.editedUser();
if (ui.validateForm(form) === false) {
return;
}
LOG.debug(`saveUser, user=${userVm.name()}`);
vm.isSavingUser(true);
if (vm.removeOtp()) {
delete userVm.otp;
}
if (vm.removeWebauthn()) {
delete userVm.webAuthn;
}
const user = vm.viewmodel.vmToUser(userVm);
return vm.viewmodel.client.userWrite(protocol.userWriteRequest({
action: (
userVm.isNew()
? protocol.WRITE_ACTION.CREATE
: protocol.WRITE_ACTION.UPDATE
),
user
})).then(function (reply) {
vm.errorReply(undefined);
vm.removeOtp(false);
vm.removeWebauthn(false);
userVm.isNew(false);
vm.editedUser(ko.mapping.fromJS(reply.user, userVm));
vm.saveSuccess("user_save_success");
ui.resetForm(form);
}, function (exc) {
LOG.warn("saveUser failed", exc);
vm.errorReply(JSON.stringify(exc, undefined, 4));
}).then(function () {
vm.isSavingUser(false);
});
};
vm.isDeletingUser = ko.observable(false);
vm.deleteUser = function () {
const userVm = vm.editedUser();
const user = vm.viewmodel.vmToUser(userVm);
LOG.debug(`deleteUser, user=${userVm.name()}`);
if (confirm(i18next.t("delete_user_confirmation")) === false) {
return;
}
vm.isDeletingUser(true);
return vm.viewmodel.client.userWrite(protocol.userWriteRequest({
action: protocol.WRITE_ACTION.DELETE,
user
})).then(function () {
vm.errorReply(undefined);
userVm.deleted(true);
vm.editedUser(undefined);
}, function (exc) {
LOG.warn("deleteUser failed", exc);
vm.errorReply(JSON.stringify(exc, undefined, 4));
}).then(function () {
vm.isDeletingUser(false);
});
};
vm.newGroup = function (optionalGroup) {
const group = optionalGroup || model.metaUserGroup({
grants: {},
name: "group" + dates.now().toMillis(),
users: []
});
const groupVm = vm.viewmodel.groupToVm(group);
LOG.debug("newGroup");
groupVm.isNew(true);
vm.editGroup(groupVm);
vm.navigateToTab(vm.viewmodel.USERS_TABS.GROUPS);
};
vm.cloneGroup = function () {
const groupVm = vm.editedGroup();
const group = vm.viewmodel.vmToGroup(groupVm);
group.name = group.name + "clone";
vm.newGroup(group);
};
vm.groupQuery = ko.observable();
vm.searchGroupsInternal = function (limit, clearSearch) {
if (clearSearch) {
vm.groupSearcher.clear();
}
return vm.groupSearcher.processSearch(vm.viewmodel.client.groupSearch(protocol.userGroupSearchRequest({
cursor: vm.groupSearcher.searchCursor(),
limit,
query: vm.groupQuery()
}))).then(function () {
vm.errorReply(undefined);
}, function (exc) {
LOG.warn("searchGroupsInternal failed", exc);
vm.errorReply(JSON.stringify(exc, undefined, 4));
});
};
vm.searchGroups = function (form) {
if (ui.validateForm(form) === false) {
return;
}
LOG.debug("searchGroups");
return vm.searchGroupsInternal(100, true).then(function () {
ui.resetForm(form);
});
};
vm.loadMoreGroups = function () {
LOG.debug("loadMoreGroups");
return vm.searchGroupsInternal(100, false);
};
vm.loadAllGroups = function () {
LOG.debug("loadAllGroups");
return vm.searchGroupsInternal(0, false);
};
vm.editGroup = function (group) {
LOG.debug(`editGroup, group=${group.name()}`);
vm.cancel();
vm.editedGroup(group);
};
vm.saveGroup = function (form) {
const groupVm = vm.editedGroup();
if (ui.validateForm(form) === false) {
return;
}
LOG.debug(`saveGroup, group=${groupVm.name()}`);
vm.isSavingGroup(true);
const group = vm.viewmodel.vmToGroup(groupVm);
return vm.viewmodel.client.groupWrite(protocol.userGroupWriteRequest({
action: (
groupVm.isNew()
? protocol.WRITE_ACTION.CREATE
: protocol.WRITE_ACTION.UPDATE
),
group
})).then(function (reply) {
vm.errorReply(undefined);
vm.editedGroup(ko.mapping.fromJS(reply.group, groupVm));
vm.saveSuccess("group_save_success");
ui.resetForm(form);
}, function (exc) {
LOG.warn("saveGroup failed", exc);
vm.errorReply(JSON.stringify(exc, undefined, 4));
}).then(function () {
vm.isSavingGroup(false);
});
};
vm.isDeletingGroup = ko.observable(false);
vm.deleteGroup = function () {
const groupVm = vm.editedGroup();
const group = vm.viewmodel.vmToGroup(groupVm);
LOG.debug(`deleteGroup, group=${groupVm.name()}`);
if (confirm(i18next.t("delete_user_confirmation")) === false) {
return;
}
vm.isDeletingGroup(true);
return vm.viewmodel.client.userWrite(protocol.userGroupWriteRequest({
action: protocol.WRITE_ACTION.DELETE,
group
})).then(function () {
vm.errorReply(undefined);
groupVm.deleted(true);
vm.editedGroup(undefined);
}, function (exc) {
LOG.warn("deleteGroup failed", exc);
vm.errorReply(JSON.stringify(exc, undefined, 4));
}).then(function () {
vm.isDeletingGroup(false);
});
};
vm.isUpdateActive = ko.observable(false);
vm.isUpdating = ko.observable(false);
vm.updateUsersAdd = ko.observable();
vm.isUpdateUsersAddValid = ko.observable(true);
vm.updateUsersAddString = viewmodel.newComputedJsonField(vm.updateUsersAdd, undefined, vm.isUpdateUsersAddValid);
vm.updateUsersRemove = ko.observable();
vm.isUpdateUsersRemoveValid = ko.observable(true);
vm.updateUsersRemoveString = viewmodel.newComputedJsonField(vm.updateUsersRemove, undefined, vm.isUpdateUsersRemoveValid);
vm.updateGrantsAdd = ko.observable();
vm.isUpdateGrantsAddValid = ko.observable(true);
vm.updateGrantsAddString = viewmodel.newComputedJsonField(vm.updateGrantsAdd, undefined, vm.isUpdateGrantsAddValid);
vm.updateGrantsRemove = ko.observable();
vm.isUpdateGrantsRemoveValid = ko.observable(true);
vm.updateGrantsRemoveString = viewmodel.newComputedJsonField(vm.updateGrantsRemove, undefined, vm.isUpdateGrantsRemoveValid);
vm.activateUpdate = function () {
vm.updateUsersAdd(undefined);
vm.updateUsersAddString.format();
vm.updateUsersRemove(undefined);
vm.updateUsersRemoveString.format();
vm.updateGrantsAdd(undefined);
vm.updateGrantsAddString.format();
vm.updateGrantsRemove(undefined);
vm.updateGrantsRemoveString.format();
vm.isUpdateActive(true);
};
vm.update = function (form) {
if (ui.validateForm(form) === false) {
return;
}
LOG.debug("update");
vm.isUpdating(true);
const isGroup = vm.editedGroup();
const updatePromise = (
isGroup
? vm.viewmodel.client.groupWriteUpdate(protocol.userGroupWriteUpdateRequest({
addGrants: vm.updateGrantsAdd(),
addUsers: vm.updateUsersAdd(),
group: vm.editedGroup().name(),
removeGrants: vm.updateGrantsRemove(),
removeUsers: vm.updateUsersRemove()
}))
: vm.viewmodel.client.userWriteUpdate(protocol.userWriteUpdateRequest({
addGrants: vm.updateGrantsAdd(),
removeGrants: vm.updateGrantsRemove(),
user: vm.editedUser().name()
}))
);
return updatePromise.then(function () {
// TODO reload edited user/group
vm.errorReply(undefined);
vm.isUpdateActive(false);
vm.saveSuccess(
isGroup
? "group_save_success"
: "user_save_success"
);
ui.resetForm(form);
}, function (exc) {
LOG.warn("update failed", exc);
vm.errorReply(JSON.stringify(exc, undefined, 4));
}).then(function () {
vm.isUpdating(false);
});
};
vm.newConfig = function (optionalUserConfig) {
const userConfig = optionalUserConfig || model.metaUserConfig({config: {}});
const configVm = vm.viewmodel.userConfigToVm(userConfig);
LOG.debug("newConfig");
configVm.isNew(true);
vm.editConfig(configVm);
vm.navigateToTab(vm.viewmodel.USERS_TABS.CONFIGS);
};
vm.cloneConfig = function () {
const configVm = vm.editedConfig();
const userConfig = vm.viewmodel.vmToUserConfig(configVm);
vm.newConfig(userConfig);
};
vm.configQuery = ko.observable();
vm.searchConfigsInternal = function (limit, clearSearch) {
if (clearSearch) {
vm.configSearcher.clear();
}
return vm.configSearcher.processSearch(vm.viewmodel.client.configSearch(protocol.userConfigSearchRequest({
cursor: vm.configSearcher.searchCursor(),
limit,
query: vm.configQuery()
}))).then(function () {
vm.errorReply(undefined);
}, function (exc) {
LOG.warn("searchConfigsInternal failed", exc);
vm.errorReply(JSON.stringify(exc, undefined, 4));
});
};
vm.searchConfigs = function (form) {
if (ui.validateForm(form) === false) {
return;
}
LOG.debug("searchConfigs");
return vm.searchConfigsInternal(100, true).then(function () {
ui.resetForm(form);
});
};
vm.loadMoreConfigs = function () {
LOG.debug("loadMoreConfigs");
return vm.searchConfigsInternal(100, false);
};
vm.loadAllConfigs = function () {
LOG.debug("loadAllConfigs");
return vm.searchConfigsInternal(0, false);
};
vm.editConfig = function (userConfig) {
LOG.debug(`editConfig, id=${userConfig.id}`);
vm.cancel();
vm.editedConfig(userConfig);
};
vm.saveConfig = function (form) {
const configVm = vm.editedConfig();
if (ui.validateForm(form) === false) {
return;
}
LOG.debug(`saveConfig, id=${configVm.id}`);
vm.isSavingConfig(true);
const userConfig = vm.viewmodel.vmToUserConfig(configVm);
return vm.viewmodel.client.configWrite(protocol.userConfigWriteRequest({
action: (
configVm.isNew()
? protocol.WRITE_ACTION.CREATE
: protocol.WRITE_ACTION.UPDATE
),
config: userConfig
})).then(function (reply) {
vm.errorReply(undefined);
vm.editedConfig(ko.mapping.fromJS(reply.config, configVm));
vm.saveSuccess("config_save_success");
ui.resetForm(form);
}, function (exc) {
LOG.warn("saveConfig failed", exc);
vm.errorReply(JSON.stringify(exc, undefined, 4));
}).then(function () {
vm.isSavingConfig(false);
});
};
vm.isDeletingConfig = ko.observable(false);
vm.deleteConfig = function () {
const configVm = vm.editedConfig();
const userConfig = vm.viewmodel.vmToUserConfig(configVm);
LOG.debug(`deleteConfig, id=${configVm.id}`);
if (confirm(i18next.t("delete_user_confirmation")) === false) {
return;
}
vm.isDeletingConfig(true);
return vm.viewmodel.client.configWrite(protocol.userConfigWriteRequest({
action: protocol.WRITE_ACTION.DELETE,
config: userConfig
})).then(function () {
vm.errorReply(undefined);
configVm.deleted(true);
vm.editedConfig(undefined);
}, function (exc) {
LOG.warn("deleteConfig failed", exc);
vm.errorReply(JSON.stringify(exc, undefined, 4));
}).then(function () {
vm.isDeletingConfig(false);
});
};
vm.viewmodel.userCreateHook.subscribe(function (create) {
if (_.isEmpty(create)) {
return;
}
return vm.viewmodel.navigateToUsers().then(function () {
if ("user" === create) {
vm.newUser();
}
if ("group" === create) {
vm.newGroup();
}
if ("userConfig" === create) {
vm.newConfig();
}
vm.viewmodel.userCreateHook(undefined);
});
});
vm.navigateToTab = vm.viewmodel.navigateToTab.bind(undefined, vm.viewmodel.COMPONENTS.USERS);
vm.onNavUpdate = function (tab) {
const activeTab = (
_.isEmpty(tab)
? vm.viewmodel.USERS_TABS.USERS
: tab
);
LOG.debug(`onNavUpdate, tab=${tab}, activeTab=${activeTab}`);
vm.activeTab(activeTab);
};
nav.register({
id: vm.viewmodel.COMPONENTS.USERS,
onUpdate: vm.onNavUpdate
});
return Object.freeze(vm);
}
}
});