]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9356 Refactor api/user/current to use protobuf
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Mon, 12 Jun 2017 13:25:52 +0000 (15:25 +0200)
committerStas Vilchik <stas.vilchik@sonarsource.com>
Tue, 20 Jun 2017 11:10:53 +0000 (04:10 -0700)
server/sonar-server/src/main/java/org/sonar/server/user/ws/CurrentAction.java
server/sonar-server/src/test/java/org/sonar/server/user/ws/CurrentActionTest.java
server/sonar-server/src/test/resources/org/sonar/server/user/ws/CurrentActionTest/anonymous.json [deleted file]
sonar-ws/src/main/protobuf/ws-users.proto

index 5cbd3511eb7bf54bff8cd2714194b5ff2ebabe32..36a208ca8ce348ce1067be5b42cce4c5ca5ef5b0 100644 (file)
 package org.sonar.server.user.ws;
 
 import java.util.Collection;
-import java.util.Optional;
+import java.util.List;
+import java.util.stream.Collectors;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService.NewController;
-import org.sonar.api.utils.text.JsonWriter;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.permission.OrganizationPermission;
 import org.sonar.db.user.UserDto;
 import org.sonar.server.organization.DefaultOrganizationProvider;
 import org.sonar.server.user.UserSession;
+import org.sonarqube.ws.WsUsers.CurrentWsResponse;
 
-import static com.google.common.base.Strings.isNullOrEmpty;
-import static java.util.Collections.emptyList;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.base.Strings.emptyToNull;
 import static java.util.Collections.singletonList;
-import static org.sonar.server.user.ws.UserJsonWriter.FIELD_EXTERNAL_IDENTITY;
-import static org.sonar.server.user.ws.UserJsonWriter.FIELD_EXTERNAL_PROVIDER;
+import static org.sonar.core.util.Protobuf.setNullable;
+import static org.sonar.server.ws.WsUtils.writeProtobuf;
+import static org.sonarqube.ws.WsUsers.CurrentWsResponse.Permissions;
+import static org.sonarqube.ws.WsUsers.CurrentWsResponse.newBuilder;
 
 public class CurrentAction implements UsersWsAction {
   private final UserSession userSession;
@@ -61,87 +64,43 @@ public class CurrentAction implements UsersWsAction {
 
   @Override
   public void handle(Request request, Response response) throws Exception {
-    try (DbSession dbSession = dbClient.openSession(false)) {
-      Optional<UserDto> user = Optional.empty();
-      Collection<String> groups = emptyList();
-      if (userSession.isLoggedIn()) {
-        user = selectCurrentUser(dbSession);
-        groups = selectGroups(dbSession);
+    if (userSession.isLoggedIn()) {
+      try (DbSession dbSession = dbClient.openSession(false)) {
+        writeProtobuf(toWsResponse(dbSession, userSession.getLogin()), request, response);
       }
-      writeResponse(response, user, groups);
+    } else {
+      writeProtobuf(newBuilder()
+        .setIsLoggedIn(false)
+        .setPermissions(Permissions.newBuilder().addAllGlobal(getGlobalPermissions()).build())
+        .build(),
+        request, response);
     }
   }
 
-  private Optional<UserDto> selectCurrentUser(DbSession dbSession) {
-    return Optional.ofNullable(dbClient.userDao().selectActiveUserByLogin(dbSession, userSession.getLogin()));
+  private CurrentWsResponse toWsResponse(DbSession dbSession, String userLogin) {
+    UserDto user = dbClient.userDao().selectActiveUserByLogin(dbSession, userLogin);
+    checkState(user != null, "User login '%s' cannot be found", userLogin);
+    Collection<String> groups = dbClient.groupMembershipDao().selectGroupsByLogins(dbSession, singletonList(userLogin)).get(userLogin);
+
+    CurrentWsResponse.Builder builder = newBuilder()
+      .setIsLoggedIn(true)
+      .setLogin(user.getLogin())
+      .setName(user.getName())
+      .setLocal(user.isLocal())
+      .addAllGroups(groups)
+      .addAllScmAccounts(user.getScmAccountsAsList())
+      .setPermissions(Permissions.newBuilder().addAllGlobal(getGlobalPermissions()).build());
+    setNullable(emptyToNull(user.getEmail()), builder::setEmail);
+    setNullable(user.getExternalIdentity(), builder::setExternalIdentity);
+    setNullable(user.getExternalIdentityProvider(), builder::setExternalProvider);
+    return builder.build();
   }
 
-  private Collection<String> selectGroups(DbSession dbSession) {
-    return dbClient.groupMembershipDao().selectGroupsByLogins(dbSession, singletonList(userSession.getLogin()))
-      .get(userSession.getLogin());
-  }
-
-  private void writeResponse(Response response, Optional<UserDto> user, Collection<String> groups) {
-    JsonWriter json = response.newJsonWriter().beginObject();
-    writeUserDetails(json, user, groups);
-    json.endObject().close();
-  }
-
-  private void writeUserDetails(JsonWriter json, Optional<UserDto> optionalUser, Collection<String> groups) {
-    json
-      .prop("isLoggedIn", userSession.isLoggedIn())
-      .prop("login", userSession.getLogin())
-      .prop("name", userSession.getName());
-    if (optionalUser.isPresent()) {
-      UserDto user = optionalUser.get();
-      if (!isNullOrEmpty(user.getEmail())) {
-        json.prop("email", user.getEmail());
-      }
-      json.prop("local", user.isLocal());
-      json.prop(FIELD_EXTERNAL_IDENTITY, user.getExternalIdentity());
-      json.prop(FIELD_EXTERNAL_PROVIDER, user.getExternalIdentityProvider());
-    }
-
-    writeScmAccounts(json, optionalUser);
-    writeGroups(json, groups);
-    writePermissions(json);
-  }
-
-  private static void writeScmAccounts(JsonWriter json, Optional<UserDto> optionalUser) {
-    json.name("scmAccounts");
-    json.beginArray();
-    if (optionalUser.isPresent()) {
-      for (String scmAccount : optionalUser.get().getScmAccountsAsList()) {
-        json.value(scmAccount);
-      }
-    }
-    json.endArray();
-  }
-
-  private static void writeGroups(JsonWriter json, Collection<String> groups) {
-    json.name("groups");
-    json.beginArray();
-    for (String group : groups) {
-      json.value(group);
-    }
-    json.endArray();
-  }
-
-  private void writePermissions(JsonWriter json) {
-    json.name("permissions").beginObject();
-    writeGlobalPermissions(json);
-    json.endObject();
-  }
-
-  private void writeGlobalPermissions(JsonWriter json) {
-    json.name("global").beginArray();
-
+  private List<String> getGlobalPermissions() {
     String defaultOrganizationUuid = defaultOrganizationProvider.get().getUuid();
-    OrganizationPermission.all()
+    return OrganizationPermission.all()
       .filter(permission -> userSession.hasPermission(permission, defaultOrganizationUuid))
-      .forEach(permission -> json.value(permission.getKey()));
-
-    json.endArray();
+      .map(OrganizationPermission::getKey)
+      .collect(Collectors.toList());
   }
-
 }
index 80fe655edf7cac0663a3649c4e7a1c98224b88f3..fe623c05cce48227727f370be120a9ba253b7b7d 100644 (file)
  */
 package org.sonar.server.user.ws;
 
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.server.ws.WebService;
 import org.sonar.api.utils.System2;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbTester;
-import org.sonar.db.user.GroupDto;
 import org.sonar.db.user.UserDto;
-import org.sonar.db.user.UserGroupDto;
 import org.sonar.server.organization.DefaultOrganizationProvider;
 import org.sonar.server.organization.TestDefaultOrganizationProvider;
 import org.sonar.server.tester.UserSessionRule;
 import org.sonar.server.ws.WsActionTester;
+import org.sonarqube.ws.WsUsers.CurrentWsResponse;
 
 import static com.google.common.collect.Lists.newArrayList;
-import static org.sonar.db.user.GroupTesting.newGroupDto;
-import static org.sonar.db.user.UserTesting.newUserDto;
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.sonar.db.permission.OrganizationPermission.ADMINISTER;
 import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_PROFILES;
+import static org.sonar.db.permission.OrganizationPermission.PROVISION_PROJECTS;
 import static org.sonar.db.permission.OrganizationPermission.SCAN;
+import static org.sonar.db.user.GroupTesting.newGroupDto;
 import static org.sonar.test.JsonAssert.assertJson;
 
 public class CurrentActionTest {
@@ -46,56 +47,165 @@ public class CurrentActionTest {
   public UserSessionRule userSessionRule = UserSessionRule.standalone();
   @Rule
   public DbTester db = DbTester.create(System2.INSTANCE);
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
 
   private DbClient dbClient = db.getDbClient();
   private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db);
-  private WsActionTester ws;
+  private WsActionTester ws = new WsActionTester(new CurrentAction(userSessionRule, dbClient, defaultOrganizationProvider));
+
+  @Test
+  public void return_user_info() {
+    db.users().insertUser(user -> user
+      .setLogin("obiwan.kenobi")
+      .setName("Obiwan Kenobi")
+      .setEmail("obiwan.kenobi@starwars.com")
+      .setLocal(true)
+      .setExternalIdentity("obiwan")
+      .setExternalIdentityProvider("sonarqube")
+      .setScmAccounts(newArrayList("obiwan:github", "obiwan:bitbucket")));
+    userSessionRule.logIn("obiwan.kenobi");
+
+    CurrentWsResponse response = call();
 
-  @Before
-  public void before() {
-    ws = new WsActionTester(new CurrentAction(userSessionRule, dbClient, defaultOrganizationProvider));
+    assertThat(response)
+      .extracting(CurrentWsResponse::getIsLoggedIn, CurrentWsResponse::getLogin, CurrentWsResponse::getName, CurrentWsResponse::getEmail, CurrentWsResponse::getLocal,
+        CurrentWsResponse::getExternalIdentity, CurrentWsResponse::getExternalProvider, CurrentWsResponse::getScmAccountsList)
+      .containsExactly(true, "obiwan.kenobi", "Obiwan Kenobi", "obiwan.kenobi@starwars.com", true, "obiwan", "sonarqube",
+        newArrayList("obiwan:github", "obiwan:bitbucket"));
   }
 
   @Test
-  public void json_example() {
-    userSessionRule.logIn("obiwan.kenobi").setName("Obiwan Kenobi");
+  public void return_minimal_user_info() {
+    db.users().insertUser(user -> user
+      .setLogin("obiwan.kenobi")
+      .setName("Obiwan Kenobi")
+      .setEmail(null)
+      .setLocal(true)
+      .setExternalIdentity("obiwan")
+      .setExternalIdentityProvider("sonarqube")
+      .setScmAccounts((String) null));
+    userSessionRule.logIn("obiwan.kenobi");
+
+    CurrentWsResponse response = call();
+
+    assertThat(response)
+      .extracting(CurrentWsResponse::getIsLoggedIn, CurrentWsResponse::getLogin, CurrentWsResponse::getName, CurrentWsResponse::getLocal,
+        CurrentWsResponse::getExternalIdentity, CurrentWsResponse::getExternalProvider)
+      .containsExactly(true, "obiwan.kenobi", "Obiwan Kenobi", true, "obiwan", "sonarqube");
+    assertThat(response.hasEmail()).isFalse();
+    assertThat(response.getScmAccountsList()).isEmpty();
+    assertThat(response.getGroupsList()).isEmpty();
+    assertThat(response.getPermissions().getGlobalList()).isEmpty();
+  }
+
+  @Test
+  public void convert_empty_email_to_null() {
+    db.users().insertUser(user -> user
+      .setLogin("obiwan.kenobi")
+      .setEmail(""));
+    userSessionRule.logIn("obiwan.kenobi");
 
-    // permissions on default organization
+    CurrentWsResponse response = call();
+
+    assertThat(response.hasEmail()).isFalse();
+  }
+
+  @Test
+  public void return_group_membership() {
+    UserDto user = db.users().insertUser();
+    userSessionRule.logIn(user.getLogin());
+    db.users().insertMember(db.users().insertGroup(newGroupDto().setName("Jedi")), user);
+    db.users().insertMember(db.users().insertGroup(newGroupDto().setName("Rebel")), user);
+
+    CurrentWsResponse response = call();
+
+    assertThat(response.getGroupsList()).containsOnly("Jedi", "Rebel");
+  }
+
+  @Test
+  public void return_permissions() {
+    UserDto user = db.users().insertUser();
     userSessionRule
+      .logIn(user.getLogin())
+      // permissions on default organization
       .addPermission(SCAN, db.getDefaultOrganization())
-      .addPermission(ADMINISTER_QUALITY_PROFILES, db.getDefaultOrganization());
+      .addPermission(ADMINISTER_QUALITY_PROFILES, db.getDefaultOrganization())
+      // permissions on other organizations are ignored
+      .addPermission(ADMINISTER, db.organizations().insert());
 
-    // permissions on other organizations are ignored
-    userSessionRule.addPermission(ADMINISTER, db.organizations().insert());
-
-    UserDto obiwan = db.users().insertUser(
-      newUserDto("obiwan.kenobi", "Obiwan Kenobi", "obiwan.kenobi@starwars.com")
-        .setLocal(true)
-        .setExternalIdentity("obiwan.kenobi")
-        .setExternalIdentityProvider("sonarqube")
-        .setScmAccounts(newArrayList("obiwan:github", "obiwan:bitbucket")));
-    GroupDto jedi = db.users().insertGroup(newGroupDto().setName("Jedi"));
-    GroupDto rebel = db.users().insertGroup(newGroupDto().setName("Rebel"));
-    db.users().insertGroup(newGroupDto().setName("Sith"));
-    dbClient.userGroupDao().insert(db.getSession(), new UserGroupDto()
-      .setUserId(obiwan.getId())
-      .setGroupId(jedi.getId()));
-    dbClient.userGroupDao().insert(db.getSession(), new UserGroupDto()
-      .setUserId(obiwan.getId())
-      .setGroupId(rebel.getId()));
-    db.commit();
+    CurrentWsResponse response = call();
 
-    String response = ws.newRequest().execute().getInput();
+    assertThat(response.getPermissions().getGlobalList()).containsOnly("profileadmin", "scan");
+  }
 
-    assertJson(response).isSimilarTo(getClass().getResource("current-example.json"));
+  @Test
+  public void fail_with_ISE_when_user_login_in_db_does_not_exist() {
+    db.users().insertUser(usert -> usert.setLogin("another"));
+    userSessionRule.logIn("obiwan.kenobi");
+
+    expectedException.expect(IllegalStateException.class);
+    expectedException.expectMessage("User login 'obiwan.kenobi' cannot be found");
+
+    call();
   }
 
   @Test
   public void anonymous() {
-    userSessionRule.anonymous();
+    userSessionRule
+      .anonymous()
+      .addPermission(SCAN, db.getDefaultOrganization())
+      .addPermission(PROVISION_PROJECTS, db.getDefaultOrganization());
+
+    CurrentWsResponse response = call();
+
+    assertThat(response.getIsLoggedIn()).isFalse();
+    assertThat(response.getPermissions().getGlobalList()).containsOnly("scan", "provisioning");
+    assertThat(response)
+      .extracting(CurrentWsResponse::hasLogin, CurrentWsResponse::hasName, CurrentWsResponse::hasEmail, CurrentWsResponse::hasLocal,
+        CurrentWsResponse::hasExternalIdentity, CurrentWsResponse::hasExternalProvider)
+      .containsOnly(false);
+    assertThat(response.getScmAccountsList()).isEmpty();
+    assertThat(response.getGroupsList()).isEmpty();
+  }
+
+  @Test
+  public void json_example() {
+    userSessionRule
+      .logIn("obiwan.kenobi")
+      .addPermission(SCAN, db.getDefaultOrganization())
+      .addPermission(ADMINISTER_QUALITY_PROFILES, db.getDefaultOrganization());
+    UserDto obiwan = db.users().insertUser(user -> user
+      .setLogin("obiwan.kenobi")
+      .setName("Obiwan Kenobi")
+      .setEmail("obiwan.kenobi@starwars.com")
+      .setLocal(true)
+      .setExternalIdentity("obiwan.kenobi")
+      .setExternalIdentityProvider("sonarqube")
+      .setScmAccounts(newArrayList("obiwan:github", "obiwan:bitbucket")));
+    db.users().insertMember(db.users().insertGroup(newGroupDto().setName("Jedi")), obiwan);
+    db.users().insertMember(db.users().insertGroup(newGroupDto().setName("Rebel")), obiwan);
 
     String response = ws.newRequest().execute().getInput();
 
-    assertJson(response).isSimilarTo(getClass().getResource("CurrentActionTest/anonymous.json"));
+    assertJson(response).isSimilarTo(getClass().getResource("current-example.json"));
   }
+
+  @Test
+  public void test_definition() {
+    WebService.Action definition = ws.getDef();
+    assertThat(definition.key()).isEqualTo("current");
+    assertThat(definition.description()).isEqualTo("Get the details of the current authenticated user.");
+    assertThat(definition.since()).isEqualTo("5.2");
+    assertThat(definition.isPost()).isFalse();
+    assertThat(definition.isInternal()).isTrue();
+    assertThat(definition.responseExampleAsString()).isNotEmpty();
+    assertThat(definition.params()).isEmpty();
+    assertThat(definition.changelog()).isEmpty();
+  }
+
+  private CurrentWsResponse call() {
+    return ws.newRequest().executeProtobuf(CurrentWsResponse.class);
+  }
+
 }
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/user/ws/CurrentActionTest/anonymous.json b/server/sonar-server/src/test/resources/org/sonar/server/user/ws/CurrentActionTest/anonymous.json
deleted file mode 100644 (file)
index 40a8248..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "isLoggedIn": false,
-  "scmAccounts": [],
-  "groups": [],
-  "permissions": {
-    "global": []
-  }
-}
index 21aba165b0846695da8b289bbee458ad5837f72f..0eddebed9400e103149732dc48918de011368b5b 100644 (file)
@@ -93,4 +93,22 @@ message GroupsWsResponse {
   }
 }
 
+// WS api/users/current
+message CurrentWsResponse {
+  optional bool isLoggedIn = 1;
+  optional string login = 2;
+  optional string name = 3;
+  optional string email = 4;
+  optional bool local = 5;
+  optional string externalIdentity = 6;
+  optional string externalProvider = 7;
+  repeated string scmAccounts = 8;
+  repeated string groups = 9;
+  optional Permissions permissions = 10;
+
+  message Permissions {
+    repeated string global = 1;
+  }
+}
+