diff --git a/frontend-js/src/main/js/ServerConnector.js b/frontend-js/src/main/js/ServerConnector.js
index 584e1a8d7e7a45f787765f4eaa9989da1daeaca0..e7786dd394f2d65c76ff0eb8bcc8662a6ed84301 100644
--- a/frontend-js/src/main/js/ServerConnector.js
+++ b/frontend-js/src/main/js/ServerConnector.js
@@ -204,7 +204,7 @@ ServerConnector.sendPatchRequest = function (url, json) {
 ServerConnector.getToken = function () {
   var self = this;
 
-  var login = self.getSessionData(null).getLogin()
+  var login = self.getSessionData(null).getLogin();
   var token = self.getSessionData(null).getToken();
   if (token === undefined || login === undefined) {
     return self.login();
@@ -858,7 +858,7 @@ ServerConnector.getLoggedUser = function () {
 ServerConnector.getUser = function (login) {
   var self = this;
   var queryParams = {
-    login: login,
+    login: login
   };
   var filterParams = {};
 
@@ -874,10 +874,31 @@ ServerConnector.getUser = function (login) {
   });
 };
 
+ServerConnector.updateUser = function (user) {
+  var self = this;
+  var queryParams = {
+    login: user.getLogin()
+  };
+  var filterParams = {
+    user: {
+      name: user.getName(),
+      surname: user.getSurname(),
+      password: user.getPassword(),
+      email: user.getEmail()
+    }
+  };
+  return self.sendPatchRequest(self.getUserUrl(queryParams), filterParams).then(function () {
+    return self.getConfiguration();
+  }).then(function (configuration) {
+    return self.updateUserPrivileges({user: user, privileges: user.privilegesToExport(configuration)});
+  });
+
+};
+
 ServerConnector.updateUserPrivileges = function (params) {
   var self = this;
   var queryParams = {
-    login: params.user.getLogin(),
+    login: params.user.getLogin()
   };
 
   return self.sendPatchRequest(self.getUpdateUserPrivilegesUrl(queryParams), {
@@ -891,8 +912,27 @@ ServerConnector.updateUserPrivileges = function (params) {
       self._usersByLogin[user.getLogin()] = user;
     }
     return self._usersByLogin[user.getLogin()];
+  }).then(null, function (error) {
+    return self.processNetworkError(error);
   });
 };
+
+ServerConnector.processNetworkError = function (error) {
+  if ((error instanceof NetworkError)) {
+    switch (error.statusCode) {
+      case HttpStatus.NOT_FOUND:
+        return null;
+      case HttpStatus.FORBIDDEN:
+        return Promise.reject(new SecurityError("Access denied."));
+      default:
+        return Promise.reject(error);
+    }
+  } else {
+    return Promise.reject(error);
+  }
+};
+
+
 ServerConnector.updateUserPreferences = function (params) {
   var self = this;
   var queryParams = {
diff --git a/frontend-js/src/main/js/gui/admin/EditProjectDialog.js b/frontend-js/src/main/js/gui/admin/EditProjectDialog.js
index b7293b8c72e741e49cd07f51b0e18e0a8d0f7885..cb84fb67409da81f879194e992467493dc4b940a 100644
--- a/frontend-js/src/main/js/gui/admin/EditProjectDialog.js
+++ b/frontend-js/src/main/js/gui/admin/EditProjectDialog.js
@@ -14,664 +14,664 @@ var logger = require('../../logger');
 var guiUtils = new (require('../leftPanel/GuiUtils'))();
 
 function EditProjectDialog(params) {
-    AbstractGuiElement.call(this, params);
-    var self = this;
-    $(self.getElement()).addClass("minerva-edit-project-dialog");
+  AbstractGuiElement.call(this, params);
+  var self = this;
+  $(self.getElement()).addClass("minerva-edit-project-dialog");
 
-    self.createGui();
+  self.createGui();
 }
 
 EditProjectDialog.prototype = Object.create(AbstractGuiElement.prototype);
 EditProjectDialog.prototype.constructor = EditProjectDialog;
 
 EditProjectDialog.prototype.createGui = function () {
-    var self = this;
-    var element = self.getElement();
-
-    var tabDiv = Functions.createElement({
-        type: "div",
-        name: "tabView",
-        className: "tabbable boxed parentTabs"
-    });
-    element.appendChild(tabDiv);
-
-    var tabMenuDiv = Functions.createElement({
-        type: "ul",
-        className: "nav nav-tabs"
-    });
-    tabDiv.appendChild(tabMenuDiv);
-
-    var tabContentDiv = Functions.createElement({
-        type: "div",
-        className: "tab-content"
-    });
-    tabDiv.appendChild(tabContentDiv);
-
-    self.createGeneralTab(tabMenuDiv, tabContentDiv);
-    self.createOverlaysTab(tabMenuDiv, tabContentDiv);
-    self.createUsersTab(tabMenuDiv, tabContentDiv);
+  var self = this;
+  var element = self.getElement();
+
+  var tabDiv = Functions.createElement({
+    type: "div",
+    name: "tabView",
+    className: "tabbable boxed parentTabs"
+  });
+  element.appendChild(tabDiv);
+
+  var tabMenuDiv = Functions.createElement({
+    type: "ul",
+    className: "nav nav-tabs"
+  });
+  tabDiv.appendChild(tabMenuDiv);
+
+  var tabContentDiv = Functions.createElement({
+    type: "div",
+    className: "tab-content"
+  });
+  tabDiv.appendChild(tabContentDiv);
+
+  self.createGeneralTab(tabMenuDiv, tabContentDiv);
+  self.createOverlaysTab(tabMenuDiv, tabContentDiv);
+  self.createUsersTab(tabMenuDiv, tabContentDiv);
 };
 
 EditProjectDialog.prototype.createGeneralTab = function (tabMenuDiv, tabContentDiv) {
-    var self = this;
-    self.addTab({
-        tabMenuDiv: tabMenuDiv,
-        tabContentDiv: tabContentDiv,
-        name: "GENERAL",
-        id: self.getProject().getProjectId() + "_general_tab",
-        content: self.createGeneralTabContent(),
-    });
+  var self = this;
+  self.addTab({
+    tabMenuDiv: tabMenuDiv,
+    tabContentDiv: tabContentDiv,
+    name: "GENERAL",
+    id: self.getProject().getProjectId() + "_general_tab",
+    content: self.createGeneralTabContent(),
+  });
 
 };
 
 EditProjectDialog.prototype.addTab = function (params) {
-    var navLi = guiUtils.createTabMenuObject({
-        id: params.id,
-        name: params.name,
-        navigationBar: params.tabMenuDiv
-    });
-    params.tabMenuDiv.appendChild(navLi);
-
-    var contentDiv = guiUtils.createTabContentObject({
-        id: params.id,
-        navigationObject: navLi,
-        navigationBar: params.tabMenuDiv
-    });
-
-    if (params.content !== undefined) {
-        contentDiv.appendChild(params.content);
-    }
-
-    params.tabContentDiv.appendChild(contentDiv);
+  var navLi = guiUtils.createTabMenuObject({
+    id: params.id,
+    name: params.name,
+    navigationBar: params.tabMenuDiv
+  });
+  params.tabMenuDiv.appendChild(navLi);
+
+  var contentDiv = guiUtils.createTabContentObject({
+    id: params.id,
+    navigationObject: navLi,
+    navigationBar: params.tabMenuDiv
+  });
+
+  if (params.content !== undefined) {
+    contentDiv.appendChild(params.content);
+  }
+
+  params.tabContentDiv.appendChild(contentDiv);
 };
 
 EditProjectDialog.prototype.createGeneralTabContent = function () {
-    var self = this;
-    var project = self.getProject();
-
-    var result = new Functions.createElement({
-        type: "div",
-    });
-
-    var table = new Functions.createElement({
-        type: "div",
-        style: "display:table"
-    });
-    result.appendChild(table);
-
-    var projectIdRow = new Functions.createElement({
-        type: "div",
-        style: "display:table-row"
-    });
-    table.appendChild(projectIdRow);
-    projectIdRow.appendChild(new Functions.createElement({
-        type: "div",
-        style: "display:table-cell",
-        content: "ProjectId",
-    }));
-    projectIdRow.appendChild(new Functions.createElement({
-        type: "div",
-        style: "display:table-cell",
-        content: project.getProjectId(),
-    }));
-
-    var nameRow = new Functions.createElement({
-        type: "div",
-        style: "display:table-row"
-    });
-    table.appendChild(nameRow);
-    nameRow.appendChild(new Functions.createElement({
-        type: "div",
-        style: "display:table-cell",
-        content: "Name",
-    }));
-    nameRow.appendChild(new Functions.createElement({
-        type: "div",
-        style: "display:table-cell",
-        content: "<input name='projectName' value='" + project.getName() + "'/>",
-    }));
-
-    var versionRow = new Functions.createElement({
-        type: "div",
-        style: "display:table-row"
-    });
-    table.appendChild(versionRow);
-    versionRow.appendChild(new Functions.createElement({
-        type: "div",
-        style: "display:table-cell",
-        content: "Version",
-    }));
-    versionRow.appendChild(new Functions.createElement({
-        type: "div",
-        style: "display:table-cell",
-        content: "<input name='projectVersion' value='" + project.getVersion() + "'/>",
-    }));
-
-    var diseaseRow = new Functions.createElement({
-        type: "div",
-        style: "display:table-row"
-    });
-    table.appendChild(diseaseRow);
-    diseaseRow.appendChild(new Functions.createElement({
-        type: "div",
-        style: "display:table-cell",
-        content: "Disease",
-    }));
-    var disease = "";
-    if (project.getDisease() !== undefined) {
-        disease = project.getDisease().getResource();
+  var self = this;
+  var project = self.getProject();
+
+  var result = new Functions.createElement({
+    type: "div",
+  });
+
+  var table = new Functions.createElement({
+    type: "div",
+    style: "display:table"
+  });
+  result.appendChild(table);
+
+  var projectIdRow = new Functions.createElement({
+    type: "div",
+    style: "display:table-row"
+  });
+  table.appendChild(projectIdRow);
+  projectIdRow.appendChild(new Functions.createElement({
+    type: "div",
+    style: "display:table-cell",
+    content: "ProjectId",
+  }));
+  projectIdRow.appendChild(new Functions.createElement({
+    type: "div",
+    style: "display:table-cell",
+    content: project.getProjectId(),
+  }));
+
+  var nameRow = new Functions.createElement({
+    type: "div",
+    style: "display:table-row"
+  });
+  table.appendChild(nameRow);
+  nameRow.appendChild(new Functions.createElement({
+    type: "div",
+    style: "display:table-cell",
+    content: "Name"
+  }));
+  nameRow.appendChild(new Functions.createElement({
+    type: "div",
+    style: "display:table-cell",
+    content: "<input name='projectName' value='" + project.getName() + "'/>",
+  }));
+
+  var versionRow = new Functions.createElement({
+    type: "div",
+    style: "display:table-row"
+  });
+  table.appendChild(versionRow);
+  versionRow.appendChild(new Functions.createElement({
+    type: "div",
+    style: "display:table-cell",
+    content: "Version"
+  }));
+  versionRow.appendChild(new Functions.createElement({
+    type: "div",
+    style: "display:table-cell",
+    content: "<input name='projectVersion' value='" + project.getVersion() + "'/>",
+  }));
+
+  var diseaseRow = new Functions.createElement({
+    type: "div",
+    style: "display:table-row"
+  });
+  table.appendChild(diseaseRow);
+  diseaseRow.appendChild(new Functions.createElement({
+    type: "div",
+    style: "display:table-cell",
+    content: "Disease",
+  }));
+  var disease = "";
+  if (project.getDisease() !== undefined) {
+    disease = project.getDisease().getResource();
+  }
+  diseaseRow.appendChild(new Functions.createElement({
+    type: "div",
+    style: "display:table-cell",
+    content: "<input name='projectDisease' value='" + disease + "'/>",
+  }));
+
+  var organismRow = new Functions.createElement({
+    type: "div",
+    style: "display:table-row"
+  });
+  table.appendChild(organismRow);
+  organismRow.appendChild(new Functions.createElement({
+    type: "div",
+    style: "display:table-cell",
+    content: "Organism",
+  }));
+  var organism = "";
+  if (project.getOrganism() !== undefined) {
+    organism = project.getOrganism().getResource();
+  }
+  organismRow.appendChild(new Functions.createElement({
+    type: "div",
+    style: "display:table-cell",
+    content: "<input name='projectOrganism' value='" + organism + "'/>",
+  }));
+
+  var emailRow = new Functions.createElement({
+    type: "div",
+    style: "display:table-row"
+  });
+  table.appendChild(emailRow);
+  emailRow.appendChild(new Functions.createElement({
+    type: "div",
+    style: "display:table-cell",
+    content: "Notify email"
+  }));
+  var email = "";
+  if (project.getNotifyEmail() !== undefined) {
+    email = project.getNotifyEmail();
+  }
+  emailRow.appendChild(new Functions.createElement({
+    type: "div",
+    style: "display:table-cell",
+    content: "<input name='projectNotifyEmail' value='" + email + "'/>",
+  }));
+
+  var menuRow = Functions.createElement({
+    type: "div",
+    className: "minerva-menu-row",
+    style: "display:table-row; margin:10px"
+  });
+  result.appendChild(menuRow);
+
+  var saveProjectButton = Functions.createElement({
+    type: "button",
+    name: "saveProject",
+    content: '<span class="ui-icon ui-icon-disk"></span>&nbsp;SAVE',
+    onclick: function () {
+      return self.onSaveClicked().then(function () {
+        return self.close();
+      }, GuiConnector.alert);
     }
-    diseaseRow.appendChild(new Functions.createElement({
-        type: "div",
-        style: "display:table-cell",
-        content: "<input name='projectDisease' value='" + disease + "'/>",
-    }));
-
-    var organismRow = new Functions.createElement({
-        type: "div",
-        style: "display:table-row"
-    });
-    table.appendChild(organismRow);
-    organismRow.appendChild(new Functions.createElement({
-        type: "div",
-        style: "display:table-cell",
-        content: "Organism",
-    }));
-    var organism = "";
-    if (project.getOrganism() !== undefined) {
-        organism = project.getOrganism().getResource();
-    }
-    organismRow.appendChild(new Functions.createElement({
-        type: "div",
-        style: "display:table-cell",
-        content: "<input name='projectOrganism' value='" + organism + "'/>",
-    }));
-
-    var emailRow = new Functions.createElement({
-        type: "div",
-        style: "display:table-row"
-    });
-    table.appendChild(emailRow);
-    emailRow.appendChild(new Functions.createElement({
-        type: "div",
-        style: "display:table-cell",
-        content: "Notify email",
-    }));
-    var email = "";
-    if (project.getNotifyEmail() !== undefined) {
-        email = project.getNotifyEmail();
-    }
-    emailRow.appendChild(new Functions.createElement({
-        type: "div",
-        style: "display:table-cell",
-        content: "<input name='projectNotifyEmail' value='" + email + "'/>",
-    }));
-
-    var menuRow = Functions.createElement({
-        type: "div",
-        className: "minerva-menu-row",
-        style: "display:table-row; margin:10px",
-    });
-    result.appendChild(menuRow);
-
-    var saveProjectButton = Functions.createElement({
-        type: "button",
-        name: "saveProject",
-        content: '<span class="ui-icon ui-icon-disk"></span>&nbsp;SAVE',
-        onclick: function () {
-            return self.onSaveClicked().then(function () {
-                return self.close();
-            }, GuiConnector.alert);
-        },
-    });
-    var cancelButton = Functions.createElement({
-        type: "button",
-        name: "cancelProject",
-        content: '<span class="ui-icon ui-icon-cancel"></span>&nbsp;CANCEL',
-        onclick: function () {
-            return self.close();
-        },
-    });
-    menuRow.appendChild(saveProjectButton);
-    menuRow.appendChild(cancelButton);
-
-    return result;
+  });
+  var cancelButton = Functions.createElement({
+    type: "button",
+    name: "cancelProject",
+    content: '<span class="ui-icon ui-icon-cancel"></span>&nbsp;CANCEL',
+    onclick: function () {
+      return self.close();
+    },
+  });
+  menuRow.appendChild(saveProjectButton);
+  menuRow.appendChild(cancelButton);
+
+  return result;
 
 };
 
 EditProjectDialog.prototype.createOverlaysTab = function (tabMenuDiv, tabContentDiv) {
-    var self = this;
-    self.addTab({
-        tabMenuDiv: tabMenuDiv,
-        tabContentDiv: tabContentDiv,
-        name: "OVERLAYS",
-        id: self.getProject().getProjectId() + "_overlays_tab",
-        content: self.createOverlaysTabContent(),
-    });
+  var self = this;
+  self.addTab({
+    tabMenuDiv: tabMenuDiv,
+    tabContentDiv: tabContentDiv,
+    name: "OVERLAYS",
+    id: self.getProject().getProjectId() + "_overlays_tab",
+    content: self.createOverlaysTabContent(),
+  });
 };
 
 EditProjectDialog.prototype.createOverlaysTabContent = function () {
-    var self = this;
-    var result = Functions.createElement({
-        type: "div",
-    });
-    result.appendChild(self._createOverlayTable());
-    return result;
+  var self = this;
+  var result = Functions.createElement({
+    type: "div",
+  });
+  result.appendChild(self._createOverlayTable());
+  return result;
 };
 
 EditProjectDialog.prototype._createOverlayTable = function () {
-    var self = this;
-
-    var result = Functions.createElement({
-        type: "div",
-        style: "margin-top:10px;",
-    });
-
-    var overlaysTable = Functions.createElement({
-        type: "table",
-        name: "overlaysTable",
-        className: "display",
-        style: "width:100%",
-    });
-    result.appendChild(overlaysTable);
-
-    $(overlaysTable).DataTable({
-        fnRowCallback: function (nRow, aData) {
-            nRow.setAttribute('id', "overlay-" + aData[0]);
-        },
-        columns: [{
-            title: 'Id',
-        }, {
-            title: 'Name',
-        }, {
-            title: 'Description',
-        }, {
-            title: 'Public',
-        }, {
-            title: 'Owner',
-        }, {
-            title: 'Data',
-        }, {
-            title: 'Update',
-        }, {
-            title: 'Remove',
-        },],
-        dom: '<"minerva-datatable-toolbar">frtip',
-        initComplete: function () {
-            $("div.minerva-datatable-toolbar", $(result)).html('<button name="addOverlay">Add overlay</button>');
-        },
-
-    });
-
-    $(overlaysTable).on("click", "[name='removeOverlay']", function () {
-        var button = this;
-        return self.removeOverlay($(button).attr("data")).then(null, GuiConnector.alert);
-    });
-
-    $(overlaysTable).on("click", "[name='saveOverlay']", function () {
-        var button = this;
-        GuiConnector.showProcessing("Updating");
-        return self.saveOverlay($(button).attr("data")).then(function () {
-            GuiConnector.hideProcessing();
-            GuiConnector.info("Overlay updated successfully");
-        }, function (error) {
-            GuiConnector.hideProcessing();
-            GuiConnector.alert(error);
-        });
-    });
-
-    $(overlaysTable).on("click", "[name='downloadSource']", function () {
-        var button = this;
-        return ServerConnector.getOverlaySourceDownloadUrl({
-            overlayId: $(button).attr("data")
-        }).then(function (url) {
-            return self.downloadFile(url);
-        }).then(null, GuiConnector.alert);
-    });
-
-    $(result).on("click", "[name='addOverlay']", function () {
-        return self.openAddOverlayDialog();
-    });
+  var self = this;
+
+  var result = Functions.createElement({
+    type: "div",
+    style: "margin-top:10px;",
+  });
+
+  var overlaysTable = Functions.createElement({
+    type: "table",
+    name: "overlaysTable",
+    className: "display",
+    style: "width:100%",
+  });
+  result.appendChild(overlaysTable);
+
+  $(overlaysTable).DataTable({
+    fnRowCallback: function (nRow, aData) {
+      nRow.setAttribute('id', "overlay-" + aData[0]);
+    },
+    columns: [{
+      title: 'Id'
+    }, {
+      title: 'Name'
+    }, {
+      title: 'Description'
+    }, {
+      title: 'Public'
+    }, {
+      title: 'Owner'
+    }, {
+      title: 'Data'
+    }, {
+      title: 'Update'
+    }, {
+      title: 'Remove'
+    }],
+    dom: '<"minerva-datatable-toolbar">frtip',
+    initComplete: function () {
+      $("div.minerva-datatable-toolbar", $(result)).html('<button name="addOverlay">Add overlay</button>');
+    }
 
-    return result;
+  });
+
+  $(overlaysTable).on("click", "[name='removeOverlay']", function () {
+    var button = this;
+    return self.removeOverlay($(button).attr("data")).then(null, GuiConnector.alert);
+  });
+
+  $(overlaysTable).on("click", "[name='saveOverlay']", function () {
+    var button = this;
+    GuiConnector.showProcessing("Updating");
+    return self.saveOverlay($(button).attr("data")).then(function () {
+      GuiConnector.hideProcessing();
+      GuiConnector.info("Overlay updated successfully");
+    }, function (error) {
+      GuiConnector.hideProcessing();
+      GuiConnector.alert(error);
+    });
+  });
+
+  $(overlaysTable).on("click", "[name='downloadSource']", function () {
+    var button = this;
+    return ServerConnector.getOverlaySourceDownloadUrl({
+      overlayId: $(button).attr("data")
+    }).then(function (url) {
+      return self.downloadFile(url);
+    }).then(null, GuiConnector.alert);
+  });
+
+  $(result).on("click", "[name='addOverlay']", function () {
+    return self.openAddOverlayDialog();
+  });
+
+  return result;
 };
 
 EditProjectDialog.prototype.createUsersTab = function (tabMenuDiv, tabContentDiv) {
-    var self = this;
-    self.addTab({
-        tabMenuDiv: tabMenuDiv,
-        tabContentDiv: tabContentDiv,
-        name: "USERS",
-        id: self.getProject().getProjectId() + "_users_tab",
-        content: self.createUsersTabContent(),
-    });
+  var self = this;
+  self.addTab({
+    tabMenuDiv: tabMenuDiv,
+    tabContentDiv: tabContentDiv,
+    name: "USERS",
+    id: self.getProject().getProjectId() + "_users_tab",
+    content: self.createUsersTabContent(),
+  });
 };
 
 EditProjectDialog.prototype.createUsersTabContent = function () {
-    var self = this;
-
-    var result = Functions.createElement({
-        type: "div",
-        style: "margin-top:10px;",
-    });
-
-    var usersTable = Functions.createElement({
-        type: "table",
-        name: "usersTable",
-        className: "display",
-        style: "width:100%",
-    });
-    result.appendChild(usersTable);
-
-    $(usersTable).on("click", "[name='saveUser']", function () {
-        var button = this;
-        GuiConnector.showProcessing("Updating");
-        return self.saveUser($(button).attr("data")).then(function () {
-            GuiConnector.hideProcessing();
-            GuiConnector.info("User updated successfully");
-        }, function (error) {
-            GuiConnector.hideProcessing();
-            GuiConnector.alert(error);
-        });
-    });
-
-    return result;
+  var self = this;
+
+  var result = Functions.createElement({
+    type: "div",
+    style: "margin-top:10px;",
+  });
+
+  var usersTable = Functions.createElement({
+    type: "table",
+    name: "usersTable",
+    className: "display",
+    style: "width:100%",
+  });
+  result.appendChild(usersTable);
+
+  $(usersTable).on("click", "[name='saveUser']", function () {
+    var button = this;
+    GuiConnector.showProcessing("Updating");
+    return self.saveUser($(button).attr("data")).then(function () {
+      GuiConnector.hideProcessing();
+      GuiConnector.info("User updated successfully");
+    }, function (error) {
+      GuiConnector.hideProcessing();
+      GuiConnector.alert(error);
+    });
+  });
+
+  return result;
 };
 
 EditProjectDialog.prototype.createUserPrivilegeColumns = function () {
-    var self = this;
-
-    if (self._userPrivilegeColumns !== undefined) {
-        return Promise.resolve(self._userPrivilegeColumns);
-    }
-
-    return ServerConnector.getConfiguration().then(function (configuration) {
-        self._userPrivilegeColumns = [{
-            title: "Name"
-        }];
-        var privilegeTypes = configuration.getPrivilegeTypes();
-        for (var i = 0; i < privilegeTypes.length; i++) {
-            var type = privilegeTypes[i];
-            if (type.getObjectType() === "Project") {
-                self._userPrivilegeColumns.push({
-                    "title": type.getCommonName(),
-                    privilegeType: type,
-                });
-            }
-        }
+  var self = this;
+
+  if (self._userPrivilegeColumns !== undefined) {
+    return Promise.resolve(self._userPrivilegeColumns);
+  }
+
+  return ServerConnector.getConfiguration().then(function (configuration) {
+    self._userPrivilegeColumns = [{
+      title: "Name"
+    }];
+    var privilegeTypes = configuration.getPrivilegeTypes();
+    for (var i = 0; i < privilegeTypes.length; i++) {
+      var type = privilegeTypes[i];
+      if (type.getObjectType() === "Project") {
         self._userPrivilegeColumns.push({
-            "title": "Update"
+          "title": type.getCommonName(),
+          privilegeType: type
         });
-        return self._userPrivilegeColumns;
+      }
+    }
+    self._userPrivilegeColumns.push({
+      "title": "Update"
     });
+    return self._userPrivilegeColumns;
+  });
 
 };
 
 EditProjectDialog.prototype.init = function () {
-    var self = this;
-    return self.initUsersTab().then(function () {
-        return self.refreshUsers();
-    }).then(function () {
-        return self.refreshOverlays();
-    }).then(function () {
-        $(window).trigger('resize');
-    });
+  var self = this;
+  return self.initUsersTab().then(function () {
+    return self.refreshUsers();
+  }).then(function () {
+    return self.refreshOverlays();
+  }).then(function () {
+    $(window).trigger('resize');
+  });
 };
 
 EditProjectDialog.prototype.initUsersTab = function () {
-    var self = this;
+  var self = this;
 
-    var usersTable = $("[name=usersTable]", self.getElement())[0];
+  var usersTable = $("[name=usersTable]", self.getElement())[0];
 
-    return self.createUserPrivilegeColumns().then(function (columns) {
-        $(usersTable).DataTable({
-            columns: columns,
-        });
+  return self.createUserPrivilegeColumns().then(function (columns) {
+    $(usersTable).DataTable({
+      columns: columns,
     });
+  });
 };
 
 EditProjectDialog.prototype.refreshOverlays = function () {
-    var self = this;
-    return ServerConnector.getOverlays({
-        projectId: self.getProject().getProjectId()
-    }).then(function (overlays) {
-        return self.setOverlays(overlays);
-    });
+  var self = this;
+  return ServerConnector.getOverlays({
+    projectId: self.getProject().getProjectId()
+  }).then(function (overlays) {
+    return self.setOverlays(overlays);
+  });
 };
 
 EditProjectDialog.prototype.refreshUsers = function () {
-    var self = this;
-    return ServerConnector.getUsers().then(function (users) {
-        return self.setUsers(users);
-    });
+  var self = this;
+  return ServerConnector.getUsers().then(function (users) {
+    return self.setUsers(users);
+  });
 };
 
 EditProjectDialog.prototype.setOverlays = function (overlays) {
-    var self = this;
-    self._overlayById = [];
-    return ServerConnector.getUsers().then(function (users) {
-        var dataTable = $($("[name='overlaysTable']", self.getElement())[0]).DataTable();
-        var data = [];
-        for (var i = 0; i < overlays.length; i++) {
-            var overlay = overlays[i];
-            self._overlayById[overlay.getId()] = overlay;
-            var rowData = self.overlayToTableRow(overlay, users);
-            data.push(rowData);
-        }
-        dataTable.clear().rows.add(data).draw();
-    });
+  var self = this;
+  self._overlayById = [];
+  return ServerConnector.getUsers().then(function (users) {
+    var dataTable = $($("[name='overlaysTable']", self.getElement())[0]).DataTable();
+    var data = [];
+    for (var i = 0; i < overlays.length; i++) {
+      var overlay = overlays[i];
+      self._overlayById[overlay.getId()] = overlay;
+      var rowData = self.overlayToTableRow(overlay, users);
+      data.push(rowData);
+    }
+    dataTable.clear().rows.add(data).draw();
+  });
 };
 
 EditProjectDialog.prototype.setUsers = function (users) {
-    var self = this;
-    self._userByLogin = [];
-    return self.createUserPrivilegeColumns().then(function (columns) {
-        var dataTable = $($("[name='usersTable']", self.getElement())[0]).DataTable();
-        var data = [];
-        for (var i = 0; i < users.length; i++) {
-            var user = users[i];
-            self._userByLogin[user.getLogin()] = user;
-            var rowData = self.userToTableRow(user, columns);
-            data.push(rowData);
-        }
-        dataTable.clear().rows.add(data).draw();
-    });
+  var self = this;
+  self._userByLogin = [];
+  return self.createUserPrivilegeColumns().then(function (columns) {
+    var dataTable = $($("[name='usersTable']", self.getElement())[0]).DataTable();
+    var data = [];
+    for (var i = 0; i < users.length; i++) {
+      var user = users[i];
+      self._userByLogin[user.getLogin()] = user;
+      var rowData = self.userToTableRow(user, columns);
+      data.push(rowData);
+    }
+    dataTable.clear().rows.add(data).draw();
+  });
 };
 
 EditProjectDialog.prototype.userToTableRow = function (user, columns) {
-    var self = this;
-    var row = [];
-    var login = user.getLogin();
-
-    row[0] = user.getName() + " " + user.getSurname() + " (" + login + ")";
-    for (var i = 1; i < columns.length; i++) {
-        var column = columns[i];
-        if (column.privilegeType !== undefined) {
-            if (column.privilegeType.getValueType() === "boolean") {
-                var checked = '';
-                if (user.hasPrivilege(column.privilegeType, self.getProject().getId())) {
-                    checked = 'checked';
-                }
-                row[i] = "<input type='checkbox' name='privilege-" + login + "' data='" + column.privilegeType.getName() + "' "
-                    + checked + "/>";
-            } else {
-                throw new Error("Unsupported type: " + column.privilegeType.getValueType());
-            }
+  var self = this;
+  var row = [];
+  var login = user.getLogin();
+
+  row[0] = user.getName() + " " + user.getSurname() + " (" + login + ")";
+  for (var i = 1; i < columns.length; i++) {
+    var column = columns[i];
+    if (column.privilegeType !== undefined) {
+      if (column.privilegeType.getValueType() === "boolean") {
+        var checked = '';
+        if (user.hasPrivilege(column.privilegeType, self.getProject().getId())) {
+          checked = 'checked';
         }
+        row[i] = "<input type='checkbox' name='privilege-" + login + "' data='" + column.privilegeType.getName() + "' "
+          + checked + "/>";
+      } else {
+        throw new Error("Unsupported type: " + column.privilegeType.getValueType());
+      }
     }
+  }
 
-    row.push("<button name='saveUser' data='" + login + "'>SAVE</button>");
+  row.push("<button name='saveUser' data='" + login + "'>SAVE</button>");
 
-    return row;
+  return row;
 };
 
 EditProjectDialog.prototype.overlayToTableRow = function (overlay, users) {
-    var row = [];
-    var id = overlay.getId();
-    var creatorSelect;
-    if (overlay.getCreator() === "") {
-        creatorSelect = "<select name='creator-" + id + "' value=''>";
+  var row = [];
+  var id = overlay.getId();
+  var creatorSelect;
+  if (overlay.getCreator() === "") {
+    creatorSelect = "<select name='creator-" + id + "' value=''>";
+  } else {
+    creatorSelect = "<select name='creator-" + id + "'>";
+  }
+
+  creatorSelect += "<option value='' >---</option>";
+  for (var i = 0; i < users.length; i++) {
+    var selected = "";
+    var user = users[i];
+    if (overlay.getCreator() === user.getLogin()) {
+      selected = "selected";
     } else {
-        creatorSelect = "<select name='creator-" + id + "'>";
+      selected = "";
     }
 
-    creatorSelect += "<option value='' >---</option>";
-    for (var i = 0; i < users.length; i++) {
-        var selected = "";
-        var user = users[i];
-        if (overlay.getCreator() === user.getLogin()) {
-            selected = "selected";
-        } else {
-            selected = "";
-        }
-
-        creatorSelect += "<option value='" + user.getLogin() + "' " + selected + ">" + user.getLogin() + "("
-            + user.getName() + " " + user.getSurname() + ")</option>";
-    }
-    creatorSelect += "</select>";
-
-    var checked = '';
-    if (overlay.getPublicOverlay()) {
-        checked = "checked";
-    }
-    var publicOverlayCheckbox = "<input type='checkbox' name='publicOverlay-" + id + "' " + checked + "/>";
-
-    var downloadSourceButton;
-    if (overlay.getInputDataAvailable()) {
-        downloadSourceButton = "<button name='downloadSource' data='" + id + "'>"
-            + "<span class='ui-icon ui-icon-arrowthickstop-1-s'></span>" + "</button>";
-    } else {
-        downloadSourceButton = "N/A";
-    }
-
-    row[0] = id;
-    row[1] = "<input name='name-" + id + "' value='" + overlay.getName() + "'/>";
-    row[2] = "<input name='description-" + id + "' value='" + overlay.getDescription() + "'/>";
-    row[3] = publicOverlayCheckbox;
-    row[4] = creatorSelect;
-    row[5] = downloadSourceButton;
-    row[6] = "<button name='saveOverlay' data='" + id + "'>SAVE</button>";
-    row[7] = "<button name='removeOverlay' data='" + id + "'>REMOVE</button>";
-
-    return row;
+    creatorSelect += "<option value='" + user.getLogin() + "' " + selected + ">" + user.getLogin() + "("
+      + user.getName() + " " + user.getSurname() + ")</option>";
+  }
+  creatorSelect += "</select>";
+
+  var checked = '';
+  if (overlay.getPublicOverlay()) {
+    checked = "checked";
+  }
+  var publicOverlayCheckbox = "<input type='checkbox' name='publicOverlay-" + id + "' " + checked + "/>";
+
+  var downloadSourceButton;
+  if (overlay.getInputDataAvailable()) {
+    downloadSourceButton = "<button name='downloadSource' data='" + id + "'>"
+      + "<span class='ui-icon ui-icon-arrowthickstop-1-s'></span>" + "</button>";
+  } else {
+    downloadSourceButton = "N/A";
+  }
+
+  row[0] = id;
+  row[1] = "<input name='name-" + id + "' value='" + overlay.getName() + "'/>";
+  row[2] = "<input name='description-" + id + "' value='" + overlay.getDescription() + "'/>";
+  row[3] = publicOverlayCheckbox;
+  row[4] = creatorSelect;
+  row[5] = downloadSourceButton;
+  row[6] = "<button name='saveOverlay' data='" + id + "'>SAVE</button>";
+  row[7] = "<button name='removeOverlay' data='" + id + "'>REMOVE</button>";
+
+  return row;
 };
 
 EditProjectDialog.prototype.destroy = function () {
-    var self = this;
-    var div = self.getElement();
-    var usersTable = $("[name=usersTable]", self.getElement())[0];
-    var overlaysTable = $("[name=overlaysTable]", self.getElement())[0];
-    if ($.fn.DataTable.isDataTable(usersTable)) {
-        $(usersTable).DataTable().destroy();
-    }
-    if ($.fn.DataTable.isDataTable(overlaysTable)) {
-        $(overlaysTable).DataTable().destroy();
-    }
-
-    if ($(div).hasClass("ui-dialog-content")) {
-        $(div).dialog("destroy");
-    }
-    if (self._addOverlayDialog !== undefined) {
-        self._addOverlayDialog.destroy();
-        delete self._addOverlayDialog;
-    }
+  var self = this;
+  var div = self.getElement();
+  var usersTable = $("[name=usersTable]", self.getElement())[0];
+  var overlaysTable = $("[name=overlaysTable]", self.getElement())[0];
+  if ($.fn.DataTable.isDataTable(usersTable)) {
+    $(usersTable).DataTable().destroy();
+  }
+  if ($.fn.DataTable.isDataTable(overlaysTable)) {
+    $(overlaysTable).DataTable().destroy();
+  }
+
+  if ($(div).hasClass("ui-dialog-content")) {
+    $(div).dialog("destroy");
+  }
+  if (self._addOverlayDialog !== undefined) {
+    self._addOverlayDialog.destroy();
+    delete self._addOverlayDialog;
+  }
 };
 
 EditProjectDialog.prototype.open = function () {
-    var self = this;
-    var div = self.getElement();
-    if (!$(div).hasClass("ui-dialog-content")) {
-        $(div).dialog({
-            title: self.getProject().getProjectId(),
-            width: window.innerWidth / 2,
-            height: window.innerHeight / 2,
-        });
-    }
-    $(div).dialog("open");
+  var self = this;
+  var div = self.getElement();
+  if (!$(div).hasClass("ui-dialog-content")) {
+    $(div).dialog({
+      title: self.getProject().getProjectId(),
+      width: window.innerWidth / 2,
+      height: window.innerHeight / 2,
+    });
+  }
+  $(div).dialog("open");
 };
 
 var prepareMiriamData = function (type, resource) {
-    if (resource === "" || resource === undefined || resource === null) {
-        return null;
-    } else {
-        return new Annotation({
-            type: type,
-            resource: resource
-        });
-    }
+  if (resource === "" || resource === undefined || resource === null) {
+    return null;
+  } else {
+    return new Annotation({
+      type: type,
+      resource: resource
+    });
+  }
 };
 
 EditProjectDialog.prototype.onSaveClicked = function () {
-    var self = this;
-    var project = self.getProject();
-    var element = self.getElement();
-    project.setName($("[name='projectName']", element)[0].value);
-    project.setVersion($("[name='projectVersion']", element)[0].value);
-    project.setNotifyEmail($("[name='projectNotifyEmail']", element)[0].value);
-    var organism = prepareMiriamData("TAXONOMY", $("[name='projectOrganism']", element)[0].value);
-    project.setOrganism(organism);
-    var disease = prepareMiriamData("MESH_2012", $("[name='projectDisease']", element)[0].value);
-    project.setDisease(disease);
-    return ServerConnector.updateProject(project);
+  var self = this;
+  var project = self.getProject();
+  var element = self.getElement();
+  project.setName($("[name='projectName']", element)[0].value);
+  project.setVersion($("[name='projectVersion']", element)[0].value);
+  project.setNotifyEmail($("[name='projectNotifyEmail']", element)[0].value);
+  var organism = prepareMiriamData("TAXONOMY", $("[name='projectOrganism']", element)[0].value);
+  project.setOrganism(organism);
+  var disease = prepareMiriamData("MESH_2012", $("[name='projectDisease']", element)[0].value);
+  project.setDisease(disease);
+  return ServerConnector.updateProject(project);
 };
 EditProjectDialog.prototype.close = function () {
-    var self = this;
-    $(self.getElement()).dialog("close");
+  var self = this;
+  $(self.getElement()).dialog("close");
 };
 
 EditProjectDialog.prototype.saveOverlay = function (overlayId) {
-    var self = this;
-    var overlay = self._overlayById[overlayId];
-    overlay.setName($("[name='name-" + overlayId + "']", self.getElement())[0].value);
-    overlay.setDescription($("[name='description-" + overlayId + "']", self.getElement())[0].value);
-    overlay.setPublicOverlay($("[name='publicOverlay-" + overlayId + "']", self.getElement())[0].checked);
-    overlay.setCreator($("[name='creator-" + overlayId + "']", self.getElement())[0].value);
-
-    return ServerConnector.updateOverlay(overlay);
+  var self = this;
+  var overlay = self._overlayById[overlayId];
+  overlay.setName($("[name='name-" + overlayId + "']", self.getElement())[0].value);
+  overlay.setDescription($("[name='description-" + overlayId + "']", self.getElement())[0].value);
+  overlay.setPublicOverlay($("[name='publicOverlay-" + overlayId + "']", self.getElement())[0].checked);
+  overlay.setCreator($("[name='creator-" + overlayId + "']", self.getElement())[0].value);
+
+  return ServerConnector.updateOverlay(overlay);
 };
 
 EditProjectDialog.prototype.saveUser = function (login) {
-    var self = this;
-    var checkboxes = $("[name='privilege-" + login + "']", self.getElement());
-    var privileges = {};
-    for (var i = 0; i < checkboxes.length; i++) {
-        var checkbox = checkboxes[i];
-        var privilege = {};
-        privilege[self.getProject().getId()] = checkbox.checked;
-        privileges[$(checkbox).attr("data")] = privilege;
-    }
-
-    return ServerConnector.updateUserPrivileges({
-        user: self._userByLogin[login],
-        privileges: privileges
-    });
+  var self = this;
+  var checkboxes = $("[name='privilege-" + login + "']", self.getElement());
+  var privileges = {};
+  for (var i = 0; i < checkboxes.length; i++) {
+    var checkbox = checkboxes[i];
+    var privilege = {};
+    privilege[self.getProject().getId()] = checkbox.checked;
+    privileges[$(checkbox).attr("data")] = privilege;
+  }
+
+  return ServerConnector.updateUserPrivileges({
+    user: self._userByLogin[login],
+    privileges: privileges
+  });
 };
 
 EditProjectDialog.prototype.removeOverlay = function (overlayId) {
-    var self = this;
-    return ServerConnector.removeOverlay({
-        overlayId: overlayId
-    }).then(function () {
-        return self.refreshOverlays();
-    });
+  var self = this;
+  return ServerConnector.removeOverlay({
+    overlayId: overlayId
+  }).then(function () {
+    return self.refreshOverlays();
+  });
 };
 
 EditProjectDialog.prototype.openAddOverlayDialog = function () {
-    var self = this;
-    if (self._addOverlayDialog !== undefined) {
-        self._addOverlayDialog.destroy();
-    }
-    self._addOverlayDialog = new AddOverlayDialog({
-        project: self.getProject(),
-        customMap: null,
-        element: document.createElement("div"),
-    });
-    self._addOverlayDialog.addListener("onAddOverlay", function () {
-        return self.refreshOverlays();
-    });
-    return self._addOverlayDialog.init().then(function () {
-        return self._addOverlayDialog.open();
-    });
+  var self = this;
+  if (self._addOverlayDialog !== undefined) {
+    self._addOverlayDialog.destroy();
+  }
+  self._addOverlayDialog = new AddOverlayDialog({
+    project: self.getProject(),
+    customMap: null,
+    element: document.createElement("div"),
+  });
+  self._addOverlayDialog.addListener("onAddOverlay", function () {
+    return self.refreshOverlays();
+  });
+  return self._addOverlayDialog.init().then(function () {
+    return self._addOverlayDialog.open();
+  });
 };
 
 module.exports = EditProjectDialog;
diff --git a/frontend-js/src/main/js/gui/admin/EditUserDialog.js b/frontend-js/src/main/js/gui/admin/EditUserDialog.js
index f14ee87ede6c792b2b4c7be1e919ffd05cdb306f..21c1c09333a8759865122f92e921b05b27020dba 100644
--- a/frontend-js/src/main/js/gui/admin/EditUserDialog.js
+++ b/frontend-js/src/main/js/gui/admin/EditUserDialog.js
@@ -5,8 +5,10 @@ var Promise = require("bluebird");
 
 var AbstractGuiElement = require('../AbstractGuiElement');
 var GuiConnector = require('../../GuiConnector');
+var ValidationError = require('../../ValidationError');
 
 var Functions = require('../../Functions');
+// noinspection JSUnusedLocalSymbols
 var logger = require('../../logger');
 
 var guiUtils = new (require('../leftPanel/GuiUtils'))();
@@ -113,10 +115,98 @@ EditUserDialog.prototype.createGeneralTabContent = function () {
     style: "display:table-cell",
     content: "Login"
   }));
-  loginRow.appendChild(new Functions.createElement({
+  if (user.getLogin() === undefined) {
+    loginRow.appendChild(new Functions.createElement({
+      type: "div",
+      style: "display:table-cell",
+      content: "<input name='userLogin' value=''/>"
+    }));
+  } else {
+    loginRow.appendChild(new Functions.createElement({
+      type: "div",
+      style: "display:table-cell",
+      content: "<input name='userLogin' value='" + user.getLogin() + "' readonly/>"
+    }));
+  }
+
+  var passwordRow = new Functions.createElement({
+    type: "div",
+    style: "display:table-row"
+  });
+  table.appendChild(passwordRow);
+  passwordRow.appendChild(new Functions.createElement({
+    type: "div",
+    style: "display:table-cell",
+    content: "Password"
+  }));
+  passwordRow.appendChild(new Functions.createElement({
+    type: "div",
+    style: "display:table-cell",
+    content: "<input type=\"password\" name='userPassword' value=''/>"
+  }));
+
+  var passwordRow2 = new Functions.createElement({
+    type: "div",
+    style: "display:table-row"
+  });
+  table.appendChild(passwordRow2);
+  passwordRow2.appendChild(new Functions.createElement({
+    type: "div",
+    style: "display:table-cell",
+    content: "Confirm password"
+  }));
+  passwordRow2.appendChild(new Functions.createElement({
     type: "div",
     style: "display:table-cell",
-    content: user.getLogin()
+    content: "<input type=\"password\" name='userPassword2' value=''/>"
+  }));
+
+  var nameRow = new Functions.createElement({
+    type: "div",
+    style: "display:table-row"
+  });
+  table.appendChild(nameRow);
+  nameRow.appendChild(new Functions.createElement({
+    type: "div",
+    style: "display:table-cell",
+    content: "Name"
+  }));
+  nameRow.appendChild(new Functions.createElement({
+    type: "div",
+    style: "display:table-cell",
+    content: "<input name='userName' value='" + user.getName() + "'/>"
+  }));
+
+  var surnameRow = new Functions.createElement({
+    type: "div",
+    style: "display:table-row"
+  });
+  table.appendChild(surnameRow);
+  surnameRow.appendChild(new Functions.createElement({
+    type: "div",
+    style: "display:table-cell",
+    content: "Surname"
+  }));
+  surnameRow.appendChild(new Functions.createElement({
+    type: "div",
+    style: "display:table-cell",
+    content: "<input name='userSurname' value='" + user.getSurname() + "'/>"
+  }));
+
+  var emailRow = new Functions.createElement({
+    type: "div",
+    style: "display:table-row"
+  });
+  table.appendChild(emailRow);
+  emailRow.appendChild(new Functions.createElement({
+    type: "div",
+    style: "display:table-cell",
+    content: "Email"
+  }));
+  emailRow.appendChild(new Functions.createElement({
+    type: "div",
+    style: "display:table-cell",
+    content: "<input name='userEmail' value='" + user.getEmail() + "'/>"
   }));
 
 
@@ -274,10 +364,74 @@ EditUserDialog.prototype.open = function () {
 EditUserDialog.prototype.onSaveClicked = function () {
   var self = this;
   var user = self.getUser();
+  return self.checkValidity().then(function () {
+    user.setLogin(self.getLogin());
+    user.setPassword(self.getPassword());
+    user.setEmail(self.getEmail());
+    user.setName(self.getName());
+    user.setSurname(self.getSurname());
+    return ServerConnector.updateUser(user);
+  });
+};
 
-  return ServerConnector.updateUser(user);
+EditUserDialog.prototype.checkValidity = function () {
+  var self = this;
+  var isValid = true;
+  var error = "<b>Some data is missing.</b><ul>";
+  if (self.getPassword() !== self.getPassword2()) {
+    error += "<li>Password doesn't match</li>";
+    isValid = false;
+  }
+  if (self.getLogin() === "" || self.getLogin() === undefined || self.getLogin() === null) {
+    error += "<li>Login must not be empty</li>";
+    isValid = false;
+  }
+  var promise = Promise.resolve();
+  if (self.getUser().getLogin() !== self.getLogin()) {
+    promise = ServerConnector.getUser(self.getLogin()).then(function (remoteUser) {
+      if (remoteUser !== null) {
+        error += "<li>Login already used</li>";
+        isValid = false;
+      }
+    });
+  }
+  return promise.then(function () {
+    if (isValid) {
+      return Promise.resolve(true);
+    } else {
+      return Promise.reject(new ValidationError(error));
+    }
+  });
+};
+
+EditUserDialog.prototype.getPassword = function () {
+  var self = this;
+  return $("[name='userPassword']", self.getElement()).val();
+};
+EditUserDialog.prototype.getPassword2 = function () {
+  var self = this;
+  return $("[name='userPassword2']", self.getElement()).val();
+};
+
+EditUserDialog.prototype.getLogin = function () {
+  var self = this;
+  return $("[name='userLogin']", self.getElement()).val();
 };
 
+EditUserDialog.prototype.getEmail = function () {
+  var self = this;
+  return $("[name='userEmail']", self.getElement()).val();
+};
+EditUserDialog.prototype.getName = function () {
+  var self = this;
+  return $("[name='userName']", self.getElement()).val();
+};
+EditUserDialog.prototype.getSurname = function () {
+  var self = this;
+  return $("[name='userSurname']", self.getElement()).val();
+};
+
+
 EditUserDialog.prototype.close = function () {
   var self = this;
   $(self.getElement()).dialog("close");
diff --git a/frontend-js/src/main/js/gui/admin/MapsAdminPanel.js b/frontend-js/src/main/js/gui/admin/MapsAdminPanel.js
index 0508cd356ec81a5349624cb77e1b168e467553ed..725ef0f698ce69fcb64c28d396c6bc1ee438d6c1 100644
--- a/frontend-js/src/main/js/gui/admin/MapsAdminPanel.js
+++ b/frontend-js/src/main/js/gui/admin/MapsAdminPanel.js
@@ -66,7 +66,7 @@ MapsAdminPanel.prototype._createMenuRow = function () {
     content: '<span class="ui-icon ui-icon-refresh"></span>&nbsp;REFRESH',
     onclick: function () {
       return self.onRefreshClicked().then(null, GuiConnector.alert);
-    },
+    }
   });
   menuRow.appendChild(addProjectButton);
   menuRow.appendChild(refreshButton);
@@ -77,36 +77,37 @@ MapsAdminPanel.prototype._createProjectTableRow = function () {
   var self = this;
   var projectsRow = Functions.createElement({
     type: "div",
-    style: "display:table-row; width:100%",
+    style: "display:table-row; width:100%"
   });
 
   var projectsTable = Functions.createElement({
     type: "table",
     name: "projectsTable",
     className: "display",
-    style: "width:100%",
+    style: "width:100%"
   });
   projectsRow.appendChild(projectsTable);
 
+  // noinspection JSUnusedGlobalSymbols
   $(projectsTable).DataTable({
     fnRowCallback: function (nRow, aData) {
       nRow.setAttribute('id', aData[0]);
     },
     columns: [{
-      title: 'ProjectId',
+      title: 'ProjectId'
     }, {
-      title: 'Name',
+      title: 'Name'
     }, {
-      title: 'Disease',
+      title: 'Disease'
     }, {
-      title: 'Organism',
+      title: 'Organism'
     }, {
-      title: 'Status',
+      title: 'Status'
     }, {
-      title: 'Edit',
+      title: 'Edit'
     }, {
-      title: 'Remove',
-    },],
+      title: 'Remove'
+    }]
   });
   $(projectsTable).on("click", "[name='removeProject']", function () {
     var button = this;
diff --git a/frontend-js/src/main/js/gui/admin/UsersAdminPanel.js b/frontend-js/src/main/js/gui/admin/UsersAdminPanel.js
index c8951c68c983aa12220081b6f61b112bb8adf301..6ac46f3513d42db4f55faf5373032f099444af0a 100644
--- a/frontend-js/src/main/js/gui/admin/UsersAdminPanel.js
+++ b/frontend-js/src/main/js/gui/admin/UsersAdminPanel.js
@@ -1,9 +1,12 @@
 "use strict";
 
 var AbstractAdminPanel = require('./AbstractAdminPanel');
+var EditUserDialog = require('./EditUserDialog');
 
 var Functions = require('../../Functions');
 var GuiConnector = require('../../GuiConnector');
+// noinspection JSUnusedLocalSymbols
+var logger = require('../../logger');
 
 function UsersAdminPanel(params) {
   var self = this;
@@ -79,7 +82,11 @@ UsersAdminPanel.prototype._createUsersTableRow = function () {
   });
   projectsRow.appendChild(usersTable);
 
+  // noinspection JSUnusedGlobalSymbols
   $(usersTable).DataTable({
+    fnRowCallback: function (nRow, aData) {
+      nRow.setAttribute('id', aData[0]);
+    },
     columns: [{
       title: 'Login'
     }, {
@@ -107,6 +114,44 @@ UsersAdminPanel.prototype._createUsersTableRow = function () {
   return projectsRow;
 };
 
+UsersAdminPanel.prototype.showEditDialog = function (login) {
+  var self = this;
+  GuiConnector.showProcessing();
+  return ServerConnector.getUser(login).then(function (user) {
+    return self.getDialog(user);
+  }).then(function (dialog) {
+    dialog.open();
+    GuiConnector.hideProcessing();
+  }).then(null, function (error) {
+    GuiConnector.hideProcessing();
+    return Promise.reject(error);
+  });
+};
+
+UsersAdminPanel.prototype.getDialog = function (user) {
+  var self = this;
+  if (self._dialogs === undefined) {
+    self._dialogs = [];
+  }
+  var dialog = self._dialogs[user.getLogin()];
+  if (dialog === undefined) {
+    dialog = new EditUserDialog({
+      element: Functions.createElement({
+        type: "div"
+      }),
+      user: user,
+      project: self.getProject(),
+      customMap: null
+    });
+    self._dialogs[user.getLogin()] = dialog;
+    return dialog.init().then(function () {
+      return dialog;
+    });
+  } else {
+    return Promise.resolve(dialog);
+  }
+};
+
 UsersAdminPanel.prototype.init = function () {
   var self = this;
   return ServerConnector.getUsers().then(function (users) {
@@ -121,11 +166,36 @@ UsersAdminPanel.prototype.setUsers = function (users) {
   for (var i = 0; i < users.length; i++) {
     var user = users[i];
     var rowData = self.userToTableRow(user);
+    self.addUpdateListener(user, rowData);
     data.push(rowData);
   }
   dataTable.clear().rows.add(data).draw();
 };
 
+UsersAdminPanel.prototype.addUpdateListener = function (user, dataTableRow) {
+  var self = this;
+
+  var listenerName = "USER_LIST_LISTENER";
+  var listeners = user.getListeners("onreload");
+  for (var i = 0; i < listeners.length; i++) {
+    if (listeners[i].listenerName === listenerName) {
+      user.removeListener("onreload", listeners[i]);
+    }
+  }
+  var listener = function () {
+    var login = user.getLogin().replace(".", "\\.");
+    self.userToTableRow(user, dataTableRow);
+    var row = $($("[name='usersTable']", self.getElement())[0]).DataTable().row("#" + login);
+    if (row.length > 0) {
+      row.data(dataTableRow).draw();
+    }
+
+  };
+  listener.listenerName = listenerName;
+  user.addListener("onreload", listener);
+};
+
+
 UsersAdminPanel.prototype.userToTableRow = function (user, row) {
   if (row === undefined) {
     row = [];
@@ -155,6 +225,13 @@ UsersAdminPanel.prototype.destroy = function () {
   if ($.fn.DataTable.isDataTable(table)) {
     $(table).DataTable().destroy();
   }
+
+  for (var key in self._dialogs) {
+    if (self._dialogs.hasOwnProperty(key)) {
+      self._dialogs[key].destroy();
+    }
+  }
+
 };
 
 module.exports = UsersAdminPanel;
diff --git a/frontend-js/src/main/js/map/data/User.js b/frontend-js/src/main/js/map/data/User.js
index 410c37d506df89a17e14a410eb2183ca9cb16c17..09fc261d6ea549cd371f97dd65ab77202489c966 100644
--- a/frontend-js/src/main/js/map/data/User.js
+++ b/frontend-js/src/main/js/map/data/User.js
@@ -5,8 +5,14 @@
 var logger = require('../../logger');
 
 var UserPreferences = require('./UserPreferences');
+var ObjectWithListeners = require('../../ObjectWithListeners');
 
 function User(javaObject) {
+  // call super constructor
+  ObjectWithListeners.call(this);
+
+  this.registerListenerType("onreload");
+
   this.setLogin(javaObject.login);
   this.setName(javaObject.name);
   this.setSurname(javaObject.surname);
@@ -19,6 +25,11 @@ function User(javaObject) {
   this.setSimpleColor(javaObject.simpleColor);
 }
 
+// this class inherits from ObjectWithListeners class where generic methods for
+// listeners are set
+User.prototype = Object.create(ObjectWithListeners.prototype);
+User.prototype.constructor = User;
+
 User.prototype.setLogin = function (login) {
   this._login = login;
 };
@@ -83,6 +94,14 @@ User.prototype.getMaxColor = function () {
   return this._maxColor;
 };
 
+User.prototype.setPassword = function (password) {
+  this._password = password;
+};
+
+User.prototype.getPassword = function () {
+  return this._password;
+};
+
 User.prototype.setPrivileges = function (privileges) {
   this._privileges = privileges;
 };
@@ -114,17 +133,44 @@ User.prototype.hasPrivilege = function (type, objectId) {
   return false;
 };
 
+User.prototype.privilegesToExport = function (configuration) {
+  var self = this;
+  var result = {};
+  var validTypes = {};
+  var i;
+  for (i = 0; i < configuration.getPrivilegeTypes().length; i++) {
+    validTypes[configuration.getPrivilegeTypes()[i].getName()] = true;
+  }
+  for (i = 0; i < self.getPrivileges().length; i++) {
+    var privilege = self.getPrivileges()[i];
+    if (validTypes[privilege.type]) {
+      if (result[privilege.type] === undefined) {
+        result[privilege.type] = {};
+      }
+      if (privilege.objectId !== undefined) {
+        result[privilege.type][privilege.objectId] = privilege.value;
+      } else {
+        result[privilege.type] = privilege.value;
+      }
+    }
+  }
+  return result;
+};
+
 User.prototype.update = function (user) {
-  this.setLogin(user.getLogin());
-  this.setName(user.getName());
-  this.setSurname(user.getSurname());
-  this.setEmail(user.getEmail());
-  this.setRemoved(user.getRemoved());
-  this.setPrivileges(user.getPrivileges());
-  this.setPreferences(user.getPreferences());
-  this.setMinColor(user.getMinColor());
-  this.setMaxColor(user.getMaxColor());
-  this.setSimpleColor(user.getSimpleColor());
+  var self = this;
+  self.setLogin(user.getLogin());
+  self.setName(user.getName());
+  self.setSurname(user.getSurname());
+  self.setEmail(user.getEmail());
+  self.setRemoved(user.getRemoved());
+  self.setPrivileges(user.getPrivileges());
+  self.setPreferences(user.getPreferences());
+  self.setMinColor(user.getMinColor());
+  self.setMaxColor(user.getMaxColor());
+  self.setSimpleColor(user.getSimpleColor());
+
+  return self.callListeners("onreload");
 };
 
 module.exports = User;
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 f249501a5387f657d534ce6c5591b4ccf1a52f96..afbb5f8dd65d187909bf4cff10388ce663ac2d4f 100644
--- a/frontend-js/src/test/js/gui/admin/EditUserDialog-test.js
+++ b/frontend-js/src/test/js/gui/admin/EditUserDialog-test.js
@@ -6,8 +6,13 @@ require("../../mocha-config");
 
 var EditUserDialog = require('../../../../main/js/gui/admin/EditUserDialog');
 var User = require('../../../../main/js/map/data/User');
+var ValidationError = require('../../../../main/js/ValidationError');
+
+
+// noinspection JSUnusedLocalSymbols
 var logger = require('../../logger');
 
+// noinspection JSUnusedLocalSymbols
 var assert = require('assert');
 
 describe('EditUserDialog', function () {
@@ -32,4 +37,80 @@ describe('EditUserDialog', function () {
     });
   });
 
+  describe('checkValidity', function () {
+    it('empty user', function () {
+      var dialog;
+      var project;
+      var user = new User({});
+      return ServerConnector.getProject().then(function (result) {
+        project = result;
+        dialog = new EditUserDialog({
+          element: testDiv,
+          project: project,
+          user: user,
+          customMap: null
+        });
+        return dialog.init();
+      }).then(function () {
+        return dialog.checkValidity().then(function () {
+          assert.ok(null);
+        }, function (error) {
+          assert.ok(error instanceof ValidationError);
+        });
+      }).then(function () {
+        dialog.destroy();
+      });
+    });
+
+    it('existing user', function () {
+      var dialog;
+      var project;
+      var user;
+      return ServerConnector.getUser("anonymous").then(function (result) {
+        user = result;
+        return ServerConnector.getProject();
+      }).then(function (result) {
+        project = result;
+        dialog = new EditUserDialog({
+          element: testDiv,
+          project: project,
+          user: user,
+          customMap: null
+        });
+        return dialog.init();
+      }).then(function () {
+        return dialog.checkValidity();
+      }).then(function (result) {
+        assert.ok(result);
+      }).then(function () {
+        dialog.destroy();
+      });
+    });
+  });
+
+  describe('onSaveClicked', function () {
+    it('existing user', function () {
+      var dialog;
+      var project;
+      var user;
+      return ServerConnector.getUser("anonymous").then(function (result) {
+        user = result;
+        return ServerConnector.getProject();
+      }).then(function (result) {
+        project = result;
+        dialog = new EditUserDialog({
+          element: testDiv,
+          project: project,
+          user: user,
+          customMap: null
+        });
+        return dialog.init();
+      }).then(function () {
+        return dialog.onSaveClicked();
+      }).then(function () {
+        dialog.destroy();
+      });
+    });
+
+  });
 });
diff --git a/frontend-js/src/test/js/gui/admin/UserAdminPanel-test.js b/frontend-js/src/test/js/gui/admin/UserAdminPanel-test.js
index 6180140bef0ba0dc2cb9d1a798cd73a754079435..76764bcf97c1f5f4fa71fb9af829f71e5ab9e077 100644
--- a/frontend-js/src/test/js/gui/admin/UserAdminPanel-test.js
+++ b/frontend-js/src/test/js/gui/admin/UserAdminPanel-test.js
@@ -6,8 +6,10 @@
 require("../../mocha-config");
 
 var UsersAdminPanel = require('../../../../main/js/gui/admin/UsersAdminPanel');
+// noinspection JSUnusedLocalSymbols
 var logger = require('../../logger');
 
+// noinspection JSUnusedLocalSymbols
 var assert = require('assert');
 
 describe('UsersAdminPanel', function () {
@@ -50,4 +52,24 @@ describe('UsersAdminPanel', function () {
     });
   });
 
+  it('showEditDialog', function () {
+    var mapTab;
+    var project;
+    return ServerConnector.getProject().then(function (result) {
+      project = result;
+      return ServerConnector.getConfiguration();
+    }).then(function (configuration) {
+      mapTab = new UsersAdminPanel({
+        element: testDiv,
+        project: project,
+        configuration: configuration
+      });
+      return mapTab.init();
+    }).then(function () {
+      return mapTab.showEditDialog("anonymous");
+    }).then(function () {
+      return mapTab.destroy();
+    });
+  });
+
 });
diff --git a/frontend-js/testFiles/apiCalls/users/anonymous/PATCH_token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/users/anonymous/PATCH_token=MOCK_TOKEN_ID&
new file mode 100644
index 0000000000000000000000000000000000000000..ee0146adc4cef43f5f11fa07173a5f30de8fc712
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/users/anonymous/PATCH_token=MOCK_TOKEN_ID&
@@ -0,0 +1 @@
+{"simpleColor":null,"privileges":[{"type":"LAYOUT_MANAGEMENT","value":0,"objectId":18039},{"type":"USER_MANAGEMENT","value":0},{"type":"VIEW_PROJECT","value":1,"objectId":10},{"type":"LAYOUT_MANAGEMENT","value":0,"objectId":19186},{"type":"VIEW_PROJECT","value":1,"objectId":21},{"type":"EDIT_COMMENTS_PROJECT","value":0,"objectId":19187},{"type":"VIEW_PROJECT","value":1,"objectId":1},{"type":"EDIT_COMMENTS_PROJECT","value":0,"objectId":19184},{"type":"VIEW_PROJECT","value":1,"objectId":19},{"type":"CUSTOM_LAYOUTS","value":0},{"type":"VIEW_PROJECT","value":1,"objectId":18039},{"type":"VIEW_PROJECT","value":1,"objectId":19102},{"type":"MANAGE_GENOMES","value":1},{"type":"EDIT_COMMENTS_PROJECT","value":0,"objectId":17051},{"type":"VIEW_PROJECT","value":1,"objectId":18305},{"type":"VIEW_PROJECT","value":1,"objectId":17},{"type":"EDIT_COMMENTS_PROJECT","value":0,"objectId":15763},{"type":"VIEW_PROJECT","value":1,"objectId":6},{"type":"VIEW_PROJECT","value":1,"objectId":15764},{"type":"LAYOUT_MANAGEMENT","value":0,"objectId":14898},{"type":"PROJECT_MANAGEMENT","value":0},{"type":"VIEW_PROJECT","value":1,"objectId":17051},{"type":"EDIT_COMMENTS_PROJECT","value":0,"objectId":19102},{"type":"LAYOUT_MANAGEMENT","value":0,"objectId":17051},{"type":"VIEW_PROJECT","value":1,"objectId":18115},{"type":"VIEW_PROJECT","value":1,"objectId":15763},{"type":"VIEW_PROJECT","value":1,"objectId":14898},{"type":"VIEW_PROJECT","value":1,"objectId":22},{"type":"VIEW_PROJECT","value":0,"objectId":19184},{"type":"VIEW_PROJECT","value":1,"objectId":20605},{"type":"LAYOUT_MANAGEMENT","value":0,"objectId":16668},{"type":"LAYOUT_MANAGEMENT","value":0,"objectId":19103},{"type":"EDIT_COMMENTS_PROJECT","value":0,"objectId":14898},{"type":"CONFIGURATION_MANAGE","value":0},{"type":"VIEW_PROJECT","value":1,"objectId":20},{"type":"LAYOUT_MANAGEMENT","value":0,"objectId":18115},{"type":"VIEW_PROJECT","value":1,"objectId":7},{"type":"VIEW_PROJECT","value":1,"objectId":18},{"type":"LAYOUT_MANAGEMENT","value":0,"objectId":15764},{"type":"EDIT_COMMENTS_PROJECT","value":0,"objectId":18115},{"type":"EDIT_COMMENTS_PROJECT","value":0,"objectId":16668},{"type":"VIEW_PROJECT","value":1,"objectId":19186},{"type":"EDIT_COMMENTS_PROJECT","value":0,"objectId":15764},{"type":"VIEW_PROJECT","value":1,"objectId":20603},{"type":"EDIT_COMMENTS_PROJECT","value":0,"objectId":19103},{"type":"VIEW_PROJECT","value":1,"objectId":19187},{"type":"LAYOUT_MANAGEMENT","value":0,"objectId":19184},{"type":"VIEW_PROJECT","value":1,"objectId":11},{"type":"LAYOUT_MANAGEMENT","value":0,"objectId":19187},{"type":"LAYOUT_MANAGEMENT","value":0,"objectId":15763},{"type":"VIEW_PROJECT","value":1,"objectId":20604},{"type":"VIEW_PROJECT","value":1,"objectId":16668},{"type":"EDIT_COMMENTS_PROJECT","value":0,"objectId":18039},{"type":"LAYOUT_MANAGEMENT","value":0,"objectId":19102},{"type":"VIEW_PROJECT","value":1,"objectId":8},{"type":"ADD_MAP","value":0},{"type":"VIEW_PROJECT","value":1,"objectId":9},{"type":"VIEW_PROJECT","value":1,"objectId":19103},{"type":"EDIT_COMMENTS_PROJECT","value":0,"objectId":19186},{"type":"CUSTOM_LAYOUTS_AVAILABLE","value":0}],"preferences":{"element-required-annotations":{"lcsb.mapviewer.model.map.reaction.type.UnknownReducedTriggerReaction":{"require-at-least-one":true,"annotation-list":["PUBMED"]},"lcsb.mapviewer.model.map.compartment.BottomSquareCompartment":{"require-at-least-one":false,"annotation-list":[]},"lcsb.mapviewer.model.map.reaction.type.ReducedPhysicalStimulationReaction":{"require-at-least-one":true,"annotation-list":["PUBMED"]},"lcsb.mapviewer.model.map.species.Chemical":{"require-at-least-one":true,"annotation-list":["PUBCHEM_SUBSTANCE","PUBCHEM","CHEBI"]},"lcsb.mapviewer.model.map.species.Degraded":{"require-at-least-one":false,"annotation-list":[]},"lcsb.mapviewer.model.map.compartment.PathwayCompartment":{"require-at-least-one":false,"annotation-list":[]},"lcsb.mapviewer.model.map.species.SimpleMolecule":{"require-at-least-one":true,"annotation-list":["PUBCHEM_SUBSTANCE","PUBCHEM","CHEBI"]},"lcsb.mapviewer.model.map.reaction.type.BooleanLogicGateReaction":{"require-at-least-one":true,"annotation-list":["PUBMED"]},"lcsb.mapviewer.model.map.species.ReceptorProtein":{"require-at-least-one":true,"annotation-list":["HGNC","HGNC_SYMBOL"]},"lcsb.mapviewer.model.map.reaction.type.UnknownTransitionReaction":{"require-at-least-one":true,"annotation-list":["PUBMED"]},"lcsb.mapviewer.model.map.reaction.type.TranscriptionReaction":{"require-at-least-one":true,"annotation-list":["PUBMED"]},"lcsb.mapviewer.model.map.species.Gene":{"require-at-least-one":true,"annotation-list":["HGNC","HGNC_SYMBOL"]},"lcsb.mapviewer.model.map.compartment.OvalCompartment":{"require-at-least-one":false,"annotation-list":[]},"lcsb.mapviewer.model.map.reaction.type.PositiveInfluenceReaction":{"require-at-least-one":true,"annotation-list":["PUBMED"]},"lcsb.mapviewer.model.map.reaction.type.ReducedTriggerReaction":{"require-at-least-one":true,"annotation-list":["PUBMED"]},"lcsb.mapviewer.model.map.species.Protein":{"require-at-least-one":true,"annotation-list":["HGNC","HGNC_SYMBOL"]},"lcsb.mapviewer.model.map.reaction.type.UnknownReducedPhysicalStimulationReaction":{"require-at-least-one":true,"annotation-list":["PUBMED"]},"lcsb.mapviewer.model.map.BioEntity":{"require-at-least-one":false,"annotation-list":[]},"lcsb.mapviewer.model.map.species.GenericProtein":{"require-at-least-one":true,"annotation-list":["HGNC","HGNC_SYMBOL"]},"lcsb.mapviewer.model.map.reaction.type.TransportReaction":{"require-at-least-one":true,"annotation-list":["PUBMED"]},"lcsb.mapviewer.model.map.species.IonChannelProtein":{"require-at-least-one":true,"annotation-list":["HGNC","HGNC_SYMBOL"]},"lcsb.mapviewer.model.map.reaction.type.UnknownReducedModulationReaction":{"require-at-least-one":true,"annotation-list":["PUBMED"]},"lcsb.mapviewer.model.map.species.Phenotype":{"require-at-least-one":true,"annotation-list":[]},"lcsb.mapviewer.model.map.species.Drug":{"require-at-least-one":true,"annotation-list":[]},"lcsb.mapviewer.model.map.species.Element":{"require-at-least-one":false,"annotation-list":[]},"lcsb.mapviewer.model.map.reaction.type.DissociationReaction":{"require-at-least-one":true,"annotation-list":["PUBMED"]},"lcsb.mapviewer.model.map.compartment.SquareCompartment":{"require-at-least-one":false,"annotation-list":[]},"lcsb.mapviewer.model.map.species.Ion":{"require-at-least-one":true,"annotation-list":["PUBCHEM_SUBSTANCE","PUBCHEM","CHEBI"]},"lcsb.mapviewer.model.map.reaction.Reaction":{"require-at-least-one":true,"annotation-list":["PUBMED"]},"lcsb.mapviewer.model.map.reaction.type.HeterodimerAssociationReaction":{"require-at-least-one":true,"annotation-list":["PUBMED"]},"lcsb.mapviewer.model.map.compartment.RightSquareCompartment":{"require-at-least-one":false,"annotation-list":[]},"lcsb.mapviewer.model.map.reaction.type.TranslationReaction":{"require-at-least-one":true,"annotation-list":["PUBMED"]},"lcsb.mapviewer.model.map.reaction.type.UnknownPositiveInfluenceReaction":{"require-at-least-one":true,"annotation-list":["PUBMED"]},"lcsb.mapviewer.model.map.reaction.type.ReducedModulationReaction":{"require-at-least-one":true,"annotation-list":["PUBMED"]},"lcsb.mapviewer.model.map.species.AntisenseRna":{"require-at-least-one":true,"annotation-list":[]},"lcsb.mapviewer.model.map.species.Complex":{"require-at-least-one":true,"annotation-list":[]},"lcsb.mapviewer.model.map.species.Unknown":{"require-at-least-one":false,"annotation-list":[]},"lcsb.mapviewer.model.map.reaction.type.TruncationReaction":{"require-at-least-one":true,"annotation-list":["PUBMED"]},"lcsb.mapviewer.model.map.compartment.LeftSquareCompartment":{"require-at-least-one":false,"annotation-list":[]},"lcsb.mapviewer.model.map.reaction.type.UnknownNegativeInfluenceReaction":{"require-at-least-one":true,"annotation-list":["PUBMED"]},"lcsb.mapviewer.model.map.reaction.type.NegativeInfluenceReaction":{"require-at-least-one":true,"annotation-list":["PUBMED"]},"lcsb.mapviewer.model.map.species.TruncatedProtein":{"require-at-least-one":true,"annotation-list":["HGNC","HGNC_SYMBOL"]},"lcsb.mapviewer.model.map.compartment.Compartment":{"require-at-least-one":false,"annotation-list":[]},"lcsb.mapviewer.model.map.compartment.TopSquareCompartment":{"require-at-least-one":false,"annotation-list":[]},"lcsb.mapviewer.model.map.species.Species":{"require-at-least-one":false,"annotation-list":[]},"lcsb.mapviewer.model.map.species.Rna":{"require-at-least-one":true,"annotation-list":["HGNC","HGNC_SYMBOL"]},"lcsb.mapviewer.model.map.reaction.type.KnownTransitionOmittedReaction":{"require-at-least-one":true,"annotation-list":["PUBMED"]},"lcsb.mapviewer.model.map.reaction.type.StateTransitionReaction":{"require-at-least-one":true,"annotation-list":["PUBMED"]}},"element-valid-annotations":{"lcsb.mapviewer.model.map.reaction.type.UnknownReducedTriggerReaction":["PUBMED","COG","KEGG_REACTION","REACTOME","KEGG_PATHWAY"],"lcsb.mapviewer.model.map.compartment.BottomSquareCompartment":["PUBMED","GO","MESH_2012"],"lcsb.mapviewer.model.map.reaction.type.ReducedPhysicalStimulationReaction":["PUBMED","COG","KEGG_REACTION","REACTOME","KEGG_PATHWAY"],"lcsb.mapviewer.model.map.species.Chemical":["PUBCHEM_SUBSTANCE","PUBMED","PUBCHEM","HMDB","CHEBI","KEGG_COMPOUND"],"lcsb.mapviewer.model.map.species.Degraded":["PUBMED"],"lcsb.mapviewer.model.map.compartment.PathwayCompartment":["PUBMED","GO","MESH_2012"],"lcsb.mapviewer.model.map.species.SimpleMolecule":["PUBCHEM_SUBSTANCE","PUBMED","PUBCHEM","HMDB","CHEBI","KEGG_COMPOUND"],"lcsb.mapviewer.model.map.reaction.type.BooleanLogicGateReaction":["PUBMED","COG","KEGG_REACTION","REACTOME","KEGG_PATHWAY"],"lcsb.mapviewer.model.map.species.ReceptorProtein":["KEGG_GENES","INTERPRO","HGNC_SYMBOL","UNIPROT","CHEMBL_TARGET","ENSEMBL","PANTHER","EC","REFSEQ","PUBMED","HGNC","ENTREZ","MGD","UNIPROT_ISOFORM"],"lcsb.mapviewer.model.map.reaction.type.UnknownTransitionReaction":["PUBMED","COG","KEGG_REACTION","REACTOME","KEGG_PATHWAY"],"lcsb.mapviewer.model.map.reaction.type.TranscriptionReaction":["PUBMED","COG","KEGG_REACTION","REACTOME","KEGG_PATHWAY"],"lcsb.mapviewer.model.map.species.Gene":["KEGG_GENES","REFSEQ","PUBMED","HGNC","HGNC_SYMBOL","UNIPROT","ENSEMBL","PANTHER","ENTREZ","MGD"],"lcsb.mapviewer.model.map.compartment.OvalCompartment":["PUBMED","GO","MESH_2012"],"lcsb.mapviewer.model.map.reaction.type.PositiveInfluenceReaction":["PUBMED","COG","KEGG_REACTION","REACTOME","KEGG_PATHWAY"],"lcsb.mapviewer.model.map.reaction.type.ReducedTriggerReaction":["PUBMED","COG","KEGG_REACTION","REACTOME","KEGG_PATHWAY"],"lcsb.mapviewer.model.map.species.Protein":["KEGG_GENES","INTERPRO","HGNC_SYMBOL","UNIPROT","CHEMBL_TARGET","ENSEMBL","PANTHER","EC","REFSEQ","PUBMED","HGNC","ENTREZ","MGD","UNIPROT_ISOFORM"],"lcsb.mapviewer.model.map.reaction.type.UnknownReducedPhysicalStimulationReaction":["PUBMED","COG","KEGG_REACTION","REACTOME","KEGG_PATHWAY"],"lcsb.mapviewer.model.map.BioEntity":["PUBMED"],"lcsb.mapviewer.model.map.species.GenericProtein":["KEGG_GENES","INTERPRO","HGNC_SYMBOL","UNIPROT","CHEMBL_TARGET","ENSEMBL","PANTHER","EC","REFSEQ","PUBMED","HGNC","ENTREZ","MGD","UNIPROT_ISOFORM"],"lcsb.mapviewer.model.map.reaction.type.TransportReaction":["PUBMED","COG","KEGG_REACTION","REACTOME","KEGG_PATHWAY"],"lcsb.mapviewer.model.map.species.IonChannelProtein":["KEGG_GENES","INTERPRO","HGNC_SYMBOL","UNIPROT","CHEMBL_TARGET","ENSEMBL","PANTHER","EC","REFSEQ","PUBMED","HGNC","ENTREZ","MGD","UNIPROT_ISOFORM"],"lcsb.mapviewer.model.map.reaction.type.UnknownReducedModulationReaction":["PUBMED","COG","KEGG_REACTION","REACTOME","KEGG_PATHWAY"],"lcsb.mapviewer.model.map.species.Phenotype":["PUBMED","OMIM","GO","MESH_2012"],"lcsb.mapviewer.model.map.species.Drug":["CHEMBL_COMPOUND","DRUGBANK","PUBMED","HMDB","CHEBI"],"lcsb.mapviewer.model.map.species.Element":["PUBMED"],"lcsb.mapviewer.model.map.reaction.type.DissociationReaction":["PUBMED","COG","KEGG_REACTION","REACTOME","KEGG_PATHWAY"],"lcsb.mapviewer.model.map.compartment.SquareCompartment":["PUBMED","GO","MESH_2012"],"lcsb.mapviewer.model.map.species.Ion":["PUBCHEM_SUBSTANCE","PUBMED","PUBCHEM","HMDB","CHEBI","KEGG_COMPOUND"],"lcsb.mapviewer.model.map.reaction.Reaction":["PUBMED","COG","KEGG_REACTION","REACTOME","KEGG_PATHWAY"],"lcsb.mapviewer.model.map.reaction.type.HeterodimerAssociationReaction":["PUBMED","COG","KEGG_REACTION","REACTOME","KEGG_PATHWAY"],"lcsb.mapviewer.model.map.compartment.RightSquareCompartment":["PUBMED","GO","MESH_2012"],"lcsb.mapviewer.model.map.reaction.type.TranslationReaction":["PUBMED","COG","KEGG_REACTION","REACTOME","KEGG_PATHWAY"],"lcsb.mapviewer.model.map.reaction.type.UnknownPositiveInfluenceReaction":["PUBMED","COG","KEGG_REACTION","REACTOME","KEGG_PATHWAY"],"lcsb.mapviewer.model.map.reaction.type.ReducedModulationReaction":["PUBMED","COG","KEGG_REACTION","REACTOME","KEGG_PATHWAY"],"lcsb.mapviewer.model.map.species.AntisenseRna":["PUBMED"],"lcsb.mapviewer.model.map.species.Complex":["EC","PUBMED","INTERPRO","CHEMBL_TARGET","GO","MESH_2012"],"lcsb.mapviewer.model.map.species.Unknown":["PUBMED"],"lcsb.mapviewer.model.map.reaction.type.TruncationReaction":["PUBMED","COG","KEGG_REACTION","REACTOME","KEGG_PATHWAY"],"lcsb.mapviewer.model.map.compartment.LeftSquareCompartment":["PUBMED","GO","MESH_2012"],"lcsb.mapviewer.model.map.reaction.type.UnknownNegativeInfluenceReaction":["PUBMED","COG","KEGG_REACTION","REACTOME","KEGG_PATHWAY"],"lcsb.mapviewer.model.map.reaction.type.NegativeInfluenceReaction":["PUBMED","COG","KEGG_REACTION","REACTOME","KEGG_PATHWAY"],"lcsb.mapviewer.model.map.species.TruncatedProtein":["KEGG_GENES","INTERPRO","HGNC_SYMBOL","UNIPROT","CHEMBL_TARGET","ENSEMBL","PANTHER","EC","REFSEQ","PUBMED","HGNC","ENTREZ","MGD","UNIPROT_ISOFORM"],"lcsb.mapviewer.model.map.compartment.Compartment":["PUBMED","GO","MESH_2012"],"lcsb.mapviewer.model.map.compartment.TopSquareCompartment":["PUBMED","GO","MESH_2012"],"lcsb.mapviewer.model.map.species.Species":["PUBMED"],"lcsb.mapviewer.model.map.species.Rna":["KEGG_GENES","REFSEQ","PUBMED","HGNC","HGNC_SYMBOL","UNIPROT","ENSEMBL","PANTHER","ENTREZ","MGD"],"lcsb.mapviewer.model.map.reaction.type.KnownTransitionOmittedReaction":["PUBMED","COG","KEGG_REACTION","REACTOME","KEGG_PATHWAY"],"lcsb.mapviewer.model.map.reaction.type.StateTransitionReaction":["PUBMED","COG","KEGG_REACTION","REACTOME","KEGG_PATHWAY"]},"element-annotators":{"lcsb.mapviewer.model.map.reaction.type.UnknownReducedTriggerReaction":[],"lcsb.mapviewer.model.map.compartment.BottomSquareCompartment":["Gene Ontology"],"lcsb.mapviewer.model.map.reaction.type.ReducedPhysicalStimulationReaction":[],"lcsb.mapviewer.model.map.species.Chemical":["Chebi"],"lcsb.mapviewer.model.map.species.Degraded":[],"lcsb.mapviewer.model.map.compartment.PathwayCompartment":["Gene Ontology"],"lcsb.mapviewer.model.map.species.SimpleMolecule":["Chebi"],"lcsb.mapviewer.model.map.reaction.type.BooleanLogicGateReaction":[],"lcsb.mapviewer.model.map.species.ReceptorProtein":["Biocompendium","HGNC"],"lcsb.mapviewer.model.map.reaction.type.UnknownTransitionReaction":[],"lcsb.mapviewer.model.map.reaction.type.TranscriptionReaction":[],"lcsb.mapviewer.model.map.species.Gene":["HGNC"],"lcsb.mapviewer.model.map.compartment.OvalCompartment":["Gene Ontology"],"lcsb.mapviewer.model.map.reaction.type.PositiveInfluenceReaction":[],"lcsb.mapviewer.model.map.reaction.type.ReducedTriggerReaction":[],"lcsb.mapviewer.model.map.species.Protein":["Biocompendium","HGNC"],"lcsb.mapviewer.model.map.reaction.type.UnknownReducedPhysicalStimulationReaction":[],"lcsb.mapviewer.model.map.BioEntity":[],"lcsb.mapviewer.model.map.species.GenericProtein":["Biocompendium","HGNC"],"lcsb.mapviewer.model.map.reaction.type.TransportReaction":[],"lcsb.mapviewer.model.map.species.IonChannelProtein":["Biocompendium","HGNC"],"lcsb.mapviewer.model.map.reaction.type.UnknownReducedModulationReaction":[],"lcsb.mapviewer.model.map.species.Phenotype":["Gene Ontology"],"lcsb.mapviewer.model.map.species.Drug":[],"lcsb.mapviewer.model.map.species.Element":[],"lcsb.mapviewer.model.map.reaction.type.DissociationReaction":[],"lcsb.mapviewer.model.map.compartment.SquareCompartment":["Gene Ontology"],"lcsb.mapviewer.model.map.species.Ion":["Chebi"],"lcsb.mapviewer.model.map.reaction.Reaction":[],"lcsb.mapviewer.model.map.reaction.type.HeterodimerAssociationReaction":[],"lcsb.mapviewer.model.map.compartment.RightSquareCompartment":["Gene Ontology"],"lcsb.mapviewer.model.map.reaction.type.TranslationReaction":[],"lcsb.mapviewer.model.map.reaction.type.UnknownPositiveInfluenceReaction":[],"lcsb.mapviewer.model.map.reaction.type.ReducedModulationReaction":[],"lcsb.mapviewer.model.map.species.AntisenseRna":[],"lcsb.mapviewer.model.map.species.Complex":["Gene Ontology"],"lcsb.mapviewer.model.map.species.Unknown":[],"lcsb.mapviewer.model.map.reaction.type.TruncationReaction":[],"lcsb.mapviewer.model.map.compartment.LeftSquareCompartment":["Gene Ontology"],"lcsb.mapviewer.model.map.reaction.type.UnknownNegativeInfluenceReaction":[],"lcsb.mapviewer.model.map.reaction.type.NegativeInfluenceReaction":[],"lcsb.mapviewer.model.map.species.TruncatedProtein":["Biocompendium","HGNC"],"lcsb.mapviewer.model.map.compartment.Compartment":["Gene Ontology"],"lcsb.mapviewer.model.map.compartment.TopSquareCompartment":["Gene Ontology"],"lcsb.mapviewer.model.map.species.Species":[],"lcsb.mapviewer.model.map.species.Rna":["HGNC"],"lcsb.mapviewer.model.map.reaction.type.KnownTransitionOmittedReaction":[],"lcsb.mapviewer.model.map.reaction.type.StateTransitionReaction":[]},"project-upload":{"auto-resize":true,"sbgn":false,"cache-data":false,"semantic-zooming":false,"annotate-model":false,"validate-miriam":false}},"removed":false,"surname":"","minColor":null,"name":"","maxColor":null,"id":3,"login":"anonymous","email":""}
\ No newline at end of file
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/users/UserController.java b/rest-api/src/main/java/lcsb/mapviewer/api/users/UserController.java
index 36b1d4ee8681a1c420e78f6fe1b36da28ab4a9ed..787825759efd3dd3b7f0c8964d6e907a78418da9 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/users/UserController.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/users/UserController.java
@@ -30,6 +30,7 @@ import lcsb.mapviewer.common.Configuration;
 import lcsb.mapviewer.services.SecurityException;
 import lcsb.mapviewer.services.interfaces.IUserService;
 import lcsb.mapviewer.services.view.AuthenticationToken;
+import lcsb.mapviewer.services.view.LayoutView;
 
 @RestController
 public class UserController extends BaseController {
@@ -143,6 +144,18 @@ public class UserController extends BaseController {
     return result;
   }
 
+  @RequestMapping(value = "/users/{login:.+}", method = { RequestMethod.PATCH }, produces = { MediaType.APPLICATION_JSON_VALUE })
+  public Map<String, Object> updateUser(//
+          @RequestBody String body, //
+          @PathVariable(value = "login") String login, //
+          @CookieValue(value = Configuration.AUTH_TOKEN) String token //
+  ) throws SecurityException, QueryException, IOException {
+      Map<String, Object> node = parseBody(body);
+      Map<String, Object> data = getData(node, "user");
+      return userRest.updateUser(token, login, data);
+  }
+
+  
   /**
    * @return the userService
    * @see #userService
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/users/UserRestImpl.java b/rest-api/src/main/java/lcsb/mapviewer/api/users/UserRestImpl.java
index b3dbe1354330db2b53e19797776072ead5ffca71..5f6f44c17e084542f839f0c170bb82d2aa57c4d2 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/users/UserRestImpl.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/users/UserRestImpl.java
@@ -16,6 +16,7 @@ import lcsb.mapviewer.api.ObjectNotFoundException;
 import lcsb.mapviewer.api.QueryException;
 import lcsb.mapviewer.common.exception.InvalidArgumentException;
 import lcsb.mapviewer.model.map.MiriamType;
+import lcsb.mapviewer.model.map.layout.Layout;
 import lcsb.mapviewer.model.user.BasicPrivilege;
 import lcsb.mapviewer.model.user.ObjectPrivilege;
 import lcsb.mapviewer.model.user.PrivilegeType;
@@ -27,377 +28,424 @@ import lcsb.mapviewer.model.user.UserClassValidAnnotations;
 import lcsb.mapviewer.services.SecurityException;
 import lcsb.mapviewer.services.interfaces.ILayoutService;
 import lcsb.mapviewer.services.view.AuthenticationToken;
+import lcsb.mapviewer.services.view.LayoutView;
 
 @Transactional(value = "txManager")
 public class UserRestImpl extends BaseRestImpl {
 
-	/**
-	 * Default class logger.
-	 */
-	@SuppressWarnings("unused")
-	private Logger				 logger	= Logger.getLogger(UserRestImpl.class);
-
-	@Autowired
-	private ILayoutService layoutService;
-
-	public Map<String, Object> getUser(String token, String login, String columns) throws SecurityException, ObjectNotFoundException {
-		User ownUserData = getUserService().getUserByToken(token);
-
-		Set<String> columnSet = createUserColumnSet(columns);
-
-		boolean isAdmin = getUserService().userHasPrivilege(ownUserData, PrivilegeType.USER_MANAGEMENT);
-
-		if (ownUserData.getLogin().equals(login) || isAdmin) {
-			User user = getUserService().getUserByLogin(login);
-			if (user == null) {
-				throw new ObjectNotFoundException("User doesn't exist");
-			}
-			return prepareUse(user, columnSet, isAdmin);
-		} else {
-			throw new SecurityException("You cannot access data of the user with given id");
-		}
-	}
-
-	private Set<String> createUserColumnSet(String columns) {
-		Set<String> columnsSet = new HashSet<>();
-		if (columns.equals("")) {
-			columnsSet.add("id");
-			columnsSet.add("login");
-			columnsSet.add("name");
-			columnsSet.add("surname");
-			columnsSet.add("email");
-			columnsSet.add("minColor");
-			columnsSet.add("maxColor");
-			columnsSet.add("simpleColor");
-			columnsSet.add("removed");
-			columnsSet.add("privileges");
-			columnsSet.add("preferences");
-		} else {
-			for (String str : columns.split(",")) {
-				columnsSet.add(str);
-			}
-		}
-		return columnsSet;
-	}
-
-	private Map<String, Object> prepareUse(User user, Set<String> columnsSet, boolean admin) {
-		Map<String, Object> result = new HashMap<>();
-		for (String string : columnsSet) {
-			String column = string.toLowerCase();
-			Object value = null;
-			if (column.equals("id") || column.equals("idobject")) {
-				value = user.getId();
-			} else if (column.equals("name")) {
-				value = user.getName();
-			} else if (column.equals("surname")) {
-				value = user.getSurname();
-			} else if (column.equals("login")) {
-				value = user.getLogin();
-			} else if (column.equals("email")) {
-				value = user.getEmail();
-			} else if (column.equals("mincolor")) {
-				value = user.getMinColor();
-			} else if (column.equals("maxcolor")) {
-				value = user.getMaxColor();
-			} else if (column.equals("simplecolor")) {
-				value = user.getSimpleColor();
-			} else if (column.equals("removed")) {
-				value = user.isRemoved();
-			} else if (column.equals("privileges") && admin) {
-				value = preparePrivileges(user);
-			} else if (column.equals("preferences")) {
-				value = preparePreferences(user);
-			} else {
-				value = "Unknown column";
-			}
-			result.put(string, value);
-		}
-		return result;
-	}
-
-	private Map<String, Object> preparePreferences(User user) {
-		Map<String, Object> result = new HashMap<>();
-		UserAnnotationSchema schema = getProjectService().prepareUserAnnotationSchema(user);
-		result.put("project-upload", prepareProjectUploadPreferences(schema));
-		result.put("element-annotators", prepareElementAnnotators(schema.getClassAnnotators()));
-		result.put("element-required-annotations", prepareRequiredAnnotations(schema.getClassRequiredAnnotators()));
-		result.put("element-valid-annotations", prepareValidAnnotations(schema.getClassValidAnnotators()));
-		return result;
-	}
-
-	private Map<String, Object> prepareValidAnnotations(List<UserClassValidAnnotations> classValidAnnotators) {
-		Map<String, Object> result = new HashMap<>();
-		for (UserClassValidAnnotations userClassAnnotators : classValidAnnotators) {
-			result.put(userClassAnnotators.getClassName(), new ArrayList<>(userClassAnnotators.getValidMiriamTypes()));
-		}
-		return result;
-	}
-
-	private void updateValidAnnotations(UserAnnotationSchema schema, Map<String, Object> data) {
-		for (String key : data.keySet()) {
-			UserClassValidAnnotations annotator = null;
-			for (UserClassValidAnnotations userClassAnnotators : schema.getClassValidAnnotators()) {
-				if (userClassAnnotators.getClassName().equals(key)) {
-					annotator = userClassAnnotators;
-				}
-			}
-			if (annotator == null) {
-				annotator = new UserClassValidAnnotations();
-				annotator.setClassName(key);
-				schema.addClassValidAnnotations(annotator);
-			}
-			annotator.getValidMiriamTypes().clear();
-			for (Object row : (List<?>) data.get(key)) {
-				annotator.getValidMiriamTypes().add(MiriamType.valueOf((String) row));
-			}
-		}
-	}
-
-	private Map<String, Object> prepareRequiredAnnotations(List<UserClassRequiredAnnotations> classRequiredAnnotators) {
-		Map<String, Object> result = new HashMap<>();
-		for (UserClassRequiredAnnotations requiredAnnotations : classRequiredAnnotators) {
-			Map<String, Object> row = new HashMap<>();
-			row.put("require-at-least-one", requiredAnnotations.getRequireAtLeastOneAnnotation());
-			List<String> miriamTypes = new ArrayList<>();
-
-			for (MiriamType mt : requiredAnnotations.getRequiredMiriamTypes()) {
-				miriamTypes.add(mt.name());
-			}
-			row.put("annotation-list", miriamTypes);
-			result.put(requiredAnnotations.getClassName(), row);
-		}
-		return result;
-	}
-
-	private void updateRequiredAnnotations(UserAnnotationSchema schema, Map<String, Object> data) throws QueryException {
-		for (String key : data.keySet()) {
-			UserClassRequiredAnnotations annotator = null;
-			for (UserClassRequiredAnnotations userClassAnnotators : schema.getClassRequiredAnnotators()) {
-				if (userClassAnnotators.getClassName().equals(key)) {
-					annotator = userClassAnnotators;
-				}
-			}
-			if (annotator == null) {
-				annotator = new UserClassRequiredAnnotations();
-				annotator.setClassName(key);
-				schema.addClassRequiredAnnotations(annotator);
-			}
-			updateAnnotator(annotator, (Map<String, Object>) data.get(key));
-		}
-	}
-
-	private void updateAnnotator(UserClassRequiredAnnotations annotator, Map<String, Object> data) throws QueryException {
-		for (String key : data.keySet()) {
-			if (key.equals("require-at-least-one")) {
-				annotator.setRequireAtLeastOneAnnotation((Boolean) data.get("require-at-least-one"));
-			} else if (key.equals("annotation-list")) {
-				annotator.getRequiredMiriamTypes().clear();
-				for (Object row : (List<?>) data.get(key)) {
-					annotator.getRequiredMiriamTypes().add(MiriamType.valueOf((String) row));
-				}
-			} else {
-				throw new QueryException("Unknown field: " + key);
-			}
-		}
-
-	}
-
-	private Map<String, Object> prepareElementAnnotators(List<UserClassAnnotators> classAnnotators) {
-		Map<String, Object> result = new HashMap<>();
-		for (UserClassAnnotators userClassAnnotators : classAnnotators) {
-			result.put(userClassAnnotators.getClassName(), new ArrayList<>(userClassAnnotators.getAnnotators()));
-		}
-		return result;
-	}
-
-	private void updateElementAnnotators(UserAnnotationSchema schema, Map<String, Object> data) {
-		for (String key : data.keySet()) {
-			UserClassAnnotators annotator = null;
-			for (UserClassAnnotators userClassAnnotators : schema.getClassAnnotators()) {
-				if (userClassAnnotators.getClassName().equals(key)) {
-					annotator = userClassAnnotators;
-				}
-			}
-			if (annotator == null) {
-				annotator = new UserClassAnnotators();
-				annotator.setClassName(key);
-				schema.addClassAnnotator(annotator);
-			}
-			annotator.getAnnotators().clear();
-			annotator.getAnnotators().addAll((List<String>) data.get(key));
-		}
-	}
-
-	private Map<String, Object> prepareProjectUploadPreferences(UserAnnotationSchema schema) {
-		Map<String, Object> result = new HashMap<>();
-		result.put("validate-miriam", schema.getValidateMiriamTypes());
-		result.put("annotate-model", schema.getAnnotateModel());
-		result.put("cache-data", schema.getCacheData());
-		result.put("auto-resize", schema.getAutoResizeMap());
-		result.put("semantic-zooming", schema.getSemanticZooming());
-		result.put("sbgn", schema.getSbgnFormat());
-		return result;
-	}
-
-	private List<Map<String, Object>> preparePrivileges(User user) {
-		List<Map<String, Object>> result = new ArrayList<>();
-		for (BasicPrivilege privilege : user.getPrivileges()) {
-			if (privilege instanceof ObjectPrivilege) {
-				result.add(prepareObjectPrivilege((ObjectPrivilege) privilege));
-			} else {
-				result.add(prepareBasicPrivilege(privilege));
-			}
-		}
-		Map<String, Object> customLayouts = new HashMap<>();
-		customLayouts.put("type", "CUSTOM_LAYOUTS_AVAILABLE");
-		customLayouts.put("value", layoutService.getAvailableCustomLayoutsNumber(user));
-		result.add(customLayouts);
-		return result;
-	}
-
-	private Map<String, Object> prepareObjectPrivilege(ObjectPrivilege privilege) {
-		Map<String, Object> result = new HashMap<>();
-		result.put("type", privilege.getType());
-		result.put("value", privilege.getLevel());
-		result.put("objectId", privilege.getIdObject());
-		return result;
-	}
-
-	private Map<String, Object> prepareBasicPrivilege(BasicPrivilege privilege) {
-		Map<String, Object> result = new HashMap<>();
-		if (privilege.getClass().equals(BasicPrivilege.class)) {
-			result.put("type", privilege.getType());
-			result.put("value", privilege.getLevel());
-			return result;
-		} else {
-			throw new InvalidArgumentException("Don't know how to handle class: " + privilege.getClass());
-		}
-	}
-
-	/**
-	 * @return the layoutService
-	 * @see #layoutService
-	 */
-	public ILayoutService getLayoutService() {
-		return layoutService;
-	}
-
-	/**
-	 * @param layoutService
-	 *          the layoutService to set
-	 * @see #layoutService
-	 */
-	public void setLayoutService(ILayoutService layoutService) {
-		this.layoutService = layoutService;
-	}
-
-	public List<Map<String, Object>> getUsers(String token, String columns) throws SecurityException {
-		AuthenticationToken authenticationToken = getUserService().getToken(token);
-		User ownUserData = getUserService().getUserByToken(token);
-		boolean isAdmin = getUserService().userHasPrivilege(ownUserData, PrivilegeType.USER_MANAGEMENT);
-
-		Set<String> columnSet = createUserColumnSet(columns);
-
-		List<Map<String, Object>> result = new ArrayList<>();
-		for (User user : getUserService().getUsers(authenticationToken)) {
-			result.add(prepareUse(user, columnSet, isAdmin));
-		}
-		return result;
-	}
-
-	public Map<String, Object> updatePrivileges(String token, String login, Map<String, Object> privilegesData) throws SecurityException, QueryException {
-		if (privilegesData == null) {
-			throw new QueryException("Privileges not defined");
-		}
-		try {
-			AuthenticationToken authenticationToken = getUserService().getToken(token);
-			User modifiedUser = getUserService().getUserByLogin(login);
-
-			for (String key : privilegesData.keySet()) {
-				Object value = privilegesData.get(key);
-
-				PrivilegeType type = PrivilegeType.valueOf(key);
-
-				if (type.getPrivilegeClassType().equals(BasicPrivilege.class)) {
-					getUserService().setUserPrivilege(modifiedUser, type, value, authenticationToken);
-				} else if (type.getPrivilegeClassType().equals(ObjectPrivilege.class)) {
-					if (value instanceof Map) {
-						Map<?, ?> objects = (Map<?, ?>) value;
-						for (Object objectId : objects.keySet()) {
-							getUserService().setUserPrivilege(modifiedUser, type, objects.get(objectId), Integer.valueOf((String) objectId), authenticationToken);
-						}
-					} else {
-						throw new QueryException("Invalid value for privilege: " + key);
-					}
-				} else {
-					throw new QueryException("Unknown privilege type: " + key);
-				}
-
-			}
-			return getUser(token, login, "");
-		} catch (IllegalArgumentException e) {
-			throw new QueryException("Invalid input", e);
-		}
-	}
-
-	public Map<String, Object> updatePreferences(String token, String login, Map<String, Object> preferencesData) throws SecurityException, QueryException {
-		if (preferencesData == null) {
-			throw new QueryException("Preferences not defined");
-		}
-		try {
-			AuthenticationToken authenticationToken = getUserService().getToken(token);
-			User modifiedUser = getUserService().getUserByLogin(login);
-			if (modifiedUser == null) {
-				throw new ObjectNotFoundException("User doesn't exist");
-			}
-
-			UserAnnotationSchema schema = getProjectService().prepareUserAnnotationSchema(modifiedUser);
-
-			for (String key : preferencesData.keySet()) {
-				Map<String, Object> value = (Map<String, Object>) preferencesData.get(key);
-
-				if (key.equals("project-upload")) {
-					updateUploadPreferences(schema, value);
-				} else if (key.equals("element-annotators")) {
-					updateElementAnnotators(schema, value);
-				} else if (key.equals("element-required-annotations")) {
-					updateRequiredAnnotations(schema, value);
-				} else if (key.equals("element-valid-annotations")) {
-					updateValidAnnotations(schema, value);
-				} else {
-					throw new QueryException("Unknown preferences field: " + key);
-				}
-			}
-			modifiedUser.setAnnotationSchema(schema);
-			getUserService().updateUser(modifiedUser, authenticationToken);
-			return getUser(token, login, "");
-		} catch (IllegalArgumentException e) {
-			throw new QueryException("Invalid input", e);
-		}
-	}
-
-	private void updateUploadPreferences(UserAnnotationSchema schema, Map<String, Object> data) throws QueryException {
-		for (String key : data.keySet()) {
-			Boolean value = (Boolean) data.get(key);
-			if (value != null) {
-				if (key.equals("validate-miriam")) {
-					schema.setValidateMiriamTypes(value);
-				} else if (key.equals("annotate-model")) {
-					schema.setAnnotateModel(value);
-				} else if (key.equals("cache-data")) {
-					schema.setCacheData(value);
-				} else if (key.equals("auto-resize")) {
-					schema.setAutoResizeMap(value);
-				} else if (key.equals("semantic-zooming")) {
-					schema.setSemanticZooming(value);
-				} else if (key.equals("sbgn")) {
-					schema.setSbgnFormat(value);
-				} else {
-					throw new QueryException("Unknown upload preference field: " + key);
-				}
-			}
-		}
-
-	}
+  /**
+   * Default class logger.
+   */
+  @SuppressWarnings("unused")
+  private Logger logger = Logger.getLogger(UserRestImpl.class);
+
+  @Autowired
+  private ILayoutService layoutService;
+
+  public Map<String, Object> getUser(String token, String login, String columns)
+      throws SecurityException, ObjectNotFoundException {
+    User ownUserData = getUserService().getUserByToken(token);
+
+    Set<String> columnSet = createUserColumnSet(columns);
+
+    boolean isAdmin = getUserService().userHasPrivilege(ownUserData, PrivilegeType.USER_MANAGEMENT);
+
+    if (ownUserData.getLogin().equals(login) || isAdmin) {
+      User user = getUserService().getUserByLogin(login);
+      if (user == null) {
+        throw new ObjectNotFoundException("User doesn't exist");
+      }
+      return prepareUse(user, columnSet, isAdmin);
+    } else {
+      throw new SecurityException("You cannot access data of the user with given id");
+    }
+  }
+
+  private Set<String> createUserColumnSet(String columns) {
+    Set<String> columnsSet = new HashSet<>();
+    if (columns.equals("")) {
+      columnsSet.add("id");
+      columnsSet.add("login");
+      columnsSet.add("name");
+      columnsSet.add("surname");
+      columnsSet.add("email");
+      columnsSet.add("minColor");
+      columnsSet.add("maxColor");
+      columnsSet.add("simpleColor");
+      columnsSet.add("removed");
+      columnsSet.add("privileges");
+      columnsSet.add("preferences");
+    } else {
+      for (String str : columns.split(",")) {
+        columnsSet.add(str);
+      }
+    }
+    return columnsSet;
+  }
+
+  private Map<String, Object> prepareUse(User user, Set<String> columnsSet, boolean admin) {
+    Map<String, Object> result = new HashMap<>();
+    for (String string : columnsSet) {
+      String column = string.toLowerCase();
+      Object value = null;
+      if (column.equals("id") || column.equals("idobject")) {
+        value = user.getId();
+      } else if (column.equals("name")) {
+        value = user.getName();
+      } else if (column.equals("surname")) {
+        value = user.getSurname();
+      } else if (column.equals("login")) {
+        value = user.getLogin();
+      } else if (column.equals("email")) {
+        value = user.getEmail();
+      } else if (column.equals("mincolor")) {
+        value = user.getMinColor();
+      } else if (column.equals("maxcolor")) {
+        value = user.getMaxColor();
+      } else if (column.equals("simplecolor")) {
+        value = user.getSimpleColor();
+      } else if (column.equals("removed")) {
+        value = user.isRemoved();
+      } else if (column.equals("privileges") && admin) {
+        value = preparePrivileges(user);
+      } else if (column.equals("preferences")) {
+        value = preparePreferences(user);
+      } else {
+        value = "Unknown column";
+      }
+      result.put(string, value);
+    }
+    return result;
+  }
+
+  private Map<String, Object> preparePreferences(User user) {
+    Map<String, Object> result = new HashMap<>();
+    UserAnnotationSchema schema = getProjectService().prepareUserAnnotationSchema(user);
+    result.put("project-upload", prepareProjectUploadPreferences(schema));
+    result.put("element-annotators", prepareElementAnnotators(schema.getClassAnnotators()));
+    result.put("element-required-annotations", prepareRequiredAnnotations(schema.getClassRequiredAnnotators()));
+    result.put("element-valid-annotations", prepareValidAnnotations(schema.getClassValidAnnotators()));
+    return result;
+  }
+
+  private Map<String, Object> prepareValidAnnotations(List<UserClassValidAnnotations> classValidAnnotators) {
+    Map<String, Object> result = new HashMap<>();
+    for (UserClassValidAnnotations userClassAnnotators : classValidAnnotators) {
+      result.put(userClassAnnotators.getClassName(), new ArrayList<>(userClassAnnotators.getValidMiriamTypes()));
+    }
+    return result;
+  }
+
+  private void updateValidAnnotations(UserAnnotationSchema schema, Map<String, Object> data) {
+    for (String key : data.keySet()) {
+      UserClassValidAnnotations annotator = null;
+      for (UserClassValidAnnotations userClassAnnotators : schema.getClassValidAnnotators()) {
+        if (userClassAnnotators.getClassName().equals(key)) {
+          annotator = userClassAnnotators;
+        }
+      }
+      if (annotator == null) {
+        annotator = new UserClassValidAnnotations();
+        annotator.setClassName(key);
+        schema.addClassValidAnnotations(annotator);
+      }
+      annotator.getValidMiriamTypes().clear();
+      for (Object row : (List<?>) data.get(key)) {
+        annotator.getValidMiriamTypes().add(MiriamType.valueOf((String) row));
+      }
+    }
+  }
+
+  private Map<String, Object> prepareRequiredAnnotations(List<UserClassRequiredAnnotations> classRequiredAnnotators) {
+    Map<String, Object> result = new HashMap<>();
+    for (UserClassRequiredAnnotations requiredAnnotations : classRequiredAnnotators) {
+      Map<String, Object> row = new HashMap<>();
+      row.put("require-at-least-one", requiredAnnotations.getRequireAtLeastOneAnnotation());
+      List<String> miriamTypes = new ArrayList<>();
+
+      for (MiriamType mt : requiredAnnotations.getRequiredMiriamTypes()) {
+        miriamTypes.add(mt.name());
+      }
+      row.put("annotation-list", miriamTypes);
+      result.put(requiredAnnotations.getClassName(), row);
+    }
+    return result;
+  }
+
+  private void updateRequiredAnnotations(UserAnnotationSchema schema, Map<String, Object> data) throws QueryException {
+    for (String key : data.keySet()) {
+      UserClassRequiredAnnotations annotator = null;
+      for (UserClassRequiredAnnotations userClassAnnotators : schema.getClassRequiredAnnotators()) {
+        if (userClassAnnotators.getClassName().equals(key)) {
+          annotator = userClassAnnotators;
+        }
+      }
+      if (annotator == null) {
+        annotator = new UserClassRequiredAnnotations();
+        annotator.setClassName(key);
+        schema.addClassRequiredAnnotations(annotator);
+      }
+      updateAnnotator(annotator, (Map<String, Object>) data.get(key));
+    }
+  }
+
+  private void updateAnnotator(UserClassRequiredAnnotations annotator, Map<String, Object> data) throws QueryException {
+    for (String key : data.keySet()) {
+      if (key.equals("require-at-least-one")) {
+        annotator.setRequireAtLeastOneAnnotation((Boolean) data.get("require-at-least-one"));
+      } else if (key.equals("annotation-list")) {
+        annotator.getRequiredMiriamTypes().clear();
+        for (Object row : (List<?>) data.get(key)) {
+          annotator.getRequiredMiriamTypes().add(MiriamType.valueOf((String) row));
+        }
+      } else {
+        throw new QueryException("Unknown field: " + key);
+      }
+    }
+
+  }
+
+  private Map<String, Object> prepareElementAnnotators(List<UserClassAnnotators> classAnnotators) {
+    Map<String, Object> result = new HashMap<>();
+    for (UserClassAnnotators userClassAnnotators : classAnnotators) {
+      result.put(userClassAnnotators.getClassName(), new ArrayList<>(userClassAnnotators.getAnnotators()));
+    }
+    return result;
+  }
+
+  private void updateElementAnnotators(UserAnnotationSchema schema, Map<String, Object> data) {
+    for (String key : data.keySet()) {
+      UserClassAnnotators annotator = null;
+      for (UserClassAnnotators userClassAnnotators : schema.getClassAnnotators()) {
+        if (userClassAnnotators.getClassName().equals(key)) {
+          annotator = userClassAnnotators;
+        }
+      }
+      if (annotator == null) {
+        annotator = new UserClassAnnotators();
+        annotator.setClassName(key);
+        schema.addClassAnnotator(annotator);
+      }
+      annotator.getAnnotators().clear();
+      annotator.getAnnotators().addAll((List<String>) data.get(key));
+    }
+  }
+
+  private Map<String, Object> prepareProjectUploadPreferences(UserAnnotationSchema schema) {
+    Map<String, Object> result = new HashMap<>();
+    result.put("validate-miriam", schema.getValidateMiriamTypes());
+    result.put("annotate-model", schema.getAnnotateModel());
+    result.put("cache-data", schema.getCacheData());
+    result.put("auto-resize", schema.getAutoResizeMap());
+    result.put("semantic-zooming", schema.getSemanticZooming());
+    result.put("sbgn", schema.getSbgnFormat());
+    return result;
+  }
+
+  private List<Map<String, Object>> preparePrivileges(User user) {
+    List<Map<String, Object>> result = new ArrayList<>();
+    for (BasicPrivilege privilege : user.getPrivileges()) {
+      if (privilege instanceof ObjectPrivilege) {
+        result.add(prepareObjectPrivilege((ObjectPrivilege) privilege));
+      } else {
+        result.add(prepareBasicPrivilege(privilege));
+      }
+    }
+    Map<String, Object> customLayouts = new HashMap<>();
+    customLayouts.put("type", "CUSTOM_LAYOUTS_AVAILABLE");
+    customLayouts.put("value", layoutService.getAvailableCustomLayoutsNumber(user));
+    result.add(customLayouts);
+    return result;
+  }
+
+  private Map<String, Object> prepareObjectPrivilege(ObjectPrivilege privilege) {
+    Map<String, Object> result = new HashMap<>();
+    result.put("type", privilege.getType());
+    result.put("value", privilege.getLevel());
+    result.put("objectId", privilege.getIdObject());
+    return result;
+  }
+
+  private Map<String, Object> prepareBasicPrivilege(BasicPrivilege privilege) {
+    Map<String, Object> result = new HashMap<>();
+    if (privilege.getClass().equals(BasicPrivilege.class)) {
+      result.put("type", privilege.getType());
+      result.put("value", privilege.getLevel());
+      return result;
+    } else {
+      throw new InvalidArgumentException("Don't know how to handle class: " + privilege.getClass());
+    }
+  }
+
+  /**
+   * @return the layoutService
+   * @see #layoutService
+   */
+  public ILayoutService getLayoutService() {
+    return layoutService;
+  }
+
+  /**
+   * @param layoutService
+   *          the layoutService to set
+   * @see #layoutService
+   */
+  public void setLayoutService(ILayoutService layoutService) {
+    this.layoutService = layoutService;
+  }
+
+  public List<Map<String, Object>> getUsers(String token, String columns) throws SecurityException {
+    AuthenticationToken authenticationToken = getUserService().getToken(token);
+    User ownUserData = getUserService().getUserByToken(token);
+    boolean isAdmin = getUserService().userHasPrivilege(ownUserData, PrivilegeType.USER_MANAGEMENT);
+
+    Set<String> columnSet = createUserColumnSet(columns);
+
+    List<Map<String, Object>> result = new ArrayList<>();
+    for (User user : getUserService().getUsers(authenticationToken)) {
+      result.add(prepareUse(user, columnSet, isAdmin));
+    }
+    return result;
+  }
+
+  public Map<String, Object> updatePrivileges(String token, String login, Map<String, Object> privilegesData)
+      throws SecurityException, QueryException {
+    if (privilegesData == null) {
+      throw new QueryException("Privileges not defined");
+    }
+    try {
+      AuthenticationToken authenticationToken = getUserService().getToken(token);
+      User modifiedUser = getUserService().getUserByLogin(login);
+
+      for (String key : privilegesData.keySet()) {
+        Object value = privilegesData.get(key);
+
+        PrivilegeType type = PrivilegeType.valueOf(key);
+
+        if (type.getPrivilegeClassType().equals(BasicPrivilege.class)) {
+          getUserService().setUserPrivilege(modifiedUser, type, value, authenticationToken);
+        } else if (type.getPrivilegeClassType().equals(ObjectPrivilege.class)) {
+          if (value instanceof Map) {
+            Map<?, ?> objects = (Map<?, ?>) value;
+            for (Object objectId : objects.keySet()) {
+              getUserService().setUserPrivilege(modifiedUser, type, objects.get(objectId),
+                  Integer.valueOf((String) objectId), authenticationToken);
+            }
+          } else {
+            throw new QueryException("Invalid value for privilege: " + key);
+          }
+        } else {
+          throw new QueryException("Unknown privilege type: " + key);
+        }
+
+      }
+      return getUser(token, login, "");
+    } catch (IllegalArgumentException e) {
+      throw new QueryException("Invalid input", e);
+    }
+  }
+
+  public Map<String, Object> updatePreferences(String token, String login, Map<String, Object> preferencesData)
+      throws SecurityException, QueryException {
+    if (preferencesData == null) {
+      throw new QueryException("Preferences not defined");
+    }
+    try {
+      AuthenticationToken authenticationToken = getUserService().getToken(token);
+      User modifiedUser = getUserService().getUserByLogin(login);
+      if (modifiedUser == null) {
+        throw new ObjectNotFoundException("User doesn't exist");
+      }
+
+      UserAnnotationSchema schema = getProjectService().prepareUserAnnotationSchema(modifiedUser);
+
+      for (String key : preferencesData.keySet()) {
+        Map<String, Object> value = (Map<String, Object>) preferencesData.get(key);
+
+        if (key.equals("project-upload")) {
+          updateUploadPreferences(schema, value);
+        } else if (key.equals("element-annotators")) {
+          updateElementAnnotators(schema, value);
+        } else if (key.equals("element-required-annotations")) {
+          updateRequiredAnnotations(schema, value);
+        } else if (key.equals("element-valid-annotations")) {
+          updateValidAnnotations(schema, value);
+        } else {
+          throw new QueryException("Unknown preferences field: " + key);
+        }
+      }
+      modifiedUser.setAnnotationSchema(schema);
+      getUserService().updateUser(modifiedUser, authenticationToken);
+      return getUser(token, login, "");
+    } catch (IllegalArgumentException e) {
+      throw new QueryException("Invalid input", e);
+    }
+  }
+
+  private void updateUploadPreferences(UserAnnotationSchema schema, Map<String, Object> data) throws QueryException {
+    for (String key : data.keySet()) {
+      Boolean value = (Boolean) data.get(key);
+      if (value != null) {
+        if (key.equals("validate-miriam")) {
+          schema.setValidateMiriamTypes(value);
+        } else if (key.equals("annotate-model")) {
+          schema.setAnnotateModel(value);
+        } else if (key.equals("cache-data")) {
+          schema.setCacheData(value);
+        } else if (key.equals("auto-resize")) {
+          schema.setAutoResizeMap(value);
+        } else if (key.equals("semantic-zooming")) {
+          schema.setSemanticZooming(value);
+        } else if (key.equals("sbgn")) {
+          schema.setSbgnFormat(value);
+        } else {
+          throw new QueryException("Unknown upload preference field: " + key);
+        }
+      }
+    }
+
+  }
+
+  public Map<String, Object> updateUser(String token, String login, Map<String, Object> userData)
+      throws QueryException, SecurityException {
+    AuthenticationToken authenticationToken = getUserService().getToken(token);
+    if (userData == null) {
+      throw new QueryException("user field cannot be undefined");
+    }
+    User user = getUserService().getUserByLogin(login);
+    if (user == null) {
+      throw new ObjectNotFoundException("user doesn't exist");
+    }
+    boolean isAdmin = getUserService().userHasPrivilege(authenticationToken, PrivilegeType.USER_MANAGEMENT);
+    if (!isAdmin && !login.equalsIgnoreCase(getUserService().getUserByToken(token).getLogin())) {
+      throw new SecurityException("Access denied");
+    }
+    for (String key : userData.keySet()) {
+      Object value = userData.get(key);
+      String stringValue = null;
+      if (value instanceof String) {
+        stringValue = (String) value;
+      }
+      if (key.equalsIgnoreCase("name")) {
+        user.setName(stringValue);
+      } else if (key.equalsIgnoreCase("surname")) {
+        user.setSurname(stringValue);
+      } else if (key.equalsIgnoreCase("email")) {
+        user.setEmail(stringValue);
+      } else if (key.equalsIgnoreCase("password")) {
+        if (stringValue != null && !stringValue.trim().isEmpty()) {
+          user.setCryptedPassword(getUserService().encodePassword(stringValue));
+        }
+      } else if (key.equalsIgnoreCase("login")) {
+        if (!user.getLogin().equals((String) value)) {
+          throw new QueryException("login cannot be modified");
+        }
+      } else {
+        throw new QueryException("Unknown parameter: " + key);
+      }
+    }
+    getUserService().updateUser(user);
+    return getUser(token, login, "");
+  }
 
 }