From: Julien Lancelot Date: Thu, 15 Sep 2016 16:37:18 +0000 (+0200) Subject: SONAR-7907 It should be possible to add SCM account that contains comma X-Git-Tag: 6.1-RC1~23 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=65d3b1d057c3c1265b23b75911c51cfa863ad817;p=sonarqube.git SONAR-7907 It should be possible to add SCM account that contains comma --- diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/UserUpdater.java b/server/sonar-server/src/main/java/org/sonar/server/user/UserUpdater.java index b5a7cfb7229..5c52cef1c23 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/user/UserUpdater.java +++ b/server/sonar-server/src/main/java/org/sonar/server/user/UserUpdater.java @@ -21,10 +21,10 @@ package org.sonar.server.user; import com.google.common.base.Joiner; import com.google.common.base.Predicate; +import com.google.common.base.Strings; import com.google.common.collect.Iterables; import java.net.HttpURLConnection; import java.security.SecureRandom; -import java.util.Arrays; import java.util.List; import java.util.Random; import javax.annotation.CheckForNull; @@ -35,6 +35,7 @@ import org.sonar.api.config.Settings; import org.sonar.api.platform.NewUserHandler; import org.sonar.api.server.ServerSide; import org.sonar.api.utils.System2; +import org.sonar.core.util.stream.Collectors; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.user.GroupDto; @@ -353,9 +354,9 @@ public class UserUpdater { @CheckForNull private static List sanitizeScmAccounts(@Nullable List scmAccounts) { if (scmAccounts != null) { - scmAccounts.removeAll(Arrays.asList(null, "")); + return scmAccounts.stream().filter(s -> !Strings.isNullOrEmpty(s)).collect(Collectors.toList()); } - return scmAccounts; + return null; } private void saveUser(DbSession dbSession, UserDto userDto) { diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/ws/CreateAction.java b/server/sonar-server/src/main/java/org/sonar/server/user/ws/CreateAction.java index 78a47459faf..caa1ec13598 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/user/ws/CreateAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/user/ws/CreateAction.java @@ -20,6 +20,8 @@ package org.sonar.server.user.ws; import com.google.common.collect.ImmutableSet; +import java.util.Collections; +import java.util.List; import org.sonar.api.i18n.I18n; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; @@ -32,15 +34,17 @@ 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.client.user.CreateRequest; -public class CreateAction implements UsersWsAction { +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; +import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_SCM_ACCOUNTS; +import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_SCM_ACCOUNTS_DEPRECATED; - private static final String PARAM_LOGIN = "login"; - private static final String PARAM_PASSWORD = "password"; - private static final String PARAM_NAME = "name"; - private static final String PARAM_EMAIL = "email"; - private static final String PARAM_SCM_ACCOUNTS = "scmAccounts"; - private static final String PARAM_SCM_ACCOUNTS_DEPRECATED = "scm_accounts"; +public class CreateAction implements UsersWsAction { private final DbClient dbClient; private final UserUpdater userUpdater; @@ -85,26 +89,31 @@ public class CreateAction implements UsersWsAction { .setExampleValue("myname@email.com"); action.createParam(PARAM_SCM_ACCOUNTS) - .setDescription("SCM accounts. This parameter has been added in 5.1") + .setDescription("This parameter is deprecated, please use '%s' instead", PARAM_SCM_ACCOUNT) .setDeprecatedKey(PARAM_SCM_ACCOUNTS_DEPRECATED) + .setDeprecatedSince("6.1") .setExampleValue("myscmaccount1,myscmaccount2"); + + action.createParam(PARAM_SCM_ACCOUNT) + .setDescription("SCM accounts. To set several values, the parameter must be called once for each value.") + .setExampleValue("scmAccount=firstValue&scmAccount=secondValue&scmAccount=thirdValue"); } @Override public void handle(Request request, Response response) throws Exception { userSession.checkLoggedIn().checkPermission(GlobalPermissions.SYSTEM_ADMIN); + doHandle(toWsRequest(request), response); + } - String login = request.mandatoryParam(PARAM_LOGIN); - String password = request.mandatoryParam(PARAM_PASSWORD); + private void doHandle(CreateRequest request, Response response) { NewUser newUser = NewUser.create() - .setLogin(login) - .setName(request.mandatoryParam(PARAM_NAME)) - .setEmail(request.param(PARAM_EMAIL)) - .setScmAccounts(request.paramAsStrings(PARAM_SCM_ACCOUNTS)) - .setPassword(password); - + .setLogin(request.getLogin()) + .setName(request.getName()) + .setEmail(request.getEmail()) + .setScmAccounts(request.getScmAccounts()) + .setPassword(request.getPassword()); boolean isUserReactivated = userUpdater.create(newUser); - writeResponse(response, login, isUserReactivated); + writeResponse(response, request.getLogin(), isUserReactivated); } private void writeResponse(Response response, String login, boolean isUserReactivated) { @@ -119,7 +128,7 @@ public class CreateAction implements UsersWsAction { private void writeUser(JsonWriter json, UserDto user) { json.name("user"); - userWriter.write(json, user, ImmutableSet.of(), UserJsonWriter.FIELDS); + userWriter.write(json, user, ImmutableSet.of(), UserJsonWriter.FIELDS); } private void writeReactivationMessage(JsonWriter json, String login) { @@ -131,7 +140,7 @@ public class CreateAction implements UsersWsAction { json.endArray(); } - private UserDto loadUser(String login){ + private UserDto loadUser(String login) { DbSession dbSession = dbClient.openSession(false); try { return dbClient.userDao().selectOrFailByLogin(dbSession, login); @@ -139,4 +148,22 @@ public class CreateAction implements UsersWsAction { dbClient.closeSession(dbSession); } } + + private static CreateRequest toWsRequest(Request request) { + return CreateRequest.builder() + .setLogin(request.mandatoryParam(PARAM_LOGIN)) + .setPassword(request.mandatoryParam(PARAM_PASSWORD)) + .setName(request.param(PARAM_NAME)) + .setEmail(request.param(PARAM_EMAIL)) + .setScmAccounts(getScmAccounts(request)) + .build(); + } + + private static List getScmAccounts(Request request) { + if (request.hasParam(PARAM_SCM_ACCOUNT)) { + return request.multiParam(PARAM_SCM_ACCOUNT); + } + List oldScmAccounts = request.paramAsStrings(PARAM_SCM_ACCOUNTS); + return oldScmAccounts != null ? oldScmAccounts : Collections.emptyList(); + } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/ws/UpdateAction.java b/server/sonar-server/src/main/java/org/sonar/server/user/ws/UpdateAction.java index 9da94fae484..362b5fe19a2 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/user/ws/UpdateAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/user/ws/UpdateAction.java @@ -20,6 +20,8 @@ package org.sonar.server.user.ws; import com.google.common.collect.Sets; +import java.util.ArrayList; +import java.util.List; import java.util.Set; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; @@ -33,19 +35,21 @@ import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.user.UpdateUser; import org.sonar.server.user.UserSession; import org.sonar.server.user.UserUpdater; +import org.sonarqube.ws.client.user.UpdateRequest; import static com.google.common.base.Strings.emptyToNull; import static java.lang.String.format; import static java.util.Collections.singletonList; +import static org.sonarqube.ws.client.user.UsersWsParameters.ACTION_UPDATE; +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_SCM_ACCOUNT; +import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_SCM_ACCOUNTS; +import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_SCM_ACCOUNTS_DEPRECATED; public class UpdateAction implements UsersWsAction { - private static final String PARAM_LOGIN = "login"; - private static final String PARAM_NAME = "name"; - private static final String PARAM_EMAIL = "email"; - private static final String PARAM_SCM_ACCOUNTS = "scmAccounts"; - private static final String PARAM_SCM_ACCOUNTS_DEPRECATED = "scm_accounts"; - private final UserUpdater userUpdater; private final UserSession userSession; private final UserJsonWriter userWriter; @@ -60,7 +64,7 @@ public class UpdateAction implements UsersWsAction { @Override public void define(WebService.NewController controller) { - WebService.NewAction action = controller.createAction("update") + WebService.NewAction action = controller.createAction(ACTION_UPDATE) .setDescription("Update a user. If a deactivated user account exists with the given login, it will be reactivated. " + "Requires Administer System permission. Since 5.2, a user's password can only be changed using the 'change_password' action.") .setSince("3.7") @@ -82,29 +86,37 @@ public class UpdateAction implements UsersWsAction { .setExampleValue("myname@email.com"); action.createParam(PARAM_SCM_ACCOUNTS) - .setDescription("SCM accounts. This parameter has been added in 5.1") + .setDescription("This parameter is deprecated, please use '%s' instead", PARAM_SCM_ACCOUNT) .setDeprecatedKey(PARAM_SCM_ACCOUNTS_DEPRECATED) + .setDeprecatedSince("6.1") .setExampleValue("myscmaccount1,myscmaccount2"); + + action.createParam(PARAM_SCM_ACCOUNT) + .setDescription("SCM accounts. To set several values, the parameter must be called once for each value.") + .setExampleValue("scmAccount=firstValue&scmAccount=secondValue&scmAccount=thirdValue"); } @Override public void handle(Request request, Response response) throws Exception { userSession.checkLoggedIn().checkPermission(GlobalPermissions.SYSTEM_ADMIN); + UpdateRequest updateRequest = toWsRequest(request); + doHandle(toWsRequest(request)); + writeResponse(response, updateRequest.getLogin()); + } - String login = request.mandatoryParam(PARAM_LOGIN); + private void doHandle(UpdateRequest request) { + String login = request.getLogin(); UpdateUser updateUser = UpdateUser.create(login); - if (request.hasParam(PARAM_NAME)) { - updateUser.setName(request.mandatoryParam(PARAM_NAME)); + if (request.getName() != null) { + updateUser.setName(request.getName()); } - if (request.hasParam(PARAM_EMAIL)) { - updateUser.setEmail(emptyToNull(request.param(PARAM_EMAIL))); + if (request.getEmail() != null) { + updateUser.setEmail(emptyToNull(request.getEmail())); } - if (request.hasParam(PARAM_SCM_ACCOUNTS) || request.hasParam(PARAM_SCM_ACCOUNTS_DEPRECATED)) { - updateUser.setScmAccounts(request.paramAsStrings(PARAM_SCM_ACCOUNTS)); + if (!request.getScmAccounts().isEmpty()) { + updateUser.setScmAccounts(request.getScmAccounts()); } - userUpdater.update(updateUser); - writeResponse(response, login); } private void writeResponse(Response response, String login) { @@ -128,4 +140,21 @@ public class UpdateAction implements UsersWsAction { dbClient.closeSession(dbSession); } } + + private static UpdateRequest toWsRequest(Request request) { + return UpdateRequest.builder() + .setLogin(request.mandatoryParam(PARAM_LOGIN)) + .setName(request.param(PARAM_NAME)) + .setEmail(request.param(PARAM_EMAIL)) + .setScmAccounts(getScmAccounts(request)) + .build(); + } + + private static List getScmAccounts(Request request) { + if (request.hasParam(PARAM_SCM_ACCOUNT)) { + return new ArrayList<>(request.multiParam(PARAM_SCM_ACCOUNT)); + } + List oldScmAccounts = request.paramAsStrings(PARAM_SCM_ACCOUNTS); + return oldScmAccounts != null ? oldScmAccounts : new ArrayList<>(); + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/user/UserUpdaterTest.java b/server/sonar-server/src/test/java/org/sonar/server/user/UserUpdaterTest.java index fbb906739e6..df4c1fcfb2c 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/user/UserUpdaterTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/user/UserUpdaterTest.java @@ -20,6 +20,7 @@ package org.sonar.server.user; import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; import java.util.List; import org.elasticsearch.search.SearchHit; import org.junit.Before; @@ -106,7 +107,7 @@ public class UserUpdaterTest { .setName("User") .setEmail("user@mail.com") .setPassword("PASSWORD") - .setScmAccounts(newArrayList("u1", "u_1", "User 1"))); + .setScmAccounts(ImmutableList.of("u1", "u_1", "User 1"))); UserDto dto = userDao.selectByLogin(session, "user"); assertThat(dto.getId()).isNotNull(); diff --git a/server/sonar-server/src/test/java/org/sonar/server/user/ws/CreateActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/user/ws/CreateActionTest.java index 9ef9707fe16..962ca17728f 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/user/ws/CreateActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/user/ws/CreateActionTest.java @@ -24,8 +24,8 @@ import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.sonar.api.config.Settings; import org.sonar.api.config.MapSettings; +import org.sonar.api.config.Settings; import org.sonar.api.i18n.I18n; import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.System2; @@ -112,7 +112,7 @@ public class CreateActionTest { .setParam("login", "john") .setParam("name", "John") .setParam("email", "john@email.com") - .setParam("scmAccounts", "jn") + .setParam("scmAccount", "jn") .setParam("password", "1234").execute() .assertJson(getClass(), "create_user.json"); @@ -124,7 +124,38 @@ public class CreateActionTest { } @Test - public void create_user_with_deprecated_scm_parameter() throws Exception { + public void create_user_with_coma_in_scm_account() throws Exception { + userSessionRule.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN); + + tester.newPostRequest("api/users", "create") + .setParam("login", "john") + .setParam("name", "John") + .setParam("email", "john@email.com") + .setParam("scmAccount", "j,n") + .setParam("password", "1234").execute(); + + UserDoc user = index.getNullableByLogin("john"); + assertThat(user.scmAccounts()).containsOnly("j,n"); + } + + @Test + public void create_user_with_deprecated_scmAccounts_parameter() throws Exception { + userSessionRule.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN); + + tester.newPostRequest("api/users", "create") + .setParam("login", "john") + .setParam("name", "John") + .setParam("email", "john@email.com") + .setParam("scmAccounts", "jn") + .setParam("password", "1234").execute() + .assertJson(getClass(), "create_user.json"); + + UserDoc user = index.getNullableByLogin("john"); + assertThat(user.scmAccounts()).containsOnly("jn"); + } + + @Test + public void create_user_with_deprecated_scm_accounts_parameter() throws Exception { userSessionRule.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN); tester.newPostRequest("api/users", "create") @@ -136,9 +167,6 @@ public class CreateActionTest { .assertJson(getClass(), "create_user.json"); UserDoc user = index.getNullableByLogin("john"); - assertThat(user.login()).isEqualTo("john"); - assertThat(user.name()).isEqualTo("John"); - assertThat(user.email()).isEqualTo("john@email.com"); assertThat(user.scmAccounts()).containsOnly("jn"); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/user/ws/DeactivateActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/user/ws/DeactivateActionTest.java index 925c2767fec..6b7650b5584 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/user/ws/DeactivateActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/user/ws/DeactivateActionTest.java @@ -22,8 +22,8 @@ package org.sonar.server.user.ws; import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.sonar.api.config.Settings; import org.sonar.api.config.MapSettings; +import org.sonar.api.config.Settings; import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.System2; import org.sonar.core.permission.GlobalPermissions; @@ -47,6 +47,7 @@ import org.sonar.server.user.index.UserIndexDefinition; import org.sonar.server.user.index.UserIndexer; import org.sonar.server.ws.WsTester; +import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.sonar.db.user.UserTokenTesting.newUserToken; @@ -136,7 +137,7 @@ public class DeactivateActionTest { .setEmail("john@email.com") .setLogin("john") .setName("John") - .setScmAccounts("jn")); + .setScmAccounts(singletonList("jn"))); dbClient.userTokenDao().insert(dbSession, newUserToken().setLogin("john")); dbSession.commit(); userIndexer.index(); diff --git a/server/sonar-server/src/test/java/org/sonar/server/user/ws/GroupsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/user/ws/GroupsActionTest.java index ec198c0f995..f70f4d8da63 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/user/ws/GroupsActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/user/ws/GroupsActionTest.java @@ -42,6 +42,8 @@ import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.WsTester; +import static java.util.Collections.singletonList; + public class GroupsActionTest { @Rule @@ -154,7 +156,7 @@ public class GroupsActionTest { .setEmail("john@email.com") .setLogin("john") .setName("John") - .setScmAccounts("jn")); + .setScmAccounts(singletonList("jn"))); } @Test diff --git a/server/sonar-server/src/test/java/org/sonar/server/user/ws/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/user/ws/SearchActionTest.java index 91cbb2d3064..8884751a7b8 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/user/ws/SearchActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/user/ws/SearchActionTest.java @@ -122,9 +122,7 @@ public class SearchActionTest { public void search_with_query() throws Exception { loginAsSimpleUser(); injectUsers(5); - UserDto user = userDb.insertUser( - newUserDto("user-%_%-login", "user-name", "user@mail.com") - .setScmAccounts("user1")); + UserDto user = userDb.insertUser(newUserDto("user-%_%-login", "user-name", "user@mail.com").setScmAccounts(singletonList("user1"))); esTester.putDocuments(UserIndexDefinition.INDEX, UserIndexDefinition.TYPE_USER, new UserDoc() .setActive(true) diff --git a/server/sonar-server/src/test/java/org/sonar/server/user/ws/UpdateActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/user/ws/UpdateActionTest.java index 95c527dd96f..2a329a49b74 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/user/ws/UpdateActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/user/ws/UpdateActionTest.java @@ -23,8 +23,8 @@ import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.sonar.api.config.Settings; import org.sonar.api.config.MapSettings; +import org.sonar.api.config.Settings; import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.System2; import org.sonar.core.permission.GlobalPermissions; @@ -147,19 +147,62 @@ public class UpdateActionTest { assertThat(userDto.getEmail()).isNull(); } + @Test + public void remove_scm_accounts() throws Exception { + createUser(); + + tester.newPostRequest("api/users", "update") + .setParam("login", "john") + .setParam("scmAccount", "") + .execute(); + + UserDto userDto = dbClient.userDao().selectByLogin(session, "john"); + assertThat(userDto.getScmAccounts()).isNull(); + } + @Test public void update_only_scm_accounts() throws Exception { createUser(); + tester.newPostRequest("api/users", "update") + .setParam("login", "john") + .setParam("scmAccount", "jon.snow") + .execute() + .assertJson(getClass(), "update_scm_accounts.json"); + + UserDto user = dbClient.userDao().selectByLogin(session, "john"); + assertThat(user.getScmAccountsAsList()).containsOnly("jon.snow"); + } + + @Test + public void update_scm_account_having_coma() throws Exception { + createUser(); + + tester.newPostRequest("api/users", "update") + .setParam("login", "john") + .setParam("scmAccount", "jon,snow") + .execute(); + + UserDto user = dbClient.userDao().selectByLogin(session, "john"); + assertThat(user.getScmAccountsAsList()).containsOnly("jon,snow"); + } + + @Test + public void update_only_scm_accounts_with_deprecated_scmAccounts_parameter() throws Exception { + createUser(); + tester.newPostRequest("api/users", "update") .setParam("login", "john") .setParam("scmAccounts", "jon.snow") .execute() .assertJson(getClass(), "update_scm_accounts.json"); + + UserDto user = dbClient.userDao().selectByLogin(session, "john"); + assertThat(user.getScmAccountsAsList()).containsOnly("jon.snow"); } @Test - public void update_only_scm_accounts_with_deprecated_parameter() throws Exception { + public void update_only_scm_accounts_with_deprecated_scm_accounts_parameter() throws Exception { createUser(); tester.newPostRequest("api/users", "update") @@ -167,6 +210,9 @@ public class UpdateActionTest { .setParam("scm_accounts", "jon.snow") .execute() .assertJson(getClass(), "update_scm_accounts.json"); + + UserDto user = dbClient.userDao().selectByLogin(session, "john"); + assertThat(user.getScmAccountsAsList()).containsOnly("jon.snow"); } @Test(expected = NotFoundException.class) diff --git a/server/sonar-server/src/test/java/org/sonar/server/user/ws/UsersWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/user/ws/UsersWsTest.java index 58c2963e389..843437efb0f 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/user/ws/UsersWsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/user/ws/UsersWsTest.java @@ -72,7 +72,7 @@ public class UsersWsTest { WebService.Action action = controller.action("create"); assertThat(action).isNotNull(); assertThat(action.isPost()).isTrue(); - assertThat(action.params()).hasSize(5); + assertThat(action.params()).hasSize(6); } @Test @@ -80,7 +80,7 @@ public class UsersWsTest { WebService.Action action = controller.action("update"); assertThat(action).isNotNull(); assertThat(action.isPost()).isTrue(); - assertThat(action.params()).hasSize(4); + assertThat(action.params()).hasSize(5); } @Test diff --git a/sonar-db/src/main/java/org/sonar/db/user/UserDto.java b/sonar-db/src/main/java/org/sonar/db/user/UserDto.java index 9b83805dbaa..826317bcc87 100644 --- a/sonar-db/src/main/java/org/sonar/db/user/UserDto.java +++ b/sonar-db/src/main/java/org/sonar/db/user/UserDto.java @@ -19,8 +19,6 @@ */ package org.sonar.db.user; -import static java.util.Objects.requireNonNull; - import com.google.common.base.Splitter; import com.google.common.collect.Lists; import java.util.ArrayList; @@ -31,6 +29,8 @@ import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang.StringUtils; import org.sonar.core.user.DefaultUser; +import static java.util.Objects.requireNonNull; + /** * @since 3.2 */ @@ -110,9 +110,6 @@ public class UserDto { return decodeScmAccounts(scmAccounts); } - /** - * List of SCM accounts separated by '|' - */ public UserDto setScmAccounts(@Nullable String s) { this.scmAccounts = s; return this; diff --git a/sonar-db/src/test/java/org/sonar/db/user/UserDaoTest.java b/sonar-db/src/test/java/org/sonar/db/user/UserDaoTest.java index 6e5a916033c..cd28421be24 100644 --- a/sonar-db/src/test/java/org/sonar/db/user/UserDaoTest.java +++ b/sonar-db/src/test/java/org/sonar/db/user/UserDaoTest.java @@ -19,16 +19,6 @@ */ package org.sonar.db.user; -import static java.util.Arrays.asList; -import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.sonar.db.user.GroupMembershipQuery.IN; -import static org.sonar.db.user.GroupMembershipQuery.builder; -import static org.sonar.db.user.UserTesting.newUserDto; - import java.util.Collection; import java.util.Collections; import java.util.List; @@ -52,6 +42,16 @@ import org.sonar.db.measure.MeasureFilterFavouriteDto; import org.sonar.db.property.PropertyDto; import org.sonar.db.property.PropertyQuery; +import static java.util.Arrays.asList; +import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.sonar.db.user.GroupMembershipQuery.IN; +import static org.sonar.db.user.GroupMembershipQuery.builder; +import static org.sonar.db.user.UserTesting.newUserDto; + public class UserDaoTest { @Rule diff --git a/sonar-db/src/test/java/org/sonar/db/user/UserTesting.java b/sonar-db/src/test/java/org/sonar/db/user/UserTesting.java index b2f74af3c5c..cdf891465f4 100644 --- a/sonar-db/src/test/java/org/sonar/db/user/UserTesting.java +++ b/sonar-db/src/test/java/org/sonar/db/user/UserTesting.java @@ -19,6 +19,7 @@ */ package org.sonar.db.user; +import static java.util.Collections.singletonList; import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; import static org.apache.commons.lang.math.RandomUtils.nextLong; @@ -35,7 +36,7 @@ public class UserTesting { .setName(name) .setEmail(email) .setLogin(login) - .setScmAccounts(randomAlphanumeric(40)) + .setScmAccounts(singletonList(randomAlphanumeric(40))) .setExternalIdentity(login) .setExternalIdentityProvider("sonarqube") .setSalt(randomAlphanumeric(40)) @@ -51,7 +52,7 @@ public class UserTesting { .setName(name) .setEmail(email) .setLogin(login) - .setScmAccounts(randomAlphanumeric(40)) + .setScmAccounts(singletonList(randomAlphanumeric(40))) .setExternalIdentity(login) .setExternalIdentityProvider("sonarqube") .setSalt(randomAlphanumeric(40)) @@ -67,7 +68,7 @@ public class UserTesting { .setName(name) .setEmail(email) .setLogin(login) - .setScmAccounts(randomAlphanumeric(40)) + .setScmAccounts(singletonList(randomAlphanumeric(40))) .setExternalIdentity(randomAlphanumeric(40)) .setExternalIdentityProvider(randomAlphanumeric(40)) .setCreatedAt(nextLong()) diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/user/CreateRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/user/CreateRequest.java new file mode 100644 index 00000000000..4144497bc86 --- /dev/null +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/user/CreateRequest.java @@ -0,0 +1,115 @@ +/* + * 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 java.util.List; +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Strings.isNullOrEmpty; +import static java.util.Collections.emptyList; + +public class CreateRequest { + + private final String login; + private final String password; + private final String name; + private final String email; + private final List scmAccounts; + + public CreateRequest(Builder builder) { + this.login = builder.login; + this.password = builder.password; + this.name = builder.name; + this.email = builder.email; + this.scmAccounts = builder.scmAccounts; + } + + public String getLogin() { + return login; + } + + public String getPassword() { + return password; + } + + public String getName() { + return name; + } + + @CheckForNull + public String getEmail() { + return email; + } + + public List getScmAccounts() { + return scmAccounts; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private String login; + private String password; + private String name; + private String email; + private List scmAccounts = emptyList(); + + private Builder() { + // enforce factory method use + } + + public Builder setLogin(String login) { + this.login = login; + return this; + } + + public Builder setPassword(String password) { + this.password = password; + return this; + } + + public Builder setName(String name) { + this.name = name; + return this; + } + + public Builder setEmail(@Nullable String email) { + this.email = email; + return this; + } + + public Builder setScmAccounts(List scmAccounts) { + this.scmAccounts = scmAccounts; + return this; + } + + public CreateRequest build() { + checkArgument(!isNullOrEmpty(login), "Login is mandatory and must not be empty"); + checkArgument(!isNullOrEmpty(password), "Password is mandatory and must not be empty"); + checkArgument(!isNullOrEmpty(name), "Name is mandatory and must not be empty"); + return new CreateRequest(this); + } + } +} diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/user/UpdateRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/user/UpdateRequest.java new file mode 100644 index 00000000000..87757cce4e2 --- /dev/null +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/user/UpdateRequest.java @@ -0,0 +1,102 @@ +/* + * 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 java.util.List; +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Strings.isNullOrEmpty; +import static java.util.Collections.emptyList; + +public class UpdateRequest { + + private final String login; + private final String name; + private final String email; + private final List scmAccounts; + + public UpdateRequest(Builder builder) { + this.login = builder.login; + this.name = builder.name; + this.email = builder.email; + this.scmAccounts = builder.scmAccounts; + } + + public String getLogin() { + return login; + } + + @CheckForNull + public String getName() { + return name; + } + + @CheckForNull + public String getEmail() { + return email; + } + + public List getScmAccounts() { + return scmAccounts; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private String login; + private String name; + private String email; + private List scmAccounts = emptyList(); + + private Builder() { + // enforce factory method use + } + + public Builder setLogin(String login) { + this.login = login; + return this; + } + + public Builder setName(@Nullable String name) { + this.name = name; + return this; + } + + public Builder setEmail(@Nullable String email) { + this.email = email; + return this; + } + + public Builder setScmAccounts(List scmAccounts) { + this.scmAccounts = scmAccounts; + return this; + } + + public UpdateRequest build() { + checkArgument(!isNullOrEmpty(login), "Login is mandatory and must not be empty"); + return new UpdateRequest(this); + } + } +} 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 new file mode 100644 index 00000000000..df9c73ffd8f --- /dev/null +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/user/UserService.java @@ -0,0 +1,59 @@ +/* + * 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/UsersWsParameters.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/user/UsersWsParameters.java new file mode 100644 index 00000000000..ea79758067c --- /dev/null +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/user/UsersWsParameters.java @@ -0,0 +1,42 @@ +/* + * 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; + +public class UsersWsParameters { + + public static final String CONTROLLER_USERS = "api/users"; + + public static final String ACTION_CREATE = "create"; + public static final String ACTION_UPDATE = "update"; + + public static final String PARAM_LOGIN = "login"; + public static final String PARAM_PASSWORD = "password"; + public static final String PARAM_NAME = "name"; + public static final String PARAM_EMAIL = "email"; + public static final String PARAM_SCM_ACCOUNTS = "scmAccounts"; + public static final String PARAM_SCM_ACCOUNTS_DEPRECATED = "scm_accounts"; + public static final String PARAM_SCM_ACCOUNT = "scmAccount"; + + private UsersWsParameters() { + // Only static stuff + } + +} diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/user/CreateRequestTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/user/CreateRequestTest.java new file mode 100644 index 00000000000..0ba49c20a98 --- /dev/null +++ b/sonar-ws/src/test/java/org/sonarqube/ws/client/user/CreateRequestTest.java @@ -0,0 +1,96 @@ +/* + * 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.junit.rules.ExpectedException; + +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; + +public class CreateRequestTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + CreateRequest.Builder underTest = CreateRequest.builder(); + + @Test + public void create_request() { + CreateRequest result = underTest + .setLogin("john") + .setPassword("123456") + .setName("John") + .setEmail("john@doo.com") + .setScmAccounts(asList("jo", "hn")) + .build(); + + assertThat(result.getLogin()).isEqualTo("john"); + assertThat(result.getPassword()).isEqualTo("123456"); + assertThat(result.getName()).isEqualTo("John"); + assertThat(result.getEmail()).isEqualTo("john@doo.com"); + assertThat(result.getScmAccounts()).containsOnly("jo", "hn"); + } + + @Test + public void scm_accounts_is_empty_by_default() throws Exception { + CreateRequest result = underTest + .setLogin("john") + .setPassword("123456") + .setName("John") + .setEmail("john@doo.com") + .build(); + + assertThat(result.getScmAccounts()).isEmpty(); + } + + @Test + public void fail_when_empty_login() { + expectedException.expect(IllegalArgumentException.class); + underTest + .setLogin("") + .setPassword("123456") + .setName("John") + .build(); + } + + @Test + public void fail_when_empty_password() { + expectedException.expect(IllegalArgumentException.class); + underTest + .setLogin("john") + .setPassword("") + .setName("John") + .build(); + } + + @Test + public void fail_when_empty_name() { + expectedException.expect(IllegalArgumentException.class); + underTest + .setLogin("john") + .setPassword("12345") + .setName("") + .build(); + } + +} diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/user/UpdateRequestTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/user/UpdateRequestTest.java new file mode 100644 index 00000000000..2d8428dfb7e --- /dev/null +++ b/sonar-ws/src/test/java/org/sonarqube/ws/client/user/UpdateRequestTest.java @@ -0,0 +1,72 @@ +/* + * 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.junit.rules.ExpectedException; + +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; + +public class UpdateRequestTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + UpdateRequest.Builder underTest = UpdateRequest.builder(); + + @Test + public void create_request() { + UpdateRequest result = underTest + .setLogin("john") + .setName("John") + .setEmail("john@doo.com") + .setScmAccounts(asList("jo", "hn")) + .build(); + + assertThat(result.getLogin()).isEqualTo("john"); + assertThat(result.getName()).isEqualTo("John"); + assertThat(result.getEmail()).isEqualTo("john@doo.com"); + assertThat(result.getScmAccounts()).containsOnly("jo", "hn"); + } + + @Test + public void scm_accounts_is_empty_by_default() throws Exception { + UpdateRequest result = underTest + .setLogin("john") + .setName("John") + .setEmail("john@doo.com") + .build(); + + assertThat(result.getScmAccounts()).isEmpty(); + } + + @Test + public void fail_when_empty_login() { + expectedException.expect(IllegalArgumentException.class); + underTest + .setLogin("") + .setName("John") + .build(); + } + +} 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 new file mode 100644 index 00000000000..675894bf53c --- /dev/null +++ b/sonar-ws/src/test/java/org/sonarqube/ws/client/user/UserServiceTest.java @@ -0,0 +1,79 @@ +/* + * 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 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(); + } + +}