]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-11610 Create api/users/update_login WS
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Tue, 8 Jan 2019 11:33:58 +0000 (12:33 +0100)
committersonartech <sonartech@sonarsource.com>
Wed, 16 Jan 2019 08:43:14 +0000 (09:43 +0100)
server/sonar-server/src/main/java/org/sonar/server/user/UserUpdater.java
server/sonar-server/src/main/java/org/sonar/server/user/ws/UpdateLoginAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/user/ws/UsersWsModule.java
server/sonar-server/src/test/java/org/sonar/server/user/UserUpdaterUpdateTest.java
server/sonar-server/src/test/java/org/sonar/server/user/ws/UpdateLoginActionTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/user/ws/UsersWsModuleTest.java
sonar-ws/src/main/java/org/sonarqube/ws/client/users/UpdateLoginRequest.java [new file with mode: 0644]
sonar-ws/src/main/java/org/sonarqube/ws/client/users/UsersService.java

index 5300f19b6d442aff2ac78fe08cdd18a1d00fc8d3..f85f3ce7ef39e9db89408ee92f7192533a068fa7 100644 (file)
@@ -225,14 +225,18 @@ public class UserUpdater {
 
   private boolean updateLogin(DbSession dbSession, UpdateUser updateUser, UserDto userDto, List<String> messages) {
     String newLogin = updateUser.login();
-    if (updateUser.isLoginChanged() && validateLoginFormat(newLogin, messages) && !Objects.equals(userDto.getLogin(), newLogin)) {
-      checkLoginUniqueness(dbSession, newLogin);
-      dbClient.propertiesDao().selectByKeyAndMatchingValue(dbSession, DEFAULT_ISSUE_ASSIGNEE, userDto.getLogin())
-        .forEach(p -> dbClient.propertiesDao().saveProperty(p.setValue(newLogin)));
-      userDto.setLogin(newLogin);
-      return true;
+    if (!updateUser.isLoginChanged() || !validateLoginFormat(newLogin, messages) || Objects.equals(userDto.getLogin(), newLogin)) {
+      return false;
     }
-    return false;
+    checkLoginUniqueness(dbSession, newLogin);
+    dbClient.propertiesDao().selectByKeyAndMatchingValue(dbSession, DEFAULT_ISSUE_ASSIGNEE, userDto.getLogin())
+      .forEach(p -> dbClient.propertiesDao().saveProperty(p.setValue(newLogin)));
+    userDto.setLogin(newLogin);
+    if (userDto.isLocal()) {
+      userDto.setExternalLogin(newLogin);
+      userDto.setExternalId(newLogin);
+    }
+    return true;
   }
 
   private static boolean updateName(UpdateUser updateUser, UserDto userDto, List<String> messages) {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/ws/UpdateLoginAction.java b/server/sonar-server/src/main/java/org/sonar/server/user/ws/UpdateLoginAction.java
new file mode 100644 (file)
index 0000000..a8cf913
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.user.ws;
+
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.user.UserDto;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.organization.OrganizationUpdater;
+import org.sonar.server.user.UpdateUser;
+import org.sonar.server.user.UserSession;
+import org.sonar.server.user.UserUpdater;
+
+import static java.lang.String.format;
+import static org.sonar.server.user.UserUpdater.LOGIN_MAX_LENGTH;
+import static org.sonar.server.user.UserUpdater.LOGIN_MIN_LENGTH;
+
+public class UpdateLoginAction implements UsersWsAction {
+
+  public static final String PARAM_LOGIN = "login";
+  public static final String PARAM_NEW_LOGIN = "newLogin";
+
+  private final DbClient dbClient;
+  private final UserSession userSession;
+  private final UserUpdater userUpdater;
+  private final OrganizationUpdater organizationUpdater;
+
+  public UpdateLoginAction(DbClient dbClient, UserSession userSession, UserUpdater userUpdater, OrganizationUpdater organizationUpdater) {
+    this.dbClient = dbClient;
+    this.userSession = userSession;
+    this.userUpdater = userUpdater;
+    this.organizationUpdater = organizationUpdater;
+  }
+
+  @Override
+  public void define(WebService.NewController controller) {
+    WebService.NewAction action = controller.createAction("update_login")
+      .setDescription("Update a user login. A login can be updated many times,<br/>" +
+        "Updating the login of a user will invalidate his browser session, he will be required to login again.<br/>" +
+        "Requires Administer System permission")
+      .setSince("7.6")
+      .setPost(true)
+      .setHandler(this);
+
+    action.createParam(PARAM_LOGIN)
+      .setRequired(true)
+      .setDescription("The current login (case-sensitive)")
+      .setExampleValue("mylogin");
+
+    action.createParam(PARAM_NEW_LOGIN)
+      .setRequired(true)
+      .setMaximumLength(LOGIN_MAX_LENGTH)
+      .setMinimumLength(LOGIN_MIN_LENGTH)
+      .setDescription("The new login. It must not already exist.")
+      .setExampleValue("mynewlogin");
+  }
+
+  @Override
+  public void handle(Request request, Response response) throws Exception {
+    userSession.checkLoggedIn().checkIsSystemAdministrator();
+    String login = request.mandatoryParam(PARAM_LOGIN);
+    String newLogin = request.mandatoryParam(PARAM_NEW_LOGIN);
+    try (DbSession dbSession = dbClient.openSession(false)) {
+      UserDto user = getUser(dbSession, login);
+      userUpdater.updateAndCommit(
+        dbSession,
+        user,
+        new UpdateUser().setLogin(newLogin),
+        u -> updatePersonalOrganization(dbSession, u));
+      response.noContent();
+    }
+  }
+
+  private UserDto getUser(DbSession dbSession, String login) {
+    UserDto user = dbClient.userDao().selectByLogin(dbSession, login);
+    if (user == null || !user.isActive()) {
+      throw new NotFoundException(format("User '%s' doesn't exist", login));
+    }
+    return user;
+  }
+
+  private void updatePersonalOrganization(DbSession dbSession, UserDto user) {
+    String personalOrganizationUuid = user.getOrganizationUuid();
+    if (personalOrganizationUuid == null) {
+      return;
+    }
+    dbClient.organizationDao().selectByUuid(dbSession, personalOrganizationUuid)
+      .ifPresent(organization -> organizationUpdater.updateOrganizationKey(dbSession, organization, user.getLogin()));
+  }
+
+}
index 1fb48b966f6d5468ab3d542081d534db26a9a6a6..8e94362ab4bcd19f4823de05e6a32e8554664511 100644 (file)
@@ -36,6 +36,7 @@ public class UsersWsModule extends Module {
       UsersWs.class,
       CreateAction.class,
       UpdateAction.class,
+      UpdateLoginAction.class,
       DeactivateAction.class,
       ChangePasswordAction.class,
       CurrentAction.class,
index 65483a6d88b754378067ce40e4d9880b44fe3529..9b03952c851452e6bd0b3bcb9df82c833bcdf6a7 100644 (file)
@@ -36,7 +36,6 @@ import org.sonar.db.property.PropertyDto;
 import org.sonar.db.property.PropertyQuery;
 import org.sonar.db.user.GroupDto;
 import org.sonar.db.user.UserDto;
-import org.sonar.db.user.UserTesting;
 import org.sonar.server.authentication.CredentialsLocalAuthentication;
 import org.sonar.server.es.EsTester;
 import org.sonar.server.exceptions.BadRequestException;
@@ -55,6 +54,7 @@ import static org.assertj.core.api.Assertions.tuple;
 import static org.assertj.core.data.MapEntry.entry;
 import static org.mockito.Mockito.mock;
 import static org.sonar.api.CoreProperties.DEFAULT_ISSUE_ASSIGNEE;
+import static org.sonar.db.user.UserTesting.newExternalUser;
 import static org.sonar.db.user.UserTesting.newLocalUser;
 import static org.sonar.db.user.UserTesting.newUserDto;
 
@@ -117,7 +117,7 @@ public class UserUpdaterUpdateTest {
 
   @Test
   public void update_user_external_identity_when_user_was_not_local() {
-    UserDto user = db.users().insertUser(UserTesting.newExternalUser(DEFAULT_LOGIN, "Marius", "marius@email.com"));
+    UserDto user = db.users().insertUser(newExternalUser(DEFAULT_LOGIN, "Marius", "marius@email.com"));
     createDefaultGroup();
 
     underTest.updateAndCommit(session, user, new UpdateUser()
@@ -172,23 +172,50 @@ public class UserUpdaterUpdateTest {
   }
 
   @Test
-  public void update_only_login() {
-    UserDto oldUser = db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@lesbronzes.fr"));
+  public void update_only_login_of_local_account() {
+    UserDto user = db.users().insertUser(newLocalUser(DEFAULT_LOGIN, "Marius", "marius@lesbronzes.fr"));
     createDefaultGroup();
 
-    underTest.updateAndCommit(session, oldUser, new UpdateUser()
+    underTest.updateAndCommit(session, user, new UpdateUser()
       .setLogin("new_login"), u -> {
       });
 
     assertThat(dbClient.userDao().selectByLogin(session, DEFAULT_LOGIN)).isNull();
-    UserDto dto = dbClient.userDao().selectByUuid(session, oldUser.getUuid());
-    assertThat(dto.getLogin()).isEqualTo("new_login");
+    UserDto userReloaded = dbClient.userDao().selectByUuid(session, user.getUuid());
+    assertThat(userReloaded.getLogin()).isEqualTo("new_login");
+    assertThat(userReloaded.getExternalIdentityProvider()).isEqualTo("sonarqube");
+    assertThat(userReloaded.getExternalLogin()).isEqualTo("new_login");
+    assertThat(userReloaded.getExternalId()).isEqualTo("new_login");
+    // Following fields has not changed
+    assertThat(userReloaded.isLocal()).isTrue();
+    assertThat(userReloaded.getName()).isEqualTo(user.getName());
+    assertThat(userReloaded.getEmail()).isEqualTo(user.getEmail());
+    assertThat(userReloaded.getScmAccountsAsList()).containsAll(user.getScmAccountsAsList());
+    assertThat(userReloaded.getSalt()).isEqualTo(user.getSalt());
+    assertThat(userReloaded.getCryptedPassword()).isEqualTo(user.getCryptedPassword());
+  }
+
+  @Test
+  public void update_only_login_of_external_account() {
+    UserDto user = db.users().insertUser(newExternalUser(DEFAULT_LOGIN, "Marius", "marius@lesbronzes.fr"));
+    createDefaultGroup();
+
+    underTest.updateAndCommit(session, user, new UpdateUser()
+      .setLogin("new_login"), u -> {
+    });
+
+    assertThat(dbClient.userDao().selectByLogin(session, DEFAULT_LOGIN)).isNull();
+    UserDto userReloaded = dbClient.userDao().selectByUuid(session, user.getUuid());
+    assertThat(userReloaded.getLogin()).isEqualTo("new_login");
     // Following fields has not changed
-    assertThat(dto.getName()).isEqualTo(oldUser.getName());
-    assertThat(dto.getEmail()).isEqualTo(oldUser.getEmail());
-    assertThat(dto.getScmAccountsAsList()).containsAll(oldUser.getScmAccountsAsList());
-    assertThat(dto.getSalt()).isEqualTo(oldUser.getSalt());
-    assertThat(dto.getCryptedPassword()).isEqualTo(oldUser.getCryptedPassword());
+    assertThat(userReloaded.isLocal()).isFalse();
+    assertThat(userReloaded.getExternalLogin()).isEqualTo(user.getExternalLogin());
+    assertThat(userReloaded.getExternalId()).isEqualTo(user.getExternalId());
+    assertThat(userReloaded.getName()).isEqualTo(user.getName());
+    assertThat(userReloaded.getEmail()).isEqualTo(user.getEmail());
+    assertThat(userReloaded.getScmAccountsAsList()).containsAll(user.getScmAccountsAsList());
+    assertThat(userReloaded.getSalt()).isEqualTo(user.getSalt());
+    assertThat(userReloaded.getCryptedPassword()).isEqualTo(user.getCryptedPassword());
   }
 
   @Test
@@ -352,7 +379,7 @@ public class UserUpdaterUpdateTest {
 
   @Test
   public void update_only_external_id() {
-    UserDto user = db.users().insertUser(UserTesting.newExternalUser(DEFAULT_LOGIN, "Marius", "marius@email.com")
+    UserDto user = db.users().insertUser(newExternalUser(DEFAULT_LOGIN, "Marius", "marius@email.com")
       .setExternalId("1234")
       .setExternalLogin("john.smith")
       .setExternalIdentityProvider("github"));
@@ -368,7 +395,7 @@ public class UserUpdaterUpdateTest {
 
   @Test
   public void update_only_external_login() {
-    UserDto user = db.users().insertUser(UserTesting.newExternalUser(DEFAULT_LOGIN, "Marius", "marius@email.com")
+    UserDto user = db.users().insertUser(newExternalUser(DEFAULT_LOGIN, "Marius", "marius@email.com")
       .setExternalId("ABCD")
       .setExternalLogin("john")
       .setExternalIdentityProvider("github"));
@@ -384,7 +411,7 @@ public class UserUpdaterUpdateTest {
 
   @Test
   public void update_only_external_identity_provider() {
-    UserDto user = db.users().insertUser(UserTesting.newExternalUser(DEFAULT_LOGIN, "Marius", "marius@email.com")
+    UserDto user = db.users().insertUser(newExternalUser(DEFAULT_LOGIN, "Marius", "marius@email.com")
       .setExternalId("ABCD")
       .setExternalLogin("john")
       .setExternalIdentityProvider("github"));
@@ -400,7 +427,7 @@ public class UserUpdaterUpdateTest {
 
   @Test
   public void does_not_update_user_when_no_change() {
-    UserDto user = UserTesting.newExternalUser(DEFAULT_LOGIN, "Marius", "marius@email.com")
+    UserDto user = newExternalUser(DEFAULT_LOGIN, "Marius", "marius@email.com")
       .setScmAccounts(asList("ma1", "ma2"));
     db.users().insertUser(user);
     createDefaultGroup();
@@ -417,7 +444,7 @@ public class UserUpdaterUpdateTest {
 
   @Test
   public void does_not_update_user_when_no_change_and_scm_account_reordered() {
-    UserDto user = UserTesting.newExternalUser(DEFAULT_LOGIN, "Marius", "marius@email.com")
+    UserDto user = newExternalUser(DEFAULT_LOGIN, "Marius", "marius@email.com")
       .setScmAccounts(asList("ma1", "ma2"));
     db.users().insertUser(user);
     createDefaultGroup();
diff --git a/server/sonar-server/src/test/java/org/sonar/server/user/ws/UpdateLoginActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/user/ws/UpdateLoginActionTest.java
new file mode 100644 (file)
index 0000000..782a680
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.user.ws;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.server.ws.WebService.Param;
+import org.sonar.api.utils.System2;
+import org.sonar.core.util.UuidFactoryFast;
+import org.sonar.db.DbTester;
+import org.sonar.db.organization.OrganizationDto;
+import org.sonar.db.user.UserDto;
+import org.sonar.server.es.EsTester;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.organization.OrganizationUpdater;
+import org.sonar.server.organization.OrganizationUpdaterImpl;
+import org.sonar.server.organization.OrganizationValidationImpl;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.user.NewUserNotifier;
+import org.sonar.server.user.UserUpdater;
+import org.sonar.server.user.index.UserIndexer;
+import org.sonar.server.ws.TestResponse;
+import org.sonar.server.ws.WsActionTester;
+
+import static java.lang.String.format;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
+import static org.mockito.Mockito.mock;
+
+public class UpdateLoginActionTest {
+
+  private System2 system2 = new System2();
+
+  @Rule
+  public DbTester db = DbTester.create(system2);
+  @Rule
+  public EsTester es = EsTester.create();
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone().logIn().setSystemAdministrator();
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  private MapSettings settings = new MapSettings();
+  private OrganizationUpdater organizationUpdater = new OrganizationUpdaterImpl(db.getDbClient(), mock(System2.class), UuidFactoryFast.getInstance(),
+    new OrganizationValidationImpl(), settings.asConfig(), null, null, null, null);
+
+  private WsActionTester ws = new WsActionTester(new UpdateLoginAction(db.getDbClient(), userSession,
+    new UserUpdater(system2, mock(NewUserNotifier.class), db.getDbClient(), new UserIndexer(db.getDbClient(), es.client()),
+      null, null, null, null, null, null),
+    organizationUpdater));
+
+  @Test
+  public void update_login_from_sonarqube_account() {
+    userSession.logIn().setSystemAdministrator();
+    UserDto user = db.users().insertUser(u -> u
+      .setLogin("old_login")
+      .setLocal(true)
+      .setExternalIdentityProvider("sonarqube")
+      .setExternalLogin("old_login")
+      .setExternalId("old_login"));
+
+    ws.newRequest()
+      .setParam("login", user.getLogin())
+      .setParam("newLogin", "new_login")
+      .execute();
+
+    assertThat(db.getDbClient().userDao().selectByLogin(db.getSession(), "old_login")).isNull();
+    UserDto userReloaded = db.getDbClient().userDao().selectByUuid(db.getSession(), user.getUuid());
+    assertThat(userReloaded.getLogin()).isEqualTo("new_login");
+    assertThat(userReloaded.getExternalLogin()).isEqualTo("new_login");
+    assertThat(userReloaded.getExternalId()).isEqualTo("new_login");
+    assertThat(userReloaded.isLocal()).isTrue();
+    assertThat(userReloaded.getCryptedPassword()).isNotNull().isEqualTo(user.getCryptedPassword());
+    assertThat(userReloaded.getSalt()).isNotNull().isEqualTo(user.getSalt());
+  }
+
+  @Test
+  public void update_login_from_external_account() {
+    userSession.logIn().setSystemAdministrator();
+    UserDto user = db.users().insertUser(u -> u
+      .setLogin("old_login")
+      .setLocal(false)
+      .setExternalIdentityProvider("github")
+      .setExternalLogin("github_login")
+      .setExternalId("github_id")
+      .setCryptedPassword(null)
+      .setSalt(null));
+
+    ws.newRequest()
+      .setParam("login", user.getLogin())
+      .setParam("newLogin", "new_login")
+      .execute();
+
+    UserDto userReloaded = db.getDbClient().userDao().selectByUuid(db.getSession(), user.getUuid());
+    assertThat(userReloaded.getLogin()).isEqualTo("new_login");
+    assertThat(userReloaded.getExternalLogin()).isEqualTo("github_login");
+    assertThat(userReloaded.getExternalId()).isEqualTo("github_id");
+    assertThat(userReloaded.isLocal()).isFalse();
+    assertThat(userReloaded.getCryptedPassword()).isNull();
+    assertThat(userReloaded.getSalt()).isNull();
+  }
+
+  @Test
+  public void update_personal_organization_when_updating_login() {
+    userSession.logIn().setSystemAdministrator();
+    String oldLogin = "old_login";
+    OrganizationDto personalOrganization = db.organizations().insert(o -> o.setKey(oldLogin).setGuarded(true));
+    UserDto user = db.users().insertUser(u -> u.setLogin(oldLogin).setOrganizationUuid(personalOrganization.getUuid()));
+
+    ws.newRequest()
+      .setParam("login", oldLogin)
+      .setParam("newLogin", "new_login")
+      .execute();
+
+    UserDto userReloaded = db.getDbClient().userDao().selectByUuid(db.getSession(), user.getUuid());
+    assertThat(userReloaded.getLogin()).isEqualTo("new_login");
+    OrganizationDto organizationReloaded = db.getDbClient().organizationDao().selectByUuid(db.getSession(), personalOrganization.getUuid()).get();
+    assertThat(organizationReloaded.getKey()).isEqualTo("new_login");
+  }
+
+  @Test
+  public void fail_with_IAE_when_new_login_is_already_used() {
+    userSession.logIn().setSystemAdministrator();
+    UserDto user = db.users().insertUser();
+    UserDto user2 = db.users().insertUser();
+
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage(format("A user with login '%s' already exists", user2.getLogin()));
+
+    ws.newRequest()
+      .setParam("login", user.getLogin())
+      .setParam("newLogin", user2.getLogin())
+      .execute();
+  }
+
+  @Test
+  public void fail_with_NFE_when_login_does_not_match_active_user() {
+    userSession.logIn().setSystemAdministrator();
+    UserDto user = db.users().insertDisabledUser();
+
+    expectedException.expect(NotFoundException.class);
+    expectedException.expectMessage(format("User '%s' doesn't exist", user.getLogin()));
+
+    ws.newRequest()
+      .setParam("login", user.getLogin())
+      .setParam("newLogin", "new_login")
+      .execute();
+  }
+
+  @Test
+  public void fail_with_NFE_when_login_does_not_match_existing_user() {
+    userSession.logIn().setSystemAdministrator();
+
+    expectedException.expect(NotFoundException.class);
+    expectedException.expectMessage("User 'unknown' doesn't exist");
+
+    ws.newRequest()
+      .setParam("login", "unknown")
+      .setParam("newLogin", "new_login")
+      .execute();
+  }
+
+  @Test
+  public void fail_when_not_system_administrator() {
+    userSession.logIn();
+
+    expectedException.expect(ForbiddenException.class);
+
+    ws.newRequest()
+      .setParam("login", "old_login")
+      .setParam("newLogin", "new_login")
+      .execute();
+  }
+
+  @Test
+  public void response_has_no_content() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn().setSystemAdministrator();
+
+    TestResponse response = ws.newRequest()
+      .setParam("login", user.getLogin())
+      .setParam("newLogin", "new_login")
+      .execute();
+
+    assertThat(response.getStatus()).isEqualTo(204);
+    assertThat(response.getInput()).isEmpty();
+  }
+
+  @Test
+  public void test_definition() {
+    WebService.Action def = ws.getDef();
+    assertThat(def.key()).isEqualTo("update_login");
+    assertThat(def.isPost()).isTrue();
+    assertThat(def.isInternal()).isFalse();
+    assertThat(def.since()).isEqualTo("7.6");
+
+    assertThat(def.params())
+      .extracting(Param::key, Param::isRequired, Param::maximumLength, Param::minimumLength)
+      .containsExactlyInAnyOrder(
+        tuple("login", true, null, null),
+        tuple("newLogin", true, 255, 2));
+  }
+}
index 909f1163e63f33d42ebb084b99850d8a7309cd49..1fbd80a8f78db77fb05cc742101d391e7f5f6fd2 100644 (file)
@@ -34,7 +34,7 @@ public class UsersWsModuleTest {
   public void verify_count_of_added_components() {
     ComponentContainer container = new ComponentContainer();
     new UsersWsModule(new ConfigurationBridge(settings)).configure(container);
-    assertThat(container.size()).isEqualTo(2 + 14);
+    assertThat(container.size()).isEqualTo(2 + 15);
   }
 
   @Test
@@ -43,6 +43,6 @@ public class UsersWsModuleTest {
 
     ComponentContainer container = new ComponentContainer();
     new UsersWsModule(new ConfigurationBridge(settings)).configure(container);
-    assertThat(container.size()).isEqualTo(2 + 15);
+    assertThat(container.size()).isEqualTo(2 + 16);
   }
 }
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/users/UpdateLoginRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/users/UpdateLoginRequest.java
new file mode 100644 (file)
index 0000000..62eb60e
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonarqube.ws.client.users;
+
+import javax.annotation.Generated;
+
+/**
+ * This is part of the internal API.
+ * This is a POST request.
+ * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/users/update_login">Further information about this action online (including a response example)</a>
+ * @since 7.6
+ */
+@Generated("sonar-ws-generator")
+public class UpdateLoginRequest {
+
+  private String login;
+  private String newLogin;
+
+  /**
+   * This is a mandatory parameter.
+   * Example value: "mylogin"
+   */
+  public UpdateLoginRequest setLogin(String login) {
+    this.login = login;
+    return this;
+  }
+
+  public String getLogin() {
+    return login;
+  }
+
+  /**
+   * This is a mandatory parameter.
+   * Example value: "mynewlogin"
+   */
+  public UpdateLoginRequest setNewLogin(String newLogin) {
+    this.newLogin = newLogin;
+    return this;
+  }
+
+  public String getNewLogin() {
+    return newLogin;
+  }
+}
index 8b71cb051e73bfc3f414ccfac3c11470d2da162f..dcbda8e2c2b68544982292069947830e93e54727 100644 (file)
@@ -169,7 +169,7 @@ public class UsersService extends BaseService {
         .setParam("parameter", request.getParameter())
         .setParam("type", request.getType())
         .setMediaType(MediaTypes.JSON)
-      ).content();
+    ).content();
   }
 
   /**
@@ -220,4 +220,20 @@ public class UsersService extends BaseService {
         .setMediaType(MediaTypes.JSON)
       ).content();
   }
+
+  /**
+   *
+   * This is part of the internal API.
+   * This is a POST request.
+   * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/users/update_login">Further information about this action online (including a response example)</a>
+   * @since 7.6
+   */
+  public void updateLogin(UpdateLoginRequest request) {
+    call(
+      new PostRequest(path("update_login"))
+        .setParam("login", request.getLogin())
+        .setParam("newLogin", request.getNewLogin())
+        .setMediaType(MediaTypes.JSON)
+      ).content();
+  }
 }