]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-20944 Add externalIdentity filter in apiv2 GET users endpoint
authorAntoine Vigneau <antoine.vigneau@sonarsource.com>
Thu, 16 Nov 2023 10:10:17 +0000 (11:10 +0100)
committersonartech <sonartech@sonarsource.com>
Thu, 16 Nov 2023 20:02:37 +0000 (20:02 +0000)
server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/user/controller/DefaultUserController.java
server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/user/request/UsersSearchRestRequest.java
server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/user/controller/DefaultUserControllerTest.java

index 485a9cbaf6038ae7c7e1543b19be65f32ea35fa1..b869e40b4b7247869c5624cb7a6358e81cdcdbf9 100644 (file)
@@ -67,6 +67,7 @@ public class DefaultUserController implements UserController {
 
   private void throwIfAdminOnlyParametersAreUsed(UsersSearchRestRequest usersSearchRestRequest) {
     if (!userSession.isSystemAdministrator()) {
+      throwIfValuePresent("externalIdentity", usersSearchRestRequest.externalIdentity());
       throwIfValuePresent("sonarLintLastConnectionDateFrom", usersSearchRestRequest.sonarLintLastConnectionDateFrom());
       throwIfValuePresent("sonarLintLastConnectionDateTo", usersSearchRestRequest.sonarLintLastConnectionDateTo());
       throwIfValuePresent("sonarQubeLastConnectionDateFrom", usersSearchRestRequest.sonarQubeLastConnectionDateFrom());
@@ -79,7 +80,7 @@ public class DefaultUserController implements UserController {
   }
 
   private static void throwForbiddenFor(String parameterName) {
-    throw new ForbiddenException("parameter " + parameterName + " requires Administer System permission.");
+    throw new ForbiddenException("Parameter " + parameterName + " requires Administer System permission.");
   }
 
   private static UsersSearchRequest toUserSearchRequest(UsersSearchRestRequest usersSearchRestRequest, RestPage page) {
@@ -87,6 +88,7 @@ public class DefaultUserController implements UserController {
       .setDeactivated(Optional.ofNullable(usersSearchRestRequest.active()).map(active -> !active).orElse(false))
       .setManaged(usersSearchRestRequest.managed())
       .setQuery(usersSearchRestRequest.q())
+      .setExternalLogin(usersSearchRestRequest.externalIdentity())
       .setLastConnectionDateFrom(usersSearchRestRequest.sonarQubeLastConnectionDateFrom())
       .setLastConnectionDateTo(usersSearchRestRequest.sonarQubeLastConnectionDateTo())
       .setSonarLintLastConnectionDateFrom(usersSearchRestRequest.sonarLintLastConnectionDateFrom())
index 7c372ee2fb70c6192b10177f9b7a600f5e51a3bd..7cf37e83c419ab6eb9e4c89d8d91ea265794ab55 100644 (file)
@@ -25,30 +25,41 @@ import javax.annotation.Nullable;
 public record UsersSearchRestRequest(
   @Schema(defaultValue = "true", description = "Return active/inactive users")
   Boolean active,
+
   @Nullable
   @Schema(description = "Return managed or non-managed users. Only available for managed instances, throws for non-managed instances")
   Boolean managed,
+
   @Nullable
   @Schema(description = "Filter on login, name and email.\n"
     + "This parameter can either perform an exact match, or a partial match (contains), it is case insensitive.")
   String q,
+
+  @Nullable
+  @Schema(description = "Filter on externalIdentity.\n"
+    + "This parameter perform a case-sensitive exact match")
+  String externalIdentity,
+
   @Nullable
-  @Schema(description = "Filter the users based on the last connection date field. Only users who interacted with this instance at or after the date will be returned. "
+  @Schema(description = "Filter users based on the last connection date field. Only users who interacted with this instance at or after the date will be returned. "
     + "The format must be ISO 8601 datetime format (YYYY-MM-DDThh:mm:ss±hhmm)",
     example = "2020-01-01T00:00:00+0100")
   String sonarQubeLastConnectionDateFrom,
+
   @Nullable
-  @Schema(description = "Filter the users based on the last connection date field. Only users that never connected or who interacted with this instance at "
+  @Schema(description = "Filter users based on the last connection date field. Only users that never connected or who interacted with this instance at "
     + "or before the date will be returned. The format must be ISO 8601 datetime format (YYYY-MM-DDThh:mm:ss±hhmm)",
     example = "2020-01-01T00:00:00+0100")
   String sonarQubeLastConnectionDateTo,
+
   @Nullable
-  @Schema(description = "Filter the users based on the sonar lint last connection date field Only users who interacted with this instance using SonarLint at or after "
+  @Schema(description = "Filter users based on the SonarLint last connection date field Only users who interacted with this instance using SonarLint at or after "
     + "the date will be returned. The format must be ISO 8601 datetime format (YYYY-MM-DDThh:mm:ss±hhmm)",
     example = "2020-01-01T00:00:00+0100")
   String sonarLintLastConnectionDateFrom,
+
   @Nullable
-  @Schema(description = "Filter the users based on the sonar lint last connection date field. Only users that never connected or who interacted with this instance "
+  @Schema(description = "Filter users based on the SonarLint last connection date field. Only users that never connected or who interacted with this instance "
     + "using SonarLint at or before the date will be returned. The format must be ISO 8601 datetime format (YYYY-MM-DDThh:mm:ss±hhmm)",
     example = "2020-01-01T00:00:00+0100")
   String sonarLintLastConnectionDateTo
index 3c6efc91b4e65f56d61134841cf536989800ca27..0c8ce6ef2119dab55ac87dfc2bea02d0b6cf20a4 100644 (file)
@@ -60,6 +60,7 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.sonar.api.utils.DateUtils.formatDateTime;
+import static org.sonar.api.utils.DateUtils.parseOffsetDateTime;
 import static org.sonar.server.v2.WebApiEndpoints.JSON_MERGE_PATCH_CONTENT_TYPE;
 import static org.sonar.server.v2.WebApiEndpoints.USER_ENDPOINT;
 import static org.sonar.server.v2.api.model.RestPage.DEFAULT_PAGE_INDEX;
@@ -104,6 +105,7 @@ public class DefaultUserControllerTest {
         .param("active", "false")
         .param("managed", "true")
         .param("q", "q")
+        .param("externalIdentity", "externalIdentity")
         .param("sonarQubeLastConnectionDateFrom", "2020-01-01T00:00:00+0100")
         .param("sonarQubeLastConnectionDateTo", "2020-01-01T00:00:00+0100")
         .param("sonarLintLastConnectionDateFrom", "2020-01-01T00:00:00+0100")
@@ -114,9 +116,17 @@ public class DefaultUserControllerTest {
 
     ArgumentCaptor<UsersSearchRequest> requestCaptor = ArgumentCaptor.forClass(UsersSearchRequest.class);
     verify(userService).findUsers(requestCaptor.capture());
+
+    assertThat(requestCaptor.getValue().isDeactivated()).isTrue();
+    assertThat(requestCaptor.getValue().isManaged()).isTrue();
+    assertThat(requestCaptor.getValue().getQuery()).isEqualTo("q");
+    assertThat(requestCaptor.getValue().getExternalLogin()).contains("externalIdentity");
+    assertThat(requestCaptor.getValue().getLastConnectionDateFrom()).contains(parseOffsetDateTime("2020-01-01T00:00:00+0100"));
+    assertThat(requestCaptor.getValue().getLastConnectionDateTo()).contains(parseOffsetDateTime("2020-01-01T00:00:00+0100"));
+    assertThat(requestCaptor.getValue().getSonarLintLastConnectionDateFrom()).contains(parseOffsetDateTime("2020-01-01T00:00:00+0100"));
+    assertThat(requestCaptor.getValue().getSonarLintLastConnectionDateTo()).contains(parseOffsetDateTime("2020-01-01T00:00:00+0100"));
     assertThat(requestCaptor.getValue().getPageSize()).isEqualTo(100);
     assertThat(requestCaptor.getValue().getPage()).isEqualTo(2);
-    assertThat(requestCaptor.getValue().isDeactivated()).isTrue();
   }
 
   @Test
@@ -125,25 +135,31 @@ public class DefaultUserControllerTest {
       .param("sonarQubeLastConnectionDateFrom", "2020-01-01T00:00:00+0100"))
       .andExpectAll(
         status().isForbidden(),
-        content().string("{\"message\":\"parameter sonarQubeLastConnectionDateFrom requires Administer System permission.\"}"));
+        content().string("{\"message\":\"Parameter sonarQubeLastConnectionDateFrom requires Administer System permission.\"}"));
 
     mockMvc.perform(get(USER_ENDPOINT)
       .param("sonarQubeLastConnectionDateTo", "2020-01-01T00:00:00+0100"))
       .andExpectAll(
         status().isForbidden(),
-        content().string("{\"message\":\"parameter sonarQubeLastConnectionDateTo requires Administer System permission.\"}"));
+        content().string("{\"message\":\"Parameter sonarQubeLastConnectionDateTo requires Administer System permission.\"}"));
 
     mockMvc.perform(get(USER_ENDPOINT)
       .param("sonarLintLastConnectionDateFrom", "2020-01-01T00:00:00+0100"))
       .andExpectAll(
         status().isForbidden(),
-        content().string("{\"message\":\"parameter sonarLintLastConnectionDateFrom requires Administer System permission.\"}"));
+        content().string("{\"message\":\"Parameter sonarLintLastConnectionDateFrom requires Administer System permission.\"}"));
 
     mockMvc.perform(get(USER_ENDPOINT)
       .param("sonarLintLastConnectionDateTo", "2020-01-01T00:00:00+0100"))
       .andExpectAll(
         status().isForbidden(),
-        content().string("{\"message\":\"parameter sonarLintLastConnectionDateTo requires Administer System permission.\"}"));
+        content().string("{\"message\":\"Parameter sonarLintLastConnectionDateTo requires Administer System permission.\"}"));
+
+    mockMvc.perform(get(USER_ENDPOINT)
+        .param("externalIdentity", "externalIdentity"))
+      .andExpectAll(
+        status().isForbidden(),
+        content().string("{\"message\":\"Parameter externalIdentity requires Administer System permission.\"}"));
   }
 
   @Test