From 40d56d9e35a29b0964fe9e1bf290ebe59729038e Mon Sep 17 00:00:00 2001 From: Guillaume Jambet Date: Thu, 14 Dec 2017 12:04:25 +0100 Subject: [PATCH] SONAR-10182 Add api/users/set_homepage persistence --- .../sonar/server/user/ws/CurrentAction.java | 5 +- .../server/user/ws/SetHomepageAction.java | 86 ++++++++- .../server/user/ws/SetHomepageActionTest.java | 171 +++++++++++++++++- 3 files changed, 245 insertions(+), 17 deletions(-) diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/ws/CurrentAction.java b/server/sonar-server/src/main/java/org/sonar/server/user/ws/CurrentAction.java index 65e741f1c78..71a6447d142 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/user/ws/CurrentAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/user/ws/CurrentAction.java @@ -42,14 +42,13 @@ import static com.google.common.base.Strings.emptyToNull; import static java.lang.String.format; import static java.util.Collections.singletonList; import static java.util.stream.Collectors.toList; -import static org.apache.commons.lang.StringUtils.isNotBlank; import static org.sonar.core.util.Protobuf.setNullable; import static org.sonar.server.ws.WsUtils.writeProtobuf; +import static org.sonarqube.ws.Users.CurrentWsResponse.Permissions; +import static org.sonarqube.ws.Users.CurrentWsResponse.newBuilder; import static org.sonarqube.ws.Users.CurrentWsResponse.HomepageType.MY_PROJECTS; import static org.sonarqube.ws.Users.CurrentWsResponse.HomepageType.ORGANIZATION; import static org.sonarqube.ws.Users.CurrentWsResponse.HomepageType.PROJECT; -import static org.sonarqube.ws.Users.CurrentWsResponse.Permissions; -import static org.sonarqube.ws.Users.CurrentWsResponse.newBuilder; import static org.sonarqube.ws.client.user.UsersWsParameters.ACTION_CURRENT; public class CurrentAction implements UsersWsAction { diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/ws/SetHomepageAction.java b/server/sonar-server/src/main/java/org/sonar/server/user/ws/SetHomepageAction.java index 1adb81b82e8..5427550e819 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/user/ws/SetHomepageAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/user/ws/SetHomepageAction.java @@ -19,22 +19,50 @@ */ package org.sonar.server.user.ws; +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; 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.component.ComponentFinder; +import org.sonar.server.user.UserSession; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; +import static org.apache.commons.lang.StringUtils.isBlank; +import static org.apache.commons.lang.StringUtils.isNotBlank; +import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; +import static org.sonar.server.ws.WsUtils.checkFoundWithOptional; +import static org.sonarqube.ws.Users.CurrentWsResponse.HomepageType.MY_ISSUES; +import static org.sonarqube.ws.Users.CurrentWsResponse.HomepageType.MY_PROJECTS; +import static org.sonarqube.ws.Users.CurrentWsResponse.HomepageType.ORGANIZATION; +import static org.sonarqube.ws.Users.CurrentWsResponse.HomepageType.PROJECT; public class SetHomepageAction implements UsersWsAction { - private static final String PARAM_TYPE = "type"; - private static final String PARAM_VALUE = "value"; - private static final String ACTION = "set_homepage"; + static final String PARAM_TYPE = "type"; + static final String PARAM_VALUE = "value"; + static final String ACTION = "set_homepage"; + + private final UserSession userSession; + private final DbClient dbClient; + private final ComponentFinder componentFinder; + public SetHomepageAction(UserSession userSession, DbClient dbClient, ComponentFinder componentFinder) { + this.userSession = userSession; + this.dbClient = dbClient; + this.componentFinder = componentFinder; + } @Override public void define(WebService.NewController controller) { WebService.NewAction action = controller.createAction(ACTION) .setPost(true) - .setDescription("Set Homepage of current user.
Requires authentication.") + .setInternal(true) + .setDescription("Set homepage of current user.
Requires authentication.") .setSince("7.0") .setHandler(this); @@ -44,16 +72,60 @@ public class SetHomepageAction implements UsersWsAction { .setPossibleValues(HomepageTypes.keys()); action.createParam(PARAM_VALUE) - .setDescription("Additional information to filter the page (project or organization key)") - .setExampleValue("my-project-key"); + .setDescription("Additional information to identify the page (project or organization key)") + .setExampleValue(KEY_PROJECT_EXAMPLE_001); } @Override public void handle(Request request, Response response) throws Exception { + userSession.checkLoggedIn(); + + String type = request.mandatoryParam(PARAM_TYPE); + String value = request.param(PARAM_VALUE); + + checkRequest(type, value); + + String login = userSession.getLogin(); + + try (DbSession dbSession = dbClient.openSession(false)) { + + UserDto user = dbClient.userDao().selectActiveUserByLogin(dbSession, login); + checkState(user != null, "User login '%s' cannot be found", login); + + user.setHomepageType(type); + user.setHomepageValue(findHomepageValue(dbSession, type, value)); + + dbClient.userDao().update(dbSession, user); + dbSession.commit(); + } - // WIP : Not implemented yet. response.noContent(); + } + + @CheckForNull + private String findHomepageValue(DbSession dbSession, String type, String value) { + + if (PROJECT.toString().equals(type)) { + return componentFinder.getByKey(dbSession, value).uuid(); + } + + if (ORGANIZATION.toString().equals(type)) { + return checkFoundWithOptional(dbClient.organizationDao().selectByKey(dbSession, value), "No organizationDto with key '%s'", value).getUuid(); + } + + return null; + } + + private static void checkRequest(String type, @Nullable String value) { + + if (PROJECT.toString().equals(type) || ORGANIZATION.toString().equals(type)) { + checkArgument(isNotBlank(value), "Type %s requires a value", type); + } + + if (MY_PROJECTS.toString().equals(type) || MY_ISSUES.toString().equals(type)) { + checkArgument(isBlank(value), "Parameter value must not be provided when type is %s", type); + } } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/user/ws/SetHomepageActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/user/ws/SetHomepageActionTest.java index c84786f4d19..cae8af9edcd 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/user/ws/SetHomepageActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/user/ws/SetHomepageActionTest.java @@ -19,25 +19,55 @@ */ package org.sonar.server.user.ws; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.sonar.api.server.ws.WebService; +import org.sonar.db.DbClient; +import org.sonar.db.DbTester; +import org.sonar.db.component.ComponentDbTester; +import org.sonar.db.component.ComponentDto; +import org.sonar.db.organization.OrganizationDto; +import org.sonar.db.user.UserDto; +import org.sonar.server.component.TestComponentFinder; +import org.sonar.server.exceptions.UnauthorizedException; +import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.ws.TestResponse; import org.sonar.server.ws.WsActionTester; +import static org.apache.http.HttpStatus.SC_NO_CONTENT; import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto; +import static org.sonar.server.user.ws.SetHomepageAction.PARAM_TYPE; +import static org.sonar.server.user.ws.SetHomepageAction.PARAM_VALUE; +import static org.sonarqube.ws.Users.CurrentWsResponse.HomepageType.MY_ISSUES; +import static org.sonarqube.ws.Users.CurrentWsResponse.HomepageType.MY_PROJECTS; +import static org.sonarqube.ws.Users.CurrentWsResponse.HomepageType.ORGANIZATION; +import static org.sonarqube.ws.Users.CurrentWsResponse.HomepageType.PROJECT; public class SetHomepageActionTest { - private SetHomepageAction underTest = new SetHomepageAction(); - private WsActionTester wsTester = new WsActionTester(underTest); + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + + @Rule + public DbTester db = DbTester.create(); + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + private DbClient dbClient = db.getDbClient(); + private SetHomepageAction underTest = new SetHomepageAction(userSession, dbClient, TestComponentFinder.from(db)); + private WsActionTester ws = new WsActionTester(underTest); @Test public void verify_definition() { - WebService.Action action = wsTester.getDef(); + WebService.Action action = ws.getDef(); assertThat(action.key()).isEqualTo("set_homepage"); - assertThat(action.isInternal()).isFalse(); + assertThat(action.isInternal()).isTrue(); assertThat(action.isPost()).isTrue(); assertThat(action.since()).isEqualTo("7.0"); - assertThat(action.description()).isEqualTo("Set Homepage of current user.
Requires authentication."); + assertThat(action.description()).isEqualTo("Set homepage of current user.
Requires authentication."); assertThat(action.responseExample()).isNull(); assertThat(action.deprecatedKey()).isNull(); assertThat(action.deprecatedSince()).isNull(); @@ -54,12 +84,139 @@ public class SetHomepageActionTest { WebService.Param keyParam = action.param("value"); assertThat(keyParam.isRequired()).isFalse(); - assertThat(keyParam.description()).isEqualTo("Additional information to filter the page (project or organization key)"); - assertThat(keyParam.exampleValue()).isEqualTo("my-project-key"); + assertThat(keyParam.description()).isEqualTo("Additional information to identify the page (project or organization key)"); + assertThat(keyParam.exampleValue()).isEqualTo("my_project"); assertThat(keyParam.defaultValue()).isNull(); assertThat(keyParam.deprecatedSince()).isNull(); assertThat(keyParam.deprecatedKey()).isNull(); } + @Test + public void set_project_homepage() { + OrganizationDto organization = db.organizations().insert(); + ComponentDto project = new ComponentDbTester(db).insertComponent(newPrivateProjectDto(organization)); + + UserDto user = db.users().insertUser(); + userSession.logIn(user); + + ws.newRequest() + .setMethod("POST") + .setParam(PARAM_TYPE, PROJECT.toString()) + .setParam(PARAM_VALUE, project.getKey()) + .execute(); + + UserDto actual = db.getDbClient().userDao().selectByLogin(db.getSession(), user.getLogin()); + assertThat(actual).isNotNull(); + assertThat(actual.getHomepageType()).isEqualTo(PROJECT.toString()); + assertThat(actual.getHomepageValue()).isEqualTo(project.uuid()); + } + + @Test + public void set_organization_homepage() { + OrganizationDto organization = db.organizations().insert(); + + UserDto user = db.users().insertUser(); + userSession.logIn(user); + + ws.newRequest() + .setMethod("POST") + .setParam(PARAM_TYPE, ORGANIZATION.toString()) + .setParam(PARAM_VALUE, organization.getKey()) + .execute(); + + UserDto actual = db.getDbClient().userDao().selectByLogin(db.getSession(), user.getLogin()); + assertThat(actual).isNotNull(); + assertThat(actual.getHomepageType()).isEqualTo(ORGANIZATION.toString()); + assertThat(actual.getHomepageValue()).isEqualTo(organization.getUuid()); + } + + @Test + public void set_my_issues_homepage() { + UserDto user = db.users().insertUser(); + userSession.logIn(user); + + ws.newRequest() + .setMethod("POST") + .setParam(PARAM_TYPE, MY_ISSUES.toString()) + .execute(); + + UserDto actual = db.getDbClient().userDao().selectByLogin(db.getSession(), user.getLogin()); + assertThat(actual).isNotNull(); + assertThat(actual.getHomepageType()).isEqualTo(MY_ISSUES.toString()); + assertThat(actual.getHomepageValue()).isNullOrEmpty(); + } + + @Test + public void set_my_projects_homepage() { + UserDto user = db.users().insertUser(); + userSession.logIn(user); + + ws.newRequest() + .setMethod("POST") + .setParam(PARAM_TYPE, MY_PROJECTS.toString()) + .execute(); + + UserDto actual = db.getDbClient().userDao().selectByLogin(db.getSession(), user.getLogin()); + assertThat(actual).isNotNull(); + assertThat(actual.getHomepageType()).isEqualTo(MY_PROJECTS.toString()); + assertThat(actual.getHomepageValue()).isNullOrEmpty(); + } + + @Test + public void response_has_no_content() { + UserDto user = db.users().insertUser(); + userSession.logIn(user); + + TestResponse response = ws.newRequest() + .setMethod("POST") + .setParam(PARAM_TYPE, MY_PROJECTS.toString()) + .execute(); + + assertThat(response.getStatus()).isEqualTo(SC_NO_CONTENT); + assertThat(response.getInput()).isEmpty(); + } + + @Test + public void fail_when_missing_project_id_when_requesting_project_type() { + + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Type PROJECT requires a value"); + + UserDto user = db.users().insertUser(); + userSession.logIn(user); + + ws.newRequest() + .setMethod("POST") + .setParam(PARAM_TYPE, PROJECT.toString()) + .setParam(PARAM_VALUE, "") + .execute(); + + } + + @Test + public void fail_when_missing_organization_id_when_requesting_organization_type() { + + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Type ORGANIZATION requires a value"); + + UserDto user = db.users().insertUser(); + userSession.logIn(user); + + ws.newRequest() + .setMethod("POST") + .setParam(PARAM_TYPE, ORGANIZATION.toString()) + .setParam(PARAM_VALUE, "") + .execute(); + + } + + @Test + public void fail_for_anonymous() { + userSession.anonymous(); + expectedException.expect(UnauthorizedException.class); + expectedException.expectMessage("Authentication is required"); + + ws.newRequest().setMethod("POST").execute(); + } } \ No newline at end of file -- 2.39.5