From ab38f9d690b23f0ee6580e83affc6a1d5a023473 Mon Sep 17 00:00:00 2001
From: Piotr Gawron <piotr.gawron@uni.lu>
Date: Fri, 13 Oct 2017 15:48:36 +0200
Subject: [PATCH] adding new users implemented

---
 frontend-js/.idea/frontend-js.iml             |   3 +
 frontend-js/src/main/js/Admin.js              | 227 +++++++++---------
 frontend-js/src/main/js/ServerConnector.js    |  25 +-
 .../src/main/js/gui/admin/EditUserDialog.js   |  35 ++-
 .../src/main/js/gui/admin/UsersAdminPanel.js  |  14 ++
 .../test/js/gui/admin/UserAdminPanel-test.js  |  20 ++
 .../java/lcsb/mapviewer/api/BaseRestImpl.java |  10 +
 .../api/projects/ProjectRestImpl.java         |  10 -
 .../mapviewer/api/users/UserController.java   |  14 +-
 .../mapviewer/api/users/UserRestImpl.java     |  41 +++-
 10 files changed, 262 insertions(+), 137 deletions(-)

diff --git a/frontend-js/.idea/frontend-js.iml b/frontend-js/.idea/frontend-js.iml
index 7d104eaca0..26f5495ad6 100644
--- a/frontend-js/.idea/frontend-js.iml
+++ b/frontend-js/.idea/frontend-js.iml
@@ -4,8 +4,11 @@
     <content url="file://$MODULE_DIR$">
       <sourceFolder url="file://$MODULE_DIR$/src/test" isTestSource="true" />
       <excludeFolder url="file://$MODULE_DIR$/.tmp" />
+      <excludeFolder url="file://$MODULE_DIR$/coverage" />
       <excludeFolder url="file://$MODULE_DIR$/dist" />
+      <excludeFolder url="file://$MODULE_DIR$/target" />
       <excludeFolder url="file://$MODULE_DIR$/temp" />
+      <excludeFolder url="file://$MODULE_DIR$/testFiles" />
       <excludeFolder url="file://$MODULE_DIR$/tmp" />
     </content>
     <orderEntry type="inheritedJdk" />
diff --git a/frontend-js/src/main/js/Admin.js b/frontend-js/src/main/js/Admin.js
index b492db71a5..d1b6113aca 100644
--- a/frontend-js/src/main/js/Admin.js
+++ b/frontend-js/src/main/js/Admin.js
@@ -12,9 +12,9 @@ var ObjectWithListeners = require('./ObjectWithListeners');
 var CommentsAdminPanel = require('./gui/admin/CommentsAdminPanel');
 var ConfigurationAdminPanel = require('./gui/admin/ConfigurationAdminPanel');
 var MapsAdminPanel = require('./gui/admin/MapsAdminPanel');
-var ServicesAdminPanel = require('./gui/admin/ServicesAdminPanel');
 var UsersAdminPanel = require('./gui/admin/UsersAdminPanel');
 
+// noinspection JSUnusedLocalSymbols
 var logger = require('./logger');
 var Functions = require('./Functions');
 
@@ -26,163 +26,160 @@ var Functions = require('./Functions');
  *          creation
  */
 function Admin(options) {
-    var self = this;
-    self._panels = [];
-    self._tabIdCount = 0;
-    if (!(options instanceof CustomMapOptions)) {
-        options = new CustomMapOptions(options);
-    }
-    self.setProject(options.getProject());
-    self.setElement(options.getElement());
-
-    self.setConfiguration(options.getConfiguration());
-    self.setGuiUtils(new GuiUtils());
-    self._createGui();
+  var self = this;
+  self._panels = [];
+  self._tabIdCount = 0;
+  if (!(options instanceof CustomMapOptions)) {
+    options = new CustomMapOptions(options);
+  }
+  self.setProject(options.getProject());
+  self.setElement(options.getElement());
+
+  self.setConfiguration(options.getConfiguration());
+  self.setGuiUtils(new GuiUtils());
+  self._createGui();
 }
 
 Admin.prototype = Object.create(ObjectWithListeners.prototype);
 Admin.prototype.constructor = ObjectWithListeners;
 
 Admin.prototype._createGui = function () {
-    var self = this;
-    self.getElement().innerHTML = "";
-    var headerDiv = Functions.createElement({
-        type: "div"
-    });
-    self.setHeader(new Header({
-        element: headerDiv,
-        customMap: null,
-        project: self.getProject(),
-        adminLink: false,
-    }));
-    self.getElement().appendChild(headerDiv);
-
-    var panels = [{
-        name: "COMMENTS",
-        panelClass: CommentsAdminPanel,
-    }, {
-        name: "PROJECTS",
-        panelClass: MapsAdminPanel,
-    }, {
-        name: "USERS",
-        panelClass: UsersAdminPanel,
-    }, {
-        name: "SERVICES",
-        panelClass: ServicesAdminPanel,
-    }, {
-        name: "CONFIGURATION",
-        panelClass: ConfigurationAdminPanel,
-    }];
-
-    var tabDiv = Functions.createElement({
-        type: "div",
-        name: "tabView",
-        className: "tabbable boxed parentTabs"
-    });
-    self.getElement().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);
-
-    for (var i = 0; i < panels.length; i++) {
-        self.addTab(panels[i], tabMenuDiv, tabContentDiv);
-    }
+  var self = this;
+  self.getElement().innerHTML = "";
+  var headerDiv = Functions.createElement({
+    type: "div"
+  });
+  self.setHeader(new Header({
+    element: headerDiv,
+    customMap: null,
+    project: self.getProject(),
+    adminLink: false
+  }));
+  self.getElement().appendChild(headerDiv);
+
+  var panels = [{
+    name: "COMMENTS",
+    panelClass: CommentsAdminPanel
+  }, {
+    name: "PROJECTS",
+    panelClass: MapsAdminPanel
+  }, {
+    name: "USERS",
+    panelClass: UsersAdminPanel
+  }, {
+    name: "CONFIGURATION",
+    panelClass: ConfigurationAdminPanel
+  }];
+
+  var tabDiv = Functions.createElement({
+    type: "div",
+    name: "tabView",
+    className: "tabbable boxed parentTabs"
+  });
+  self.getElement().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);
+
+  for (var i = 0; i < panels.length; i++) {
+    self.addTab(panels[i], tabMenuDiv, tabContentDiv);
+  }
 };
 
 Admin.prototype.addTab = function (params, navElement, contentElement) {
-    var self = this;
-
-    var tabId = "admin_panel_tab_" + this._tabIdCount;
-    self._tabIdCount++;
-
-    var navLi = self.getGuiUtils().createTabMenuObject({
-        id: tabId,
-        name: params.name,
-        navigationBar: navElement
-    });
-    navElement.appendChild(navLi);
-
-    var contentDiv = self.getGuiUtils().createTabContentObject({
-        id: tabId,
-        navigationObject: navLi,
-    });
-
-    contentElement.appendChild(contentDiv);
-
-    this._panels.push(new params.panelClass({
-        element: contentDiv,
-        name: params.name,
-        project: self.getProject(),
-        configuration: self.getConfiguration(),
-    }));
+  var self = this;
+
+  var tabId = "admin_panel_tab_" + this._tabIdCount;
+  self._tabIdCount++;
+
+  var navLi = self.getGuiUtils().createTabMenuObject({
+    id: tabId,
+    name: params.name,
+    navigationBar: navElement
+  });
+  navElement.appendChild(navLi);
+
+  var contentDiv = self.getGuiUtils().createTabContentObject({
+    id: tabId,
+    navigationObject: navLi
+  });
+
+  contentElement.appendChild(contentDiv);
+
+  this._panels.push(new params.panelClass({
+    element: contentDiv,
+    name: params.name,
+    project: self.getProject(),
+    configuration: self.getConfiguration()
+  }));
 };
 
 Admin.prototype.setProject = function (project) {
-    this._project = project;
+  this._project = project;
 };
 Admin.prototype.getProject = function () {
-    return this._project;
+  return this._project;
 };
 
 Admin.prototype.setElement = function (element) {
-    this._element = element;
+  this._element = element;
 };
 Admin.prototype.getElement = function () {
-    return this._element;
+  return this._element;
 };
 
 Admin.prototype.init = function () {
-    var promises = [];
-    for (var i = 0; i < this._panels.length; i++) {
-        promises.push(this._panels[i].init());
-    }
-    promises.push(this.getHeader().init());
-    return Promise.all(promises).then(function(){
-      $(window).trigger('resize');
-    });
+  var promises = [];
+  for (var i = 0; i < this._panels.length; i++) {
+    promises.push(this._panels[i].init());
+  }
+  promises.push(this.getHeader().init());
+  return Promise.all(promises).then(function () {
+    $(window).trigger('resize');
+  });
 };
 
 Admin.prototype.setConfiguration = function (configuration) {
-    this._configuration = configuration;
+  this._configuration = configuration;
 };
 
 Admin.prototype.getConfiguration = function () {
-    return this._configuration;
+  return this._configuration;
 };
 
 Admin.prototype.setHeader = function (header) {
-    this._header = header;
+  this._header = header;
 };
 
 Admin.prototype.getHeader = function () {
-    return this._header;
+  return this._header;
 };
 
 Admin.prototype.setGuiUtils = function (guiUtils) {
-    this._guiUtils = guiUtils;
+  this._guiUtils = guiUtils;
 };
 
 Admin.prototype.getGuiUtils = function () {
-    return this._guiUtils;
+  return this._guiUtils;
 };
 
 Admin.prototype.destroy = function () {
-    var self = this;
-    var promises = [];
-    promises.push(self.getHeader().destroy());
-    for (var i = 0; i < self._panels.length; i++) {
-        promises.push(self._panels[i].destroy());
-    }
-    return Promise.all(promises);
+  var self = this;
+  var promises = [];
+  promises.push(self.getHeader().destroy());
+  for (var i = 0; i < self._panels.length; i++) {
+    promises.push(self._panels[i].destroy());
+  }
+  return Promise.all(promises);
 };
 
 module.exports = Admin;
diff --git a/frontend-js/src/main/js/ServerConnector.js b/frontend-js/src/main/js/ServerConnector.js
index e7786dd394..3b73e44a80 100644
--- a/frontend-js/src/main/js/ServerConnector.js
+++ b/frontend-js/src/main/js/ServerConnector.js
@@ -871,6 +871,8 @@ ServerConnector.getUser = function (login) {
       self._usersByLogin[user.getLogin()] = user;
     }
     return self._usersByLogin[user.getLogin()];
+  }).then(null, function (error) {
+    return self.processNetworkError(error);
   });
 };
 
@@ -893,6 +895,25 @@ ServerConnector.updateUser = function (user) {
     return self.updateUserPrivileges({user: user, privileges: user.privilegesToExport(configuration)});
   });
 
+};
+ServerConnector.addUser = function (user) {
+  var self = this;
+  var queryParams = {
+    login: user.getLogin()
+  };
+  var filterParams = {
+    login: user.getLogin(),
+    name: user.getName(),
+    surname: user.getSurname(),
+    password: user.getPassword(),
+    email: user.getEmail()
+  };
+  return self.sendPostRequest(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) {
@@ -1132,7 +1153,7 @@ ServerConnector.getReactions = function (params) {
 ServerConnector.getAliases = function (params) {
   var self = this;
   var queryParams = {
-    modelId: params.modelId,
+    modelId: params.modelId
   };
   if (params.ids === undefined) {
     params.ids = [];
@@ -1148,7 +1169,7 @@ ServerConnector.getAliases = function (params) {
     columns: params.columns,
     type: params.type,
     excludedCompartmentIds: params.excludedCompartmentIds,
-    includedCompartmentIds: params.includedCompartmentIds,
+    includedCompartmentIds: params.includedCompartmentIds
 
   };
   return self.getProjectId(params.projectId).then(function (result) {
diff --git a/frontend-js/src/main/js/gui/admin/EditUserDialog.js b/frontend-js/src/main/js/gui/admin/EditUserDialog.js
index 58f3c3ef8e..bb29f70660 100644
--- a/frontend-js/src/main/js/gui/admin/EditUserDialog.js
+++ b/frontend-js/src/main/js/gui/admin/EditUserDialog.js
@@ -26,11 +26,19 @@ EditUserDialog.prototype.constructor = EditUserDialog;
 
 EditUserDialog.prototype.setUser = function (user) {
   this._user = user;
+  this.setIsNewUser(user.getLogin() === undefined);
 };
 EditUserDialog.prototype.getUser = function () {
   return this._user;
 };
 
+EditUserDialog.prototype.setIsNewUser = function (isNewUser) {
+  this._isNewUser = isNewUser;
+};
+EditUserDialog.prototype.getIsNewUser = function () {
+  return this._isNewUser;
+};
+
 EditUserDialog.prototype.createGui = function () {
   var self = this;
   var element = self.getElement();
@@ -115,6 +123,13 @@ EditUserDialog.prototype.addTab = function (params) {
   params.tabContentDiv.appendChild(contentDiv);
 };
 
+function getStringIfDefined(value) {
+  if (value === undefined) {
+    return "";
+  }
+  return value;
+}
+
 EditUserDialog.prototype.createGeneralTabContent = function () {
   var self = this;
   var user = self.getUser();
@@ -149,7 +164,7 @@ EditUserDialog.prototype.createGeneralTabContent = function () {
     loginRow.appendChild(new Functions.createElement({
       type: "div",
       style: "display:table-cell",
-      content: "<input name='userLogin' value='" + user.getLogin() + "' readonly/>"
+      content: "<input name='userLogin' value='" + getStringIfDefined(user.getLogin()) + "' readonly/>"
     }));
   }
 
@@ -198,7 +213,7 @@ EditUserDialog.prototype.createGeneralTabContent = function () {
   nameRow.appendChild(new Functions.createElement({
     type: "div",
     style: "display:table-cell",
-    content: "<input name='userName' value='" + user.getName() + "'/>"
+    content: "<input name='userName' value='" + getStringIfDefined(user.getName()) + "'/>"
   }));
 
   var surnameRow = new Functions.createElement({
@@ -214,7 +229,7 @@ EditUserDialog.prototype.createGeneralTabContent = function () {
   surnameRow.appendChild(new Functions.createElement({
     type: "div",
     style: "display:table-cell",
-    content: "<input name='userSurname' value='" + user.getSurname() + "'/>"
+    content: "<input name='userSurname' value='" + getStringIfDefined(user.getSurname()) + "'/>"
   }));
 
   var emailRow = new Functions.createElement({
@@ -230,7 +245,7 @@ EditUserDialog.prototype.createGeneralTabContent = function () {
   emailRow.appendChild(new Functions.createElement({
     type: "div",
     style: "display:table-cell",
-    content: "<input name='userEmail' value='" + user.getEmail() + "'/>"
+    content: "<input name='userEmail' value='" + getStringIfDefined(user.getEmail()) + "'/>"
   }));
 
 
@@ -494,9 +509,13 @@ EditUserDialog.prototype.destroy = function () {
 EditUserDialog.prototype.open = function () {
   var self = this;
   var div = self.getElement();
+  var title = self.getUser().getLogin();
+  if (title === undefined) {
+    title = "NEW USER";
+  }
   if (!$(div).hasClass("ui-dialog-content")) {
     $(div).dialog({
-      title: self.getProject().getProjectId(),
+      title: title,
       width: window.innerWidth / 2,
       height: window.innerHeight / 2
     });
@@ -513,7 +532,11 @@ EditUserDialog.prototype.onSaveClicked = function () {
     user.setEmail(self.getEmail());
     user.setName(self.getName());
     user.setSurname(self.getSurname());
-    return ServerConnector.updateUser(user);
+    if (self.getIsNewUser()) {
+      return ServerConnector.addUser(user);
+    } else {
+      return ServerConnector.updateUser(user);
+    }
   });
 };
 
diff --git a/frontend-js/src/main/js/gui/admin/UsersAdminPanel.js b/frontend-js/src/main/js/gui/admin/UsersAdminPanel.js
index 6ac46f3513..3db303562b 100644
--- a/frontend-js/src/main/js/gui/admin/UsersAdminPanel.js
+++ b/frontend-js/src/main/js/gui/admin/UsersAdminPanel.js
@@ -2,6 +2,7 @@
 
 var AbstractAdminPanel = require('./AbstractAdminPanel');
 var EditUserDialog = require('./EditUserDialog');
+var User = require("../../map/data/User");
 
 var Functions = require('../../Functions');
 var GuiConnector = require('../../GuiConnector');
@@ -234,4 +235,17 @@ UsersAdminPanel.prototype.destroy = function () {
 
 };
 
+UsersAdminPanel.prototype.onAddClicked = function () {
+  var self = this;
+  var user = new User({});
+  GuiConnector.showProcessing();
+  return self.getDialog(user).then(function (dialog) {
+    dialog.open();
+    GuiConnector.hideProcessing();
+  }).then(null, function (error) {
+    GuiConnector.hideProcessing();
+    return Promise.reject(error);
+  });
+};
+
 module.exports = UsersAdminPanel;
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 76764bcf97..29ab789732 100644
--- a/frontend-js/src/test/js/gui/admin/UserAdminPanel-test.js
+++ b/frontend-js/src/test/js/gui/admin/UserAdminPanel-test.js
@@ -71,5 +71,25 @@ describe('UsersAdminPanel', function () {
       return mapTab.destroy();
     });
   });
+  it('onAddClicked', 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.onAddClicked();
+    }).then(function () {
+      return mapTab.destroy();
+    });
+  });
+
 
 });
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/BaseRestImpl.java b/rest-api/src/main/java/lcsb/mapviewer/api/BaseRestImpl.java
index 7729b2296f..0f82683334 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/BaseRestImpl.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/BaseRestImpl.java
@@ -298,4 +298,14 @@ public abstract class BaseRestImpl {
     return parser;
   }
 
+  protected String getFirstValue(List<Object> list) {
+    if (list == null) {
+      return null;
+    }
+    if (list.size() > 0) {
+      return (String) list.get(0);
+    }
+    return null;
+  }
+
 }
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectRestImpl.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectRestImpl.java
index 802493819f..2bca5632c6 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectRestImpl.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectRestImpl.java
@@ -485,7 +485,6 @@ public class ProjectRestImpl extends BaseRestImpl {
 
   public ProjectMetaData addProject(String token, String projectId, MultiValueMap<String, Object> data, String path)
       throws SecurityException, QueryException, IOException {
-    logger.info(data);
     AuthenticationToken authenticationToken = getUserService().getToken(token);
     User user = getUserService().getUserByToken(authenticationToken);
     Project project = getProjectService().getProjectByProjectId(projectId, authenticationToken);
@@ -595,15 +594,6 @@ public class ProjectRestImpl extends BaseRestImpl {
     }
   }
 
-  private String getFirstValue(List<Object> list) {
-    if (list == null) {
-      return null;
-    }
-    if (list.size() > 0) {
-      return (String) list.get(0);
-    }
-    return null;
-  }
 
   /**
    * Method that computes md5 hash for a given {@link String}.
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 787825759e..81c3a5335d 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
@@ -12,6 +12,7 @@ import javax.servlet.http.HttpServletResponse;
 import org.apache.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.MediaType;
+import org.springframework.util.MultiValueMap;
 import org.springframework.web.bind.annotation.CookieValue;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -30,7 +31,6 @@ 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 {
@@ -155,7 +155,17 @@ public class UserController extends BaseController {
       return userRest.updateUser(token, login, data);
   }
 
-  
+  @RequestMapping(value = "/users/{login:.+}", method = { RequestMethod.POST }, produces = { MediaType.APPLICATION_JSON_VALUE })
+  public Map<String, Object>  addOverlay(//
+      @RequestBody MultiValueMap<String, Object> formData, //
+      @PathVariable(value = "login") String login, //
+      @CookieValue(value = Configuration.AUTH_TOKEN) String token //
+  ) throws SecurityException, IOException, QueryException {
+    return userRest.addProject(token, login, formData);
+
+  }
+
+
   /**
    * @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 5f6f44c17e..895042c011 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
@@ -10,13 +10,13 @@ import java.util.Set;
 import org.apache.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.MultiValueMap;
 
 import lcsb.mapviewer.api.BaseRestImpl;
 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;
@@ -28,7 +28,6 @@ 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 {
@@ -448,4 +447,42 @@ public class UserRestImpl extends BaseRestImpl {
     return getUser(token, login, "");
   }
 
+  public Map<String, Object> addProject(String token, String login, MultiValueMap<String, Object> userData)
+      throws QueryException, SecurityException {
+    logger.debug(userData);
+    AuthenticationToken authenticationToken = getUserService().getToken(token);
+
+    User user = getUserService().getUserByLogin(login);
+    if (user != null) {
+      throw new QueryException("user exists");
+    }
+    if (!getUserService().userHasPrivilege(authenticationToken, PrivilegeType.USER_MANAGEMENT)) {
+      throw new SecurityException("Access denied");
+    }
+    user = new User();
+    user.setLogin(login);
+    for (String key : userData.keySet()) {
+      String stringValue = getFirstValue((List<Object>) userData.get(key));
+      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(stringValue)) {
+          throw new QueryException("login must match url");
+        }
+      } else {
+        throw new QueryException("Unknown parameter: " + key);
+      }
+    }
+    getUserService().addUser(user);
+    return getUser(token, login, "");
+  }
+
 }
-- 
GitLab