]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-8715 Handle api/users/create response as protobuf
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 2 Feb 2017 15:36:17 +0000 (16:36 +0100)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Fri, 3 Feb 2017 10:59:06 +0000 (11:59 +0100)
13 files changed:
server/sonar-server/src/main/java/org/sonar/server/user/UserUpdater.java
server/sonar-server/src/main/java/org/sonar/server/user/ws/CreateAction.java
server/sonar-server/src/test/java/org/sonar/server/user/UserUpdaterTest.java
server/sonar-server/src/test/java/org/sonar/server/user/ws/CreateActionTest.java
server/sonar-server/src/test/java/org/sonar/server/user/ws/UsersWsTest.java
server/sonar-server/src/test/java/org/sonar/server/ws/TestRequest.java
sonar-ws/src/main/java/org/sonarqube/ws/client/DefaultWsClient.java
sonar-ws/src/main/java/org/sonarqube/ws/client/WsClient.java
sonar-ws/src/main/java/org/sonarqube/ws/client/user/UserService.java [deleted file]
sonar-ws/src/main/java/org/sonarqube/ws/client/user/UsersService.java [new file with mode: 0644]
sonar-ws/src/main/protobuf/ws-users.proto
sonar-ws/src/test/java/org/sonarqube/ws/client/user/UserServiceTest.java [deleted file]
sonar-ws/src/test/java/org/sonarqube/ws/client/user/UsersServiceTest.java [new file with mode: 0644]

index 6bb8a3b8e3d362da74c4531c9a7fb3272cf6bf8a..a9376e04f19857b31531cd706bd3f346e6dabfa8 100644 (file)
@@ -48,6 +48,7 @@ import org.sonar.server.organization.DefaultOrganizationProvider;
 import org.sonar.server.user.index.UserIndexer;
 import org.sonar.server.util.Validation;
 
+import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Strings.isNullOrEmpty;
 import static com.google.common.collect.Lists.newArrayList;
 import static org.sonar.db.user.UserDto.encryptPassword;
@@ -84,59 +85,32 @@ public class UserUpdater {
     this.defaultOrganizationProvider = defaultOrganizationProvider;
   }
 
-  /**
-   * Return true if the user has been reactivated
-   */
-  public boolean create(NewUser newUser) {
-    DbSession dbSession = dbClient.openSession(false);
-    try {
-      CreatedUser createdUser = create(dbSession, newUser);
+  public UserDto create(NewUser newUser) {
+    try (DbSession dbSession = dbClient.openSession(false)) {
+      UserDto createdUser = create(dbSession, newUser);
       dbClient.userDao().updateRootFlagFromPermissions(dbSession, createdUser.getId(), defaultOrganizationProvider.get().getUuid());
       dbSession.commit();
-      return createdUser.isReactivated();
-    } finally {
-      dbClient.closeSession(dbSession);
+      return createdUser;
     }
   }
 
-  public CreatedUser create(DbSession dbSession, NewUser newUser) {
-    boolean isUserReactivated = false;
+  public UserDto create(DbSession dbSession, NewUser newUser) {
     String login = newUser.login();
     UserDto userDto = dbClient.userDao().selectByLogin(dbSession, newUser.login());
     if (userDto == null) {
       userDto = saveUser(dbSession, createNewUserDto(dbSession, newUser));
-      addDefaultGroup(dbSession, userDto);
     } else {
-      isUserReactivated = reactivateUser(dbSession, userDto, login, newUser);
+      reactivateUser(dbSession, userDto, login, newUser);
     }
+    addDefaultGroup(dbSession, userDto);
     dbSession.commit();
     notifyNewUser(userDto.getLogin(), userDto.getName(), newUser.email());
     userIndexer.index();
-    return new CreatedUser(userDto.getId(), isUserReactivated);
-  }
-
-  private static final class CreatedUser {
-    private final long id;
-    private final boolean reactivated;
-
-    private CreatedUser(long id, boolean reactivated) {
-      this.id = id;
-      this.reactivated = reactivated;
-    }
-
-    public long getId() {
-      return id;
-    }
-
-    public boolean isReactivated() {
-      return reactivated;
-    }
+    return userDto;
   }
 
-  private boolean reactivateUser(DbSession dbSession, UserDto existingUser, String login, NewUser newUser) {
-    if (existingUser.isActive()) {
-      throw new IllegalArgumentException(String.format("An active user with login '%s' already exists", login));
-    }
+  private void reactivateUser(DbSession dbSession, UserDto existingUser, String login, NewUser newUser) {
+    checkArgument(!existingUser.isActive(), "An active user with login '%s' already exists", login);
     UpdateUser updateUser = UpdateUser.create(login)
       .setName(newUser.name())
       .setEmail(newUser.email())
@@ -151,8 +125,6 @@ public class UserUpdater {
     existingUser.setLocal(true);
     updateUserDto(dbSession, updateUser, existingUser);
     updateUser(dbSession, existingUser);
-    addDefaultGroup(dbSession, existingUser);
-    return true;
   }
 
   public void update(UpdateUser updateUser) {
index de8bc866750eaba4b402248b65fff22cf0562454..236fcc26f853f3f0993dbbb9b3cf934d7778d786 100644 (file)
  */
 package org.sonar.server.user.ws;
 
-import com.google.common.collect.ImmutableSet;
 import java.util.Collections;
 import java.util.List;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
-import org.sonar.api.utils.text.JsonWriter;
 import org.sonar.core.permission.GlobalPermissions;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
 import org.sonar.db.user.UserDto;
 import org.sonar.server.user.NewUser;
 import org.sonar.server.user.UserSession;
 import org.sonar.server.user.UserUpdater;
+import org.sonarqube.ws.WsUsers.CreateWsResponse;
 import org.sonarqube.ws.client.user.CreateRequest;
 
-import static java.lang.String.format;
+import static com.google.common.base.Strings.emptyToNull;
+import static org.sonar.core.util.Protobuf.setNullable;
+import static org.sonar.server.ws.WsUtils.writeProtobuf;
+import static org.sonarqube.ws.client.user.UsersWsParameters.ACTION_CREATE;
 import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_EMAIL;
 import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_LOGIN;
 import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_NAME;
@@ -46,23 +46,21 @@ import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_SCM_ACCOUNTS_
 
 public class CreateAction implements UsersWsAction {
 
-  private final DbClient dbClient;
   private final UserUpdater userUpdater;
   private final UserSession userSession;
-  private final UserJsonWriter userWriter;
 
-  public CreateAction(DbClient dbClient, UserUpdater userUpdater, UserSession userSession, UserJsonWriter userWriter) {
-    this.dbClient = dbClient;
+  public CreateAction(UserUpdater userUpdater, UserSession userSession) {
     this.userUpdater = userUpdater;
     this.userSession = userSession;
-    this.userWriter = userWriter;
   }
 
   @Override
   public void define(WebService.NewController controller) {
-    WebService.NewAction action = controller.createAction("create")
-      .setDescription("Create a user. If a deactivated user account exists with the given login, it will be reactivated. " +
-        "Requires Administer System permission")
+    WebService.NewAction action = controller.createAction(ACTION_CREATE)
+      .setDescription("Create a user.<br/>" +
+        "If a deactivated user account exists with the given login, it will be reactivated.<br/>" +
+        "Requires Administer System permission<br/>" +
+        "Since 6.3, the 'infos' message is no more returned when a user is reactivated")
       .setSince("3.7")
       .setPost(true)
       .setHandler(this);
@@ -100,51 +98,29 @@ public class CreateAction implements UsersWsAction {
   @Override
   public void handle(Request request, Response response) throws Exception {
     userSession.checkLoggedIn().checkPermission(GlobalPermissions.SYSTEM_ADMIN);
-    doHandle(toWsRequest(request), response);
+    writeProtobuf(doHandle(toWsRequest(request)), request, response);
   }
 
-  private void doHandle(CreateRequest request, Response response) {
+  private CreateWsResponse doHandle(CreateRequest request) {
     NewUser newUser = NewUser.create()
       .setLogin(request.getLogin())
       .setName(request.getName())
       .setEmail(request.getEmail())
       .setScmAccounts(request.getScmAccounts())
       .setPassword(request.getPassword());
-    boolean isUserReactivated = userUpdater.create(newUser);
-    writeResponse(response, request.getLogin(), isUserReactivated);
+    UserDto userDto = userUpdater.create(newUser);
+    return buildResponse(userDto);
   }
 
-  private void writeResponse(Response response, String login, boolean isUserReactivated) {
-    UserDto user = loadUser(login);
-    JsonWriter json = response.newJsonWriter().beginObject();
-    writeUser(json, user);
-    if (isUserReactivated) {
-      writeReactivationMessage(json, login);
-    }
-    json.endObject().close();
-  }
-
-  private void writeUser(JsonWriter json, UserDto user) {
-    json.name("user");
-    userWriter.write(json, user, ImmutableSet.of(), UserJsonWriter.FIELDS);
-  }
-
-  private static void writeReactivationMessage(JsonWriter json, String login) {
-    json.name("infos").beginArray();
-    json.beginObject();
-    String text = format("The user '%s' has been reactivated", login);
-    json.prop("msg", text);
-    json.endObject();
-    json.endArray();
-  }
-
-  private UserDto loadUser(String login) {
-    DbSession dbSession = dbClient.openSession(false);
-    try {
-      return dbClient.userDao().selectOrFailByLogin(dbSession, login);
-    } finally {
-      dbClient.closeSession(dbSession);
-    }
+  private static CreateWsResponse buildResponse(UserDto userDto) {
+    CreateWsResponse.User.Builder userBuilder = CreateWsResponse.User.newBuilder()
+      .setLogin(userDto.getLogin())
+      .setName(userDto.getName())
+      .setActive(userDto.isActive())
+      .setLocal(userDto.isLocal())
+      .addAllScmAccounts(userDto.getScmAccountsAsList());
+    setNullable(emptyToNull(userDto.getEmail()), userBuilder::setEmail);
+    return CreateWsResponse.newBuilder().setUser(userBuilder).build();
   }
 
   private static CreateRequest toWsRequest(Request request) {
index d1dc3ca5e3be9288904677d725482bfda642d377..cd51d20523381f25adeda4cab51c24bb9959dba6 100644 (file)
@@ -92,14 +92,13 @@ public class UserUpdaterTest {
   public void create_user() {
     createDefaultGroup();
 
-    boolean result = underTest.create(NewUser.create()
+    UserDto dto = underTest.create(NewUser.create()
       .setLogin("user")
       .setName("User")
       .setEmail("user@mail.com")
       .setPassword("PASSWORD")
       .setScmAccounts(ImmutableList.of("u1", "u_1", "User 1")));
 
-    UserDto dto = dbClient.userDao().selectByLogin(session, "user");
     assertThat(dto.getId()).isNotNull();
     assertThat(dto.getLogin()).isEqualTo("user");
     assertThat(dto.getName()).isEqualTo("User");
@@ -112,8 +111,8 @@ public class UserUpdaterTest {
     assertThat(dto.getCryptedPassword()).isNotNull();
     assertThat(dto.getCreatedAt()).isEqualTo(1418215735482L);
     assertThat(dto.getUpdatedAt()).isEqualTo(1418215735482L);
-    assertThat(result).isFalse();
 
+    assertThat(dbClient.userDao().selectByLogin(session, "user").getId()).isEqualTo(dto.getId());
     List<SearchHit> indexUsers = es.getDocuments(UserIndexDefinition.INDEX, UserIndexDefinition.TYPE_USER);
     assertThat(indexUsers).hasSize(1);
     assertThat(indexUsers.get(0).getSource())
@@ -138,22 +137,6 @@ public class UserUpdaterTest {
     assertThat(dto.isLocal()).isTrue();
   }
 
-  @Test
-  public void create_user_with_authority() {
-    createDefaultGroup();
-
-    underTest.create(NewUser.create()
-      .setLogin("ABCD")
-      .setName("User")
-      .setPassword("password")
-      .setExternalIdentity(new ExternalIdentity("github", "user")));
-
-    UserDto dto = dbClient.userDao().selectByLogin(session, "ABCD");
-    assertThat(dto.getExternalIdentity()).isEqualTo("user");
-    assertThat(dto.getExternalIdentityProvider()).isEqualTo("github");
-    assertThat(dto.isLocal()).isFalse();
-  }
-
   @Test
   public void create_user_with_minimum_fields() {
     when(system2.now()).thenReturn(1418215735482L);
@@ -446,14 +429,13 @@ public class UserUpdaterTest {
       .setUpdatedAt(PAST));
     createDefaultGroup();
 
-    boolean result = underTest.create(NewUser.create()
+    UserDto dto = underTest.create(NewUser.create()
       .setLogin(DEFAULT_LOGIN)
       .setName("Marius2")
       .setEmail("marius2@mail.com")
       .setPassword("password2"));
     session.commit();
 
-    UserDto dto = dbClient.userDao().selectByLogin(session, DEFAULT_LOGIN);
     assertThat(dto.isActive()).isTrue();
     assertThat(dto.getName()).isEqualTo("Marius2");
     assertThat(dto.getEmail()).isEqualTo("marius2@mail.com");
@@ -465,7 +447,7 @@ public class UserUpdaterTest {
     assertThat(dto.getCreatedAt()).isEqualTo(PAST);
     assertThat(dto.getUpdatedAt()).isEqualTo(NOW);
 
-    assertThat(result).isTrue();
+    assertThat(dbClient.userDao().selectByLogin(session, DEFAULT_LOGIN).isActive()).isTrue();
   }
 
   @Test
@@ -474,13 +456,12 @@ public class UserUpdaterTest {
     when(system2.now()).thenReturn(1418215735486L);
     createDefaultGroup();
 
-    boolean result = underTest.create(NewUser.create()
+    UserDto dto = underTest.create(NewUser.create()
       .setLogin(DEFAULT_LOGIN)
       .setName("Marius2")
       .setEmail("marius2@mail.com"));
     session.commit();
 
-    UserDto dto = dbClient.userDao().selectByLogin(session, DEFAULT_LOGIN);
     assertThat(dto.isActive()).isTrue();
     assertThat(dto.getName()).isEqualTo("Marius2");
     assertThat(dto.getEmail()).isEqualTo("marius2@mail.com");
@@ -490,8 +471,6 @@ public class UserUpdaterTest {
     assertThat(dto.getCryptedPassword()).isNull();
     assertThat(dto.getCreatedAt()).isEqualTo(1418215735482L);
     assertThat(dto.getUpdatedAt()).isEqualTo(1418215735486L);
-
-    assertThat(result).isTrue();
   }
 
   @Test
index 983b62771b25c02bbf2ac63b691222597c8277da..ffe4849f0df453b7f6a1640ff728d6e3279b7171 100644 (file)
@@ -19,6 +19,8 @@
  */
 package org.sonar.server.user.ws;
 
+import com.google.common.base.Throwables;
+import java.io.IOException;
 import java.util.Optional;
 import org.junit.Before;
 import org.junit.Rule;
@@ -26,7 +28,6 @@ import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.sonar.api.config.MapSettings;
 import org.sonar.api.config.Settings;
-import org.sonar.api.i18n.I18n;
 import org.sonar.api.utils.System2;
 import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
 import org.sonar.core.permission.GlobalPermissions;
@@ -37,7 +38,6 @@ import org.sonar.db.user.UserDto;
 import org.sonar.server.es.EsTester;
 import org.sonar.server.exceptions.ForbiddenException;
 import org.sonar.server.exceptions.ServerException;
-import org.sonar.server.organization.DefaultOrganizationProvider;
 import org.sonar.server.organization.TestDefaultOrganizationProvider;
 import org.sonar.server.tester.UserSessionRule;
 import org.sonar.server.user.NewUserNotifier;
@@ -46,10 +46,17 @@ import org.sonar.server.user.index.UserDoc;
 import org.sonar.server.user.index.UserIndex;
 import org.sonar.server.user.index.UserIndexDefinition;
 import org.sonar.server.user.index.UserIndexer;
-import org.sonar.server.ws.WsTester;
-
+import org.sonar.server.ws.TestRequest;
+import org.sonar.server.ws.WsActionTester;
+import org.sonarqube.ws.MediaTypes;
+import org.sonarqube.ws.WsUsers.CreateWsResponse;
+import org.sonarqube.ws.WsUsers.CreateWsResponse.User;
+import org.sonarqube.ws.client.user.CreateRequest;
+
+import static java.util.Collections.singletonList;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
+import static org.sonar.core.util.Protobuf.setNullable;
 import static org.sonar.db.user.UserTesting.newUserDto;
 
 public class CreateActionTest {
@@ -67,35 +74,33 @@ public class CreateActionTest {
   @Rule
   public ExpectedException expectedException = ExpectedException.none();
 
-  private WsTester tester;
-  private UserIndex index;
-  private UserIndexer userIndexer;
-  private I18n i18n = mock(I18n.class);
+  private UserIndex index = new UserIndex(esTester.client());
+  private UserIndexer userIndexer = new UserIndexer(system2, db.getDbClient(), esTester.client());
   private GroupDto defaultGroupInDefaultOrg;
 
+  private WsActionTester tester = new WsActionTester(
+    new CreateAction(new UserUpdater(mock(NewUserNotifier.class), settings, db.getDbClient(), userIndexer, system2, TestDefaultOrganizationProvider.from(db)), userSessionRule));
+
   @Before
   public void setUp() {
     defaultGroupInDefaultOrg = db.users().insertGroup(db.getDefaultOrganization(), DEFAULT_GROUP_NAME);
-    userIndexer = new UserIndexer(system2, db.getDbClient(), esTester.client());
-    index = new UserIndex(esTester.client());
-    DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db);
-    tester = new WsTester(new UsersWs(
-      new CreateAction(db.getDbClient(),
-        new UserUpdater(mock(NewUserNotifier.class), settings, db.getDbClient(), userIndexer, system2, defaultOrganizationProvider),
-        userSessionRule, new UserJsonWriter(userSessionRule))));
   }
 
   @Test
   public void create_user() throws Exception {
     authenticateAsAdmin();
 
-    tester.newPostRequest("api/users", "create")
-      .setParam("login", "john")
-      .setParam("name", "John")
-      .setParam("email", "john@email.com")
-      .setParam("scmAccount", "jn")
-      .setParam("password", "1234").execute()
-      .assertJson(getClass(), "create_user.json");
+    CreateWsResponse response = call(CreateRequest.builder()
+      .setLogin("john")
+      .setName("John")
+      .setEmail("john@email.com")
+      .setScmAccounts(singletonList("jn"))
+      .setPassword("1234")
+      .build());
+
+    assertThat(response.getUser())
+      .extracting(User::getLogin, User::getName, User::getEmail, User::getScmAccountsList, User::getLocal)
+      .containsOnly("john", "John", "john@email.com", singletonList("jn"), true);
 
     UserDoc user = index.getNullableByLogin("john");
     assertThat(user.login()).isEqualTo("john");
@@ -115,47 +120,43 @@ public class CreateActionTest {
   public void create_user_with_comma_in_scm_account() throws Exception {
     authenticateAsAdmin();
 
-    tester.newPostRequest("api/users", "create")
-      .setParam("login", "john")
-      .setParam("name", "John")
-      .setParam("email", "john@email.com")
-      .setParam("scmAccount", "j,n")
-      .setParam("password", "1234").execute();
+    CreateWsResponse response = call(CreateRequest.builder()
+      .setLogin("john")
+      .setName("John")
+      .setEmail("john@email.com")
+      .setScmAccounts(singletonList("j,n"))
+      .setPassword("1234")
+      .build());
 
-    UserDoc user = index.getNullableByLogin("john");
-    assertThat(user.scmAccounts()).containsOnly("j,n");
+    assertThat(response.getUser().getScmAccountsList()).containsOnly("j,n");
   }
 
   @Test
   public void create_user_with_deprecated_scmAccounts_parameter() throws Exception {
     authenticateAsAdmin();
 
-    tester.newPostRequest("api/users", "create")
+    tester.newRequest()
       .setParam("login", "john")
       .setParam("name", "John")
-      .setParam("email", "john@email.com")
+      .setParam("password", "1234")
       .setParam("scmAccounts", "jn")
-      .setParam("password", "1234").execute()
-      .assertJson(getClass(), "create_user.json");
+      .execute();
 
-    UserDoc user = index.getNullableByLogin("john");
-    assertThat(user.scmAccounts()).containsOnly("jn");
+    assertThat(db.users().selectUserByLogin("john").get().getScmAccountsAsList()).containsOnly("jn");
   }
 
   @Test
   public void create_user_with_deprecated_scm_accounts_parameter() throws Exception {
     authenticateAsAdmin();
 
-    tester.newPostRequest("api/users", "create")
+    tester.newRequest()
       .setParam("login", "john")
       .setParam("name", "John")
-      .setParam("email", "john@email.com")
+      .setParam("password", "1234")
       .setParam("scm_accounts", "jn")
-      .setParam("password", "1234").execute()
-      .assertJson(getClass(), "create_user.json");
+      .execute();
 
-    UserDoc user = index.getNullableByLogin("john");
-    assertThat(user.scmAccounts()).containsOnly("jn");
+    assertThat(db.users().selectUserByLogin("john").get().getScmAccountsAsList()).containsOnly("jn");
   }
 
   @Test
@@ -167,15 +168,15 @@ public class CreateActionTest {
     db.commit();
     userIndexer.index();
 
-    tester.newPostRequest("api/users", "create")
-      .setParam("login", "john")
-      .setParam("name", "John")
-      .setParam("email", "john@email.com")
-      .setParam("scm_accounts", "jn")
-      .setParam("password", "1234").execute()
-      .assertJson(getClass(), "reactivate_user.json");
+    call(CreateRequest.builder()
+      .setLogin("john")
+      .setName("John")
+      .setEmail("john@email.com")
+      .setScmAccounts(singletonList("jn"))
+      .setPassword("1234")
+      .build());
 
-    assertThat(index.getNullableByLogin("john").active()).isTrue();
+    assertThat(db.users().selectUserByLogin("john").get().isActive()).isTrue();
   }
 
   @Test
@@ -232,29 +233,40 @@ public class CreateActionTest {
     settings.setProperty("sonar.defaultGroup", adminGroup.getName());
   }
 
-  @Test(expected = ForbiddenException.class)
+  @Test
   public void fail_on_missing_permission() throws Exception {
     userSessionRule.logIn("not_admin");
 
-    tester.newPostRequest("api/users", "create")
-      .setParam("login", "john")
-      .setParam("name", "John")
-      .setParam("email", "john@email.com")
-      .setParam("scm_accounts", "jn")
-      .setParam("password", "1234").execute();
+    expectedException.expect(ForbiddenException.class);
+    executeRequest("john");
+  }
+
+  private CreateWsResponse executeRequest(String login) throws Exception {
+    return call(CreateRequest.builder()
+      .setLogin(login)
+      .setName("name of " + login)
+      .setEmail(login + "@email.com")
+      .setScmAccounts(singletonList(login.substring(0, 2)))
+      .setPassword("pwd_" + login)
+      .build());
   }
 
   private void authenticateAsAdmin() {
     userSessionRule.logIn("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
   }
 
-  private void executeRequest(String login) throws Exception {
-    tester.newPostRequest("api/users", "create")
-      .setParam("login", login)
-      .setParam("name", "name of " + login)
-      .setParam("email", login + "@email.com")
-      .setParam("scm_accounts", login.substring(0, 2))
-      .setParam("password", "pwd_" + login)
-      .execute();
+  private CreateWsResponse call(CreateRequest createRequest) {
+    TestRequest request = tester.newRequest()
+      .setMediaType(MediaTypes.PROTOBUF);
+    setNullable(createRequest.getLogin(), e -> request.setParam("login", e));
+    setNullable(createRequest.getName(), e -> request.setParam("name", e));
+    setNullable(createRequest.getEmail(), e -> request.setParam("email", e));
+    setNullable(createRequest.getPassword(), e -> request.setParam("password", e));
+    setNullable(createRequest.getScmAccounts(), e -> request.setMultiParam("scmAccount", e));
+    try {
+      return CreateWsResponse.parseFrom(request.execute().getInputStream());
+    } catch (IOException e) {
+      throw Throwables.propagate(e);
+    }
   }
 }
index fff1bbdbc4529a911ea68502ed074182b10ae091..5e6c4991f146d66cd85454b834c40a69430bcb06 100644 (file)
@@ -41,7 +41,7 @@ public class UsersWsTest {
   @Before
   public void setUp() {
     WsTester tester = new WsTester(new UsersWs(
-      new CreateAction(mock(DbClient.class), mock(UserUpdater.class), userSessionRule, mock(UserJsonWriter.class)),
+      new CreateAction(mock(UserUpdater.class), userSessionRule),
       new UpdateAction(mock(UserUpdater.class), userSessionRule, mock(UserJsonWriter.class), mock(DbClient.class)),
       new CurrentAction(userSessionRule, mock(org.sonar.db.DbClient.class)),
       new ChangePasswordAction(mock(UserUpdater.class), userSessionRule),
index 8d4ef2fac3f8ecec09ddba98b4fdb76e9a24584d..eb3f3437200962bd1119cf4a43bd524b2aad6be0 100644 (file)
@@ -79,7 +79,7 @@ public class TestRequest extends ValidatingRequest {
 
   @Override
   public boolean hasParam(String key) {
-    return params.containsKey(key);
+    return params.containsKey(key) || multiParams.containsKey(key);
   }
 
   @Override
index f8ab3a2abf1200844714541950e98cdb2b4e8eb0..f17c7f759ba93842711bca797d9c7d78b16a289a 100644 (file)
@@ -34,6 +34,7 @@ import org.sonarqube.ws.client.root.RootsService;
 import org.sonarqube.ws.client.rule.RulesService;
 import org.sonarqube.ws.client.setting.SettingsService;
 import org.sonarqube.ws.client.system.SystemService;
+import org.sonarqube.ws.client.user.UsersService;
 import org.sonarqube.ws.client.usertoken.UserTokensService;
 import org.sonarqube.ws.client.webhook.WebhooksService;
 
@@ -52,6 +53,7 @@ class DefaultWsClient implements WsClient {
   private final FavoritesService favoritesService;
   private final QualityProfilesService qualityProfilesService;
   private final IssuesService issuesService;
+  private final UsersService usersService;
   private final UserTokensService userTokensService;
   private final QualityGatesService qualityGatesService;
   private final MeasuresService measuresService;
@@ -72,6 +74,7 @@ class DefaultWsClient implements WsClient {
     this.favoritesService = new FavoritesService(wsConnector);
     this.qualityProfilesService = new QualityProfilesService(wsConnector);
     this.issuesService = new IssuesService(wsConnector);
+    this.usersService = new UsersService(wsConnector);
     this.userTokensService = new UserTokensService(wsConnector);
     this.qualityGatesService = new QualityGatesService(wsConnector);
     this.measuresService = new MeasuresService(wsConnector);
@@ -120,6 +123,11 @@ class DefaultWsClient implements WsClient {
     return issuesService;
   }
 
+  @Override
+  public UsersService users() {
+    return usersService;
+  }
+
   @Override
   public UserTokensService userTokens() {
     return userTokensService;
index a14da6696e90eb425365f775812e45532d0371cb..8e81e1d3dc7a82e435221e7d2b38c88a8a8ae760 100644 (file)
@@ -34,6 +34,7 @@ import org.sonarqube.ws.client.root.RootsService;
 import org.sonarqube.ws.client.rule.RulesService;
 import org.sonarqube.ws.client.setting.SettingsService;
 import org.sonarqube.ws.client.system.SystemService;
+import org.sonarqube.ws.client.user.UsersService;
 import org.sonarqube.ws.client.usertoken.UserTokensService;
 import org.sonarqube.ws.client.webhook.WebhooksService;
 
@@ -68,6 +69,8 @@ public interface WsClient {
 
   QualityProfilesService qualityProfiles();
 
+  UsersService users();
+
   UserTokensService userTokens();
 
   QualityGatesService qualityGates();
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/user/UserService.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/user/UserService.java
deleted file mode 100644 (file)
index df9c73f..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.user;
-
-import org.sonarqube.ws.client.BaseService;
-import org.sonarqube.ws.client.PostRequest;
-import org.sonarqube.ws.client.WsConnector;
-
-import static org.sonarqube.ws.client.user.UsersWsParameters.ACTION_CREATE;
-import static org.sonarqube.ws.client.user.UsersWsParameters.ACTION_UPDATE;
-import static org.sonarqube.ws.client.user.UsersWsParameters.CONTROLLER_USERS;
-import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_EMAIL;
-import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_LOGIN;
-import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_NAME;
-import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_PASSWORD;
-import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_SCM_ACCOUNT;
-
-public class UserService extends BaseService {
-
-  public UserService(WsConnector wsConnector) {
-    super(wsConnector, CONTROLLER_USERS);
-  }
-
-  public void create(CreateRequest request) {
-    call(new PostRequest(path(ACTION_CREATE))
-      .setParam(PARAM_LOGIN, request.getLogin())
-      .setParam(PARAM_PASSWORD, request.getPassword())
-      .setParam(PARAM_NAME, request.getName())
-      .setParam(PARAM_EMAIL, request.getEmail())
-      .setParam(PARAM_SCM_ACCOUNT, request.getScmAccounts()));
-  }
-
-  public void update(UpdateRequest request) {
-    call(new PostRequest(path(ACTION_UPDATE))
-      .setParam(PARAM_LOGIN, request.getLogin())
-      .setParam(PARAM_NAME, request.getName())
-      .setParam(PARAM_EMAIL, request.getEmail())
-      .setParam(PARAM_SCM_ACCOUNT, request.getScmAccounts()));
-  }
-
-}
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/user/UsersService.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/user/UsersService.java
new file mode 100644 (file)
index 0000000..3393adb
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.user;
+
+import org.sonarqube.ws.WsUsers.CreateWsResponse;
+import org.sonarqube.ws.client.BaseService;
+import org.sonarqube.ws.client.PostRequest;
+import org.sonarqube.ws.client.WsConnector;
+
+import static org.sonarqube.ws.client.user.UsersWsParameters.ACTION_CREATE;
+import static org.sonarqube.ws.client.user.UsersWsParameters.ACTION_UPDATE;
+import static org.sonarqube.ws.client.user.UsersWsParameters.CONTROLLER_USERS;
+import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_EMAIL;
+import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_LOGIN;
+import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_NAME;
+import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_PASSWORD;
+import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_SCM_ACCOUNT;
+
+public class UsersService extends BaseService {
+
+  public UsersService(WsConnector wsConnector) {
+    super(wsConnector, CONTROLLER_USERS);
+  }
+
+  public CreateWsResponse create(CreateRequest request) {
+    return call(new PostRequest(path(ACTION_CREATE))
+      .setParam(PARAM_LOGIN, request.getLogin())
+      .setParam(PARAM_PASSWORD, request.getPassword())
+      .setParam(PARAM_NAME, request.getName())
+      .setParam(PARAM_EMAIL, request.getEmail())
+      .setParam(PARAM_SCM_ACCOUNT, request.getScmAccounts()),
+      CreateWsResponse.parser());
+  }
+
+  public void update(UpdateRequest request) {
+    call(new PostRequest(path(ACTION_UPDATE))
+      .setParam(PARAM_LOGIN, request.getLogin())
+      .setParam(PARAM_NAME, request.getName())
+      .setParam(PARAM_EMAIL, request.getEmail())
+      .setParam(PARAM_SCM_ACCOUNT, request.getScmAccounts()));
+  }
+
+}
index 46d7ac92660bb8be6545bcb7b216a9ed54844283..0587640916c2f6ba701f5a7fa2c74c5679f4e80a 100644 (file)
@@ -35,3 +35,16 @@ message IdentityProvider {
   optional string iconPath = 3;
   optional string backgroundColor = 4;
 }
+
+message CreateWsResponse {
+  optional User user = 1;
+
+  message User {
+    optional string login = 1;
+    optional string name = 2;
+    optional string email = 3;
+    repeated string scmAccounts = 4;
+    optional bool active = 5;
+    optional bool local = 6;
+  }
+}
diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/user/UserServiceTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/user/UserServiceTest.java
deleted file mode 100644 (file)
index 675894b..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.user;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonarqube.ws.client.ServiceTester;
-import org.sonarqube.ws.client.WsConnector;
-
-import static java.util.Arrays.asList;
-import static org.mockito.Mockito.mock;
-import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_EMAIL;
-import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_LOGIN;
-import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_NAME;
-import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_PASSWORD;
-import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_SCM_ACCOUNT;
-
-public class UserServiceTest {
-
-  @Rule
-  public ServiceTester<UserService> serviceTester = new ServiceTester<>(new UserService(mock(WsConnector.class)));
-
-  private UserService underTest = serviceTester.getInstanceUnderTest();
-
-  @Test
-  public void create() {
-    underTest.create(CreateRequest.builder()
-      .setLogin("john")
-      .setPassword("123456")
-      .setName("John")
-      .setEmail("john@doo.com")
-      .setScmAccounts(asList("jo", "hn"))
-      .build());
-
-    serviceTester.assertThat(serviceTester.getPostRequest())
-      .hasParam(PARAM_LOGIN, "john")
-      .hasParam(PARAM_PASSWORD, "123456")
-      .hasParam(PARAM_NAME, "John")
-      .hasParam(PARAM_EMAIL, "john@doo.com")
-      .hasParam(PARAM_SCM_ACCOUNT, asList("jo", "hn"))
-      .andNoOtherParam();
-  }
-
-  @Test
-  public void update() {
-    underTest.update(UpdateRequest.builder()
-      .setLogin("john")
-      .setName("John")
-      .setEmail("john@doo.com")
-      .setScmAccounts(asList("jo", "hn"))
-      .build());
-
-    serviceTester.assertThat(serviceTester.getPostRequest())
-      .hasParam(PARAM_LOGIN, "john")
-      .hasParam(PARAM_NAME, "John")
-      .hasParam(PARAM_EMAIL, "john@doo.com")
-      .hasParam(PARAM_SCM_ACCOUNT, asList("jo", "hn"))
-      .andNoOtherParam();
-  }
-
-}
diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/user/UsersServiceTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/user/UsersServiceTest.java
new file mode 100644 (file)
index 0000000..b652dc3
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.user;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonarqube.ws.WsUsers.CreateWsResponse;
+import org.sonarqube.ws.client.ServiceTester;
+import org.sonarqube.ws.client.WsConnector;
+
+import static java.util.Arrays.asList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_EMAIL;
+import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_LOGIN;
+import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_NAME;
+import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_PASSWORD;
+import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_SCM_ACCOUNT;
+
+public class UsersServiceTest {
+
+  @Rule
+  public ServiceTester<UsersService> serviceTester = new ServiceTester<>(new UsersService(mock(WsConnector.class)));
+
+  private UsersService underTest = serviceTester.getInstanceUnderTest();
+
+  @Test
+  public void create() {
+    underTest.create(CreateRequest.builder()
+      .setLogin("john")
+      .setPassword("123456")
+      .setName("John")
+      .setEmail("john@doo.com")
+      .setScmAccounts(asList("jo", "hn"))
+      .build());
+
+    assertThat(serviceTester.getPostParser()).isSameAs(CreateWsResponse.parser());
+    serviceTester.assertThat(serviceTester.getPostRequest())
+      .hasParam(PARAM_LOGIN, "john")
+      .hasParam(PARAM_PASSWORD, "123456")
+      .hasParam(PARAM_NAME, "John")
+      .hasParam(PARAM_EMAIL, "john@doo.com")
+      .hasParam(PARAM_SCM_ACCOUNT, asList("jo", "hn"))
+      .andNoOtherParam();
+  }
+
+  @Test
+  public void update() {
+    underTest.update(UpdateRequest.builder()
+      .setLogin("john")
+      .setName("John")
+      .setEmail("john@doo.com")
+      .setScmAccounts(asList("jo", "hn"))
+      .build());
+
+    serviceTester.assertThat(serviceTester.getPostRequest())
+      .hasParam(PARAM_LOGIN, "john")
+      .hasParam(PARAM_NAME, "John")
+      .hasParam(PARAM_EMAIL, "john@doo.com")
+      .hasParam(PARAM_SCM_ACCOUNT, asList("jo", "hn"))
+      .andNoOtherParam();
+  }
+
+}