diff --git a/CHANGELOG b/CHANGELOG index bafb6e926527f4bacaea944a8fbc4c26b02bccca..65aa1b9b07c4d8866dd60a3b828bb320828d6069 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,7 @@ minerva (14.0.0~beta.0) unstable; urgency=low project (#926) * Small improvement: information about person who uploaded project is visible in list of projects (#927) + * Small improvement: user role introduced in edit user dialog (#924) * Bug fix: work on FF Private Window mode could cause logout or raise an error on when opening new tab with minerva (#892) * Bug fix: fetching list of miRnas resulted sometimes in "Internal Server diff --git a/frontend-js/src/main/js/ServerConnector.js b/frontend-js/src/main/js/ServerConnector.js index 7fc0fc8ff0f4321ce69afca48f3b1378e57a16fc..0e991151fde07fc8cd9c727dd0d32cceaceb7092 100644 --- a/frontend-js/src/main/js/ServerConnector.js +++ b/frontend-js/src/main/js/ServerConnector.js @@ -67,6 +67,12 @@ ServerConnector.init = function () { self._projectsById = []; self._users = []; + + /** + * + * @type {Object.<string,User>} + * @private + */ self._usersByLogin = []; self._customMap = null; @@ -1528,13 +1534,16 @@ ServerConnector.grantUserPrivileges = function (params) { }).then(function (content) { var obj = JSON.parse(content); var user = new User(obj); + var promise = Promise.resolve(); if (self._usersByLogin[user.getLogin()] !== undefined) { - self._usersByLogin[user.getLogin()].update(user); + promise = self._usersByLogin[user.getLogin()].update(user); } else { self._usersByLogin[user.getLogin()] = user; } - return self._usersByLogin[user.getLogin()]; - }).then(null, function (error) { + return promise; + }).then(function () { + return self._usersByLogin[params.user.getLogin()]; + }).catch(function (error) { return self.processNetworkError(error); }); }; diff --git a/frontend-js/src/main/js/gui/admin/EditProjectDialog.js b/frontend-js/src/main/js/gui/admin/EditProjectDialog.js index c04e9ecbc439955d4e5a5ee291de24bd6d63d9ac..ce8f71f5a265ebe5d471b7effc2c313349ac5473 100644 --- a/frontend-js/src/main/js/gui/admin/EditProjectDialog.js +++ b/frontend-js/src/main/js/gui/admin/EditProjectDialog.js @@ -616,12 +616,10 @@ EditProjectDialog.prototype.createUsersTabContent = function () { } else { return self.revokePrivilege(self._userByLogin[login], type, self.getProject().getProjectId()); } - }) - ; + }); return result; -} -; +}; /** * @@ -889,6 +887,12 @@ EditProjectDialog.prototype.userToTableRow = function (user, columns) { var row = []; var login = user.getLogin(); + var isAdmin = user.hasPrivilege(self.getConfiguration().getPrivilegeType(PrivilegeType.IS_ADMIN)); + var disabled = ""; + if (isAdmin) { + disabled = " disabled " + } + row[0] = user.getName() + " " + user.getSurname() + " (" + login + ")"; for (var i = 1; i < columns.length; i++) { var column = columns[i]; @@ -899,7 +903,10 @@ EditProjectDialog.prototype.userToTableRow = function (user, columns) { checked = 'checked'; } row[i] = "<input type='checkbox' name='privilege" + "' data='" + column.privilegeType.getName() + "," + login + "' " - + checked + "/>"; + + checked + disabled + "/>"; + if (isAdmin) { + row[i] += " ADMIN"; + } } else { throw new Error("Unsupported type: " + column.privilegeType.getValueType()); } diff --git a/frontend-js/src/main/js/gui/admin/EditUserDialog.js b/frontend-js/src/main/js/gui/admin/EditUserDialog.js index 3cc088725d81d757c82bf52fc7784537ed24881e..7fe99b3fcb98152d8856995df75bd6ab501b8521 100644 --- a/frontend-js/src/main/js/gui/admin/EditUserDialog.js +++ b/frontend-js/src/main/js/gui/admin/EditUserDialog.js @@ -86,10 +86,6 @@ EditUserDialog.prototype.createGui = function () { name: "DETAILS", content: self.createGeneralTabContent() }); - guiUtils.addTab(self, { - name: "GLOBAL PRIVILEGES", - content: self.createPrivilegesTabContent() - }); guiUtils.addTab(self, { name: "PROJECT PRIVILEGES", content: self.createProjectsTabContent() @@ -199,47 +195,43 @@ EditUserDialog.prototype.createGeneralTabContent = function () { } } }); - return result; - -}; - -/** - * - * @returns {HTMLElement} - */ -EditUserDialog.prototype.createPrivilegesTabContent = function () { - var self = this; - var result = Functions.createElement({ - type: "div", - style: "margin-top:10px;" - }); - result.appendChild(self._createPrivilegesTable()); - return result; -}; - -/** - * - * @returns {HTMLElement} - * @private - */ -EditUserDialog.prototype._createPrivilegesTable = function () { - var result = Functions.createElement({ - type: "div", - style: "margin-top:10px;" + $(result).on('change', '[name="user-can-create-overlay"]', function () { + if ($(this).is(":checked")) { + return self.grantPrivilege({privilegeType: PrivilegeType.CAN_CREATE_OVERLAYS}); + } else { + return self.revokePrivilege({privilegeType: PrivilegeType.CAN_CREATE_OVERLAYS}); + } }); - var privilegesTable = Functions.createElement({ - type: "table", - name: "privilegesTable", - className: "display", - style: "width:100%" - }); - result.appendChild(privilegesTable); + $(result).on("click", "[name='user-role-" + self.getUser().getLogin() + "']", function () { + var field = this; + var role = $('[name="user-role-' + self.getUser().getLogin() + '"]:checked', field).val(); + var promises = []; + if (role === "ADMIN") { + promises.push(self.grantPrivilege({privilegeType: PrivilegeType.IS_ADMIN})); + promises.push(self.revokePrivilege({privilegeType: PrivilegeType.IS_CURATOR})); + $("[name='user-can-create-overlay-div']", result).css("display", "none"); + guiUtils.disableTab($(".minerva-project-privileges-tab", self.getElement())[0], "Admin can do everything") + } else if (role === "CURATOR") { + promises.push(self.revokePrivilege({privilegeType: PrivilegeType.IS_ADMIN})); + promises.push(self.grantPrivilege({privilegeType: PrivilegeType.IS_CURATOR})); + $("[name='user-can-create-overlay-div']", result).css("display", "none"); + guiUtils.enableTab($(".minerva-project-privileges-tab", self.getElement())[0]); + } else if (role === "USER") { + promises.push(self.revokePrivilege({privilegeType: PrivilegeType.IS_ADMIN})); + promises.push(self.revokePrivilege({privilegeType: PrivilegeType.IS_CURATOR})); + $("[name='user-can-create-overlay-div']", result).css("display", "block"); + guiUtils.enableTab($(".minerva-project-privileges-tab", self.getElement())[0]); + } else { + GuiConnector.alert("Invalid role: " + role); + } + return Promise.all(promises); + } + ); return result; }; - /** * * @returns {HTMLElement} @@ -248,7 +240,8 @@ EditUserDialog.prototype.createProjectsTabContent = function () { var self = this; var result = Functions.createElement({ type: "div", - style: "margin-top:10px;" + style: "margin-top:10px;", + className: "minerva-project-privileges-tab" }); result.appendChild(self._createProjectsTable()); return result; @@ -303,7 +296,6 @@ EditUserDialog.prototype.init = function () { }); self.initProjectsTab(); - self.initPrivilegesTab(); return self.refresh().then(function () { $(window).trigger('resize'); @@ -331,11 +323,49 @@ EditUserDialog.prototype.refresh = function () { data.push(['Surname', '<input name="userSurname" value="' + getStringIfDefined(user.getSurname()) + '"/>']); data.push(['Email', '<input name="userEmail" value="' + getStringIfDefined(user.getEmail()) + '"/>']); + var userRoleId = 'user-role-' + user.getLogin(); + + var adminChecked = ''; + var curatorChecked = ''; + var userChecked = ''; + var canCreateOverlayDisplay = "none"; + var canCreateOverlayChecked = ""; + + if (self.getIsNewUser()) { + var option = self.getConfiguration().getOption('DEFAULT_' + PrivilegeType.CAN_CREATE_OVERLAYS); + if (option !== null && option !== undefined) { + if (option.getValue().toLowerCase() === "true") { + user.setPrivilege({privilegeType: PrivilegeType.CAN_CREATE_OVERLAYS}); + } + } + } + + if (user.hasPrivilege(self.getConfiguration().getPrivilegeType(PrivilegeType.CAN_CREATE_OVERLAYS))) { + canCreateOverlayChecked = " checked "; + } + + if (user.hasPrivilege(self.getConfiguration().getPrivilegeType(PrivilegeType.IS_ADMIN))) { + adminChecked = " checked "; + guiUtils.disableTab($(".minerva-project-privileges-tab", self.getElement())[0], "Admin can do everything"); + } else if (user.hasPrivilege(self.getConfiguration().getPrivilegeType(PrivilegeType.IS_CURATOR))) { + curatorChecked = " checked "; + } else { + canCreateOverlayDisplay = "block"; + userChecked = " checked "; + } + data.push(["Role", + "<fieldset name='userRole' id='" + userRoleId + "'> " + + "<input type='radio' name='" + userRoleId + "' value='ADMIN' " + adminChecked + "> ADMIN<br/>" + + "<input type='radio' name='" + userRoleId + "' value='CURATOR' " + curatorChecked + "> CURATOR<br/>" + + "<input type='radio' name='" + userRoleId + "' value='USER' " + userChecked + "> USER <br/>" + + "<div name='user-can-create-overlay-div' style='display:" + canCreateOverlayDisplay + ";'>" + + "<input type='checkbox' style='float:left; ' name='user-can-create-overlay' " + canCreateOverlayChecked + "> User can create overlays " + + "</div>" + + "</fieldset>"]); + dataTable.clear().rows.add(data).draw(); - return self.refreshProjects().then(function () { - return self.refreshPrivilegesTab(); - }); + return self.refreshProjects(); }; /** @@ -385,36 +415,6 @@ EditUserDialog.prototype.initProjectsTab = function () { }); }; -/** - * - */ -EditUserDialog.prototype.initPrivilegesTab = function () { - var self = this; - - var privilegesTable = $("[name=privilegesTable]", self.getElement())[0]; - - var columns = [{ - title: "Name" - }, { - title: "Value" - }]; - - $(privilegesTable).DataTable({ - columns: columns - }); - - $(privilegesTable).on("click", "[name='privilege-checkbox']", function () { - var data = $(this).attr("data").split(":"); - var type = data[0]; - var projectId = data[1]; - if ($(this).is(":checked")) { - return self.grantPrivilege({privilegeType: type, objectId: projectId}); - } else { - return self.revokePrivilege({privilegeType: type, objectId: projectId}); - } - }); -}; - /** * * @param {Authority} privilege @@ -453,45 +453,6 @@ EditUserDialog.prototype.revokePrivilege = function (privilege) { } }; -/** - * - */ -EditUserDialog.prototype.refreshPrivilegesTab = function () { - var self = this; - - var dataTable = $("[name=privilegesTable]", self.getElement()).DataTable(); - - var data = []; - var configuration = self.getConfiguration(); - for (var i = 0; i < configuration.getPrivilegeTypes().length; i++) { - var privilege = configuration.getPrivilegeTypes()[i]; - var option; - if (privilege.getObjectType() === null) { - if (privilege.getValueType() === "boolean") { - var checked = ""; - if (self.getUser().hasPrivilege(privilege)) { - checked = "checked" - } else if (this.getIsNewUser()) { - option = this.getConfiguration().getOption('DEFAULT_' + privilege.getName()); - if (option !== null && option !== undefined) { - if (option.getValue().toLowerCase() === "true") { - self.getUser().setPrivilege({privilegeType: privilege.getName()}); - checked = "checked"; - } - } - } - data.push([ - "<span>" + privilege.getCommonName() + "</span>", - "<input type='checkbox' name='privilege-checkbox' data='" + privilege.getName() + "' " + checked + " />" - ]); - } else { - throw new Error("Not implemented"); - } - } - } - dataTable.clear().rows.add(data).draw(); -}; - /** * * @returns {Promise} @@ -593,11 +554,6 @@ EditUserDialog.prototype.destroy = function () { $(usersTable).DataTable().destroy(); } - var privilegesTable = $("[name=privilegesTable]", div)[0]; - if ($.fn.DataTable.isDataTable(privilegesTable)) { - $(privilegesTable).DataTable().destroy(); - } - var detailsTable = $("[name=detailsTable]", div)[0]; if ($.fn.DataTable.isDataTable(detailsTable)) { $(detailsTable).DataTable().destroy(); diff --git a/frontend-js/src/main/js/gui/admin/MapsAdminPanel.js b/frontend-js/src/main/js/gui/admin/MapsAdminPanel.js index 0b4c5e32b520fe986ec45096ad157fbc373d9de4..fa98fe394c68171defb5f24301867c9c58d1e546 100644 --- a/frontend-js/src/main/js/gui/admin/MapsAdminPanel.js +++ b/frontend-js/src/main/js/gui/admin/MapsAdminPanel.js @@ -262,11 +262,11 @@ MapsAdminPanel.prototype.projectToTableRow = function (project, row, user) { date = date.split(" ")[0]; } row[1] = date; - row[2] = project.getName(); - row[3] = project.getOwner(); - if (row[3] === undefined) { - row[3] = 'N/A'; + row[2] = project.getOwner(); + if (row[2] === undefined) { + row[2] = 'N/A'; } + row[3] = project.getName(); row[4] = disease; row[5] = organism; row[6] = status; diff --git a/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js b/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js index a8cfddf2cc95f48bcf432ab616156f6aabdae987..e9b8ad55e5ddc9cddcde2e9993362d7d7128591a 100644 --- a/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js +++ b/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js @@ -1193,18 +1193,36 @@ GuiUtils.prototype.hideTab = function (abstractGuiElement, panel) { * @param {string} message */ GuiUtils.prototype.disableTab = function (element, message) { - $(element).children().css("visibility", "hidden"); - $("[class='minerva-help-button']", element).children().css("visibility", "visible"); - var hideReasonDiv = document.createElement("div"); - hideReasonDiv.className = "searchPanel"; - - var center = document.createElement("center"); - var messageDiv = document.createElement("h4"); - messageDiv.innerHTML = message; - center.appendChild(messageDiv); - hideReasonDiv.appendChild(center); - - $(element).prepend(hideReasonDiv); + var hideReason = $(".minerva-hide-reason", element); + if (hideReason.length === 0) { + console.log("not hidden"); + + $(element).children().css("visibility", "hidden"); + $("[class='minerva-help-button']", element).children().css("visibility", "visible"); + var hideReasonDiv = document.createElement("div"); + hideReasonDiv.className = "searchPanel minerva-hide-reason"; + + var center = document.createElement("center"); + var messageDiv = document.createElement("h4"); + messageDiv.innerHTML = message; + center.appendChild(messageDiv); + hideReasonDiv.appendChild(center); + + $(element).prepend(hideReasonDiv); + } +}; + +/** + * + * @param {HTMLElement} element + */ +GuiUtils.prototype.enableTab = function (element) { + var hideReason = $(".minerva-hide-reason", element); + if (hideReason.length > 0) { + hideReason.remove(); + $(element).children().css("visibility", "visible"); + $("[class='minerva-help-button']", element).children().css("visibility", "visible"); + } }; /** diff --git a/frontend-js/src/test/js/gui/admin/EditUserDialog-test.js b/frontend-js/src/test/js/gui/admin/EditUserDialog-test.js index fffbc379b3ca5fb7150114c9b6bf6f9d59f24672..2b46af2001f93a67ce27b31a44b16ab99c532c74 100644 --- a/frontend-js/src/test/js/gui/admin/EditUserDialog-test.js +++ b/frontend-js/src/test/js/gui/admin/EditUserDialog-test.js @@ -138,11 +138,12 @@ describe('EditUserDialog', function () { dialog = createEditUserDialog(user); return dialog.init(); }).then(function () { - var checkbox = $("[name=privilege-checkbox]", dialog.getElement())[0]; + var checkbox = $("[name=user-can-create-overlay]", dialog.getElement())[0]; checkbox.checked = !checkbox.checked; - return helper.triggerJqueryEvent(checkbox, "click"); + return helper.triggerJqueryEvent(checkbox, "change"); }).then(function () { expect(serializedPrivileges).not.to.deep.equal(user.getPrivileges()); + }).finally(function(){ dialog.destroy(); }); }); diff --git a/frontend-js/testFiles/apiCalls/users/anonymous.updatePrivileges/PATCH_privileges.CAN_CREATE_OVERLAYS=true&token=ADMIN_TOKEN_ID& b/frontend-js/testFiles/apiCalls/users/anonymous.updatePrivileges/PATCH_privileges.CAN_CREATE_OVERLAYS=true&token=ADMIN_TOKEN_ID& new file mode 100644 index 0000000000000000000000000000000000000000..8dd908e3027bbbb61b067e3b6250356bd23e8c42 --- /dev/null +++ b/frontend-js/testFiles/apiCalls/users/anonymous.updatePrivileges/PATCH_privileges.CAN_CREATE_OVERLAYS=true&token=ADMIN_TOKEN_ID& @@ -0,0 +1 @@ +{"connectedToLdap":false,"email":"","id":3,"ldapAccountAvailable":false,"login":"anonymous","maxColor":null,"minColor":null,"name":"","neutralColor":null,"privileges":[{"objectId":null,"privilegeType":"CAN_CREATE_OVERLAYS"}, {"objectId":"empty","privilegeType":"READ_PROJECT"},{"objectId":"parameter","privilegeType":"READ_PROJECT"},{"objectId":"drug_target_sample","privilegeType":"READ_PROJECT"},{"objectId":"GSTP1_subnetwork_220214","privilegeType":"READ_PROJECT"},{"objectId":"pdmap_jun16_test","privilegeType":"READ_PROJECT"},{"objectId":"CDlayerin_v2-semantic","privilegeType":"READ_PROJECT"},{"objectId":"PD_150625_3","privilegeType":"READ_PROJECT"},{"objectId":"doi","privilegeType":"READ_PROJECT"},{"objectId":"complex_model_with_images","privilegeType":"READ_PROJECT"},{"objectId":"complex_model_with_submaps","privilegeType":"READ_PROJECT"},{"objectId":"images","privilegeType":"READ_PROJECT"},{"objectId":"kinteics_test","privilegeType":"READ_PROJECT"},{"objectId":"species_with_boundary_cond","privilegeType":"READ_PROJECT"},{"objectId":"sample","privilegeType":"READ_PROJECT"},{"objectId":"complex_model_with_layouts","privilegeType":"READ_PROJECT"},{"objectId":"pdmap_jan17","privilegeType":"READ_PROJECT"},{"objectId":"ASTHMA_V40_Test9","privilegeType":"READ_PROJECT"},{"objectId":"CDlayerin_v2","privilegeType":"READ_PROJECT"}],"removed":false,"simpleColor":null,"surname":"","termsOfUseConsent":false} \ No newline at end of file diff --git a/frontend-js/testFiles/apiCalls/users/anonymous.updatePrivileges/PATCH_privileges.IS_ADMIN=true&token=ADMIN_TOKEN_ID& b/frontend-js/testFiles/apiCalls/users/anonymous.updatePrivileges/PATCH_privileges.IS_ADMIN=true&token=ADMIN_TOKEN_ID& deleted file mode 100644 index 2fd3a0360cfd862c5e319b59843a8fbfc9c2b681..0000000000000000000000000000000000000000 --- a/frontend-js/testFiles/apiCalls/users/anonymous.updatePrivileges/PATCH_privileges.IS_ADMIN=true&token=ADMIN_TOKEN_ID& +++ /dev/null @@ -1 +0,0 @@ -{"connectedToLdap":false,"email":"","id":3,"ldapAccountAvailable":false,"login":"anonymous","maxColor":null,"minColor":null,"name":"","neutralColor":null,"privileges":[{"objectId":null,"privilegeType":"IS_ADMIN"}, {"objectId":"empty","privilegeType":"READ_PROJECT"},{"objectId":"parameter","privilegeType":"READ_PROJECT"},{"objectId":"drug_target_sample","privilegeType":"READ_PROJECT"},{"objectId":"GSTP1_subnetwork_220214","privilegeType":"READ_PROJECT"},{"objectId":"pdmap_jun16_test","privilegeType":"READ_PROJECT"},{"objectId":"CDlayerin_v2-semantic","privilegeType":"READ_PROJECT"},{"objectId":"PD_150625_3","privilegeType":"READ_PROJECT"},{"objectId":"doi","privilegeType":"READ_PROJECT"},{"objectId":"complex_model_with_images","privilegeType":"READ_PROJECT"},{"objectId":"complex_model_with_submaps","privilegeType":"READ_PROJECT"},{"objectId":"images","privilegeType":"READ_PROJECT"},{"objectId":"kinteics_test","privilegeType":"READ_PROJECT"},{"objectId":"species_with_boundary_cond","privilegeType":"READ_PROJECT"},{"objectId":"sample","privilegeType":"READ_PROJECT"},{"objectId":"complex_model_with_layouts","privilegeType":"READ_PROJECT"},{"objectId":"pdmap_jan17","privilegeType":"READ_PROJECT"},{"objectId":"ASTHMA_V40_Test9","privilegeType":"READ_PROJECT"},{"objectId":"CDlayerin_v2","privilegeType":"READ_PROJECT"}],"removed":false,"simpleColor":null,"surname":"","termsOfUseConsent":false} \ No newline at end of file