From 56d2c712d5d203dcd2f3c73b24409fea1b25d975 Mon Sep 17 00:00:00 2001 From: guillaume-peoch-sonarsource Date: Wed, 16 Aug 2023 17:44:38 +0200 Subject: [PATCH] SONAR-20181 FE - Rename pageRestResponse to page --- .../main/js/api/mocks/IssuesServiceMock.ts | 2 +- .../api/mocks/SecurityHotspotServiceMock.ts | 2 +- .../src/main/js/api/mocks/UsersServiceMock.ts | 10 +++--- server/sonar-web/src/main/js/api/users.ts | 2 +- .../src/main/js/apps/issues/utils.ts | 4 +-- server/sonar-web/src/main/js/queries/users.ts | 2 +- .../api/user/controller/UserController.java | 16 ++++----- .../server/v2/api/user/model/RestUser.java | 3 ++ .../controller/DefaultUserControllerTest.java | 33 ++++++++++++++----- 9 files changed, 47 insertions(+), 27 deletions(-) diff --git a/server/sonar-web/src/main/js/api/mocks/IssuesServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/IssuesServiceMock.ts index f40177f5444..bef870b1222 100644 --- a/server/sonar-web/src/main/js/api/mocks/IssuesServiceMock.ts +++ b/server/sonar-web/src/main/js/api/mocks/IssuesServiceMock.ts @@ -625,7 +625,7 @@ export default class IssuesServiceMock { handleGetUsers = () => { return this.reply({ - pageRestResponse: mockPaging(), + page: mockPaging(), users: [mockLoggedInUser() as unknown as RestUser], }); }; diff --git a/server/sonar-web/src/main/js/api/mocks/SecurityHotspotServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/SecurityHotspotServiceMock.ts index 6124747de14..c0f2194865d 100644 --- a/server/sonar-web/src/main/js/api/mocks/SecurityHotspotServiceMock.ts +++ b/server/sonar-web/src/main/js/api/mocks/SecurityHotspotServiceMock.ts @@ -127,7 +127,7 @@ export default class SecurityHotspotServiceMock { mockRestUser({ name: 'User Doe', login: 'user.doe' }), mockRestUser({ name: 'User Foo', login: 'user.foo' }), ], - pageRestResponse: mockPaging(), + page: mockPaging(), }); }; diff --git a/server/sonar-web/src/main/js/api/mocks/UsersServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/UsersServiceMock.ts index caca8dd61dc..13b5e1e0d0c 100644 --- a/server/sonar-web/src/main/js/api/mocks/UsersServiceMock.ts +++ b/server/sonar-web/src/main/js/api/mocks/UsersServiceMock.ts @@ -207,14 +207,14 @@ export default class UsersServiceMock { }; handleGetUsers: typeof getUsers = (data) => { - let pageRestResponse = { + let page = { pageIndex: 1, pageSize: 0, total: 10, }; - if (data.pageIndex !== undefined && data.pageIndex !== pageRestResponse.pageIndex) { - pageRestResponse = { pageIndex: 2, pageSize: 2, total: 10 }; + if (data.pageIndex !== undefined && data.pageIndex !== page.pageIndex) { + page = { pageIndex: 2, pageSize: 2, total: 10 }; const users = [ mockRestUser({ name: `Local User ${this.users.length + 4}`, @@ -226,7 +226,7 @@ export default class UsersServiceMock { }), ]; - return this.reply({ pageRestResponse, users }); + return this.reply({ page, users }); } const users = this.getFilteredRestUsers({ @@ -239,7 +239,7 @@ export default class UsersServiceMock { }); return this.reply({ - pageRestResponse: { + page: { pageIndex: 1, pageSize: users.length, total: 10, diff --git a/server/sonar-web/src/main/js/api/users.ts b/server/sonar-web/src/main/js/api/users.ts index e9e8ea5a800..754da05a7d5 100644 --- a/server/sonar-web/src/main/js/api/users.ts +++ b/server/sonar-web/src/main/js/api/users.ts @@ -92,7 +92,7 @@ export function getUsers(data: { sonarLintLastConnectionDateTo?: string; pageSize?: number; pageIndex?: number; -}): Promise<{ pageRestResponse: Paging; users: T[] }> { +}): Promise<{ page: Paging; users: T[] }> { return getJSON('/api/v2/users', data).catch(throwGlobalError); } diff --git a/server/sonar-web/src/main/js/apps/issues/utils.ts b/server/sonar-web/src/main/js/apps/issues/utils.ts index 83a0507cc38..57b4fd49565 100644 --- a/server/sonar-web/src/main/js/apps/issues/utils.ts +++ b/server/sonar-web/src/main/js/apps/issues/utils.ts @@ -237,8 +237,8 @@ export const searchAssignees = ( query: string, page = 1 ): Promise<{ paging: Paging; results: RestUser[] }> => { - return getUsers({ pageIndex: page, q: query }).then(({ pageRestResponse, users }) => ({ - paging: pageRestResponse, + return getUsers({ pageIndex: page, q: query }).then(({ page, users }) => ({ + paging: page, results: users, })); }; diff --git a/server/sonar-web/src/main/js/queries/users.ts b/server/sonar-web/src/main/js/queries/users.ts index f74f5730f33..6b1a95e8243 100644 --- a/server/sonar-web/src/main/js/queries/users.ts +++ b/server/sonar-web/src/main/js/queries/users.ts @@ -52,7 +52,7 @@ export function useUsersQueries( return results.reduce( (acc, { data, isLoading }) => ({ users: acc.users.concat(data?.users ?? []), - total: data?.pageRestResponse.total, + total: data?.page.total, isLoading: acc.isLoading || isLoading, }), { users: [] as U[], total: 0, isLoading: false } diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/user/controller/UserController.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/user/controller/UserController.java index 7f99484e96e..2d027f43b85 100644 --- a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/user/controller/UserController.java +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/user/controller/UserController.java @@ -52,15 +52,15 @@ public interface UserController { @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.OK) @Operation(summary = "Users search", description = """ - Get a list of users. By default, only active users are returned.
+ Get a list of users. By default, only active users are returned. The following fields are only returned when user has Administer System permission or for logged-in in user : - 'email' - 'externalIdentity' - 'externalProvider' - 'groups' - 'lastConnectionDate' - 'sonarLintLastConnectionDate' - 'tokensCount'
+ 'email', + 'externalIdentity', + 'externalProvider', + 'groups', + 'lastConnectionDate', + 'sonarLintLastConnectionDate', + 'tokensCount'. Field 'sonarqubeLastConnectionDate' is only updated every hour, so it may not be accurate, for instance when a user authenticates many times in less than one hour. """) UsersSearchRestResponse search( diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/user/model/RestUser.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/user/model/RestUser.java index 3f596ff68c8..bb93cc42542 100644 --- a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/user/model/RestUser.java +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/user/model/RestUser.java @@ -19,5 +19,8 @@ */ package org.sonar.server.v2.api.user.model; +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(implementation = RestUserForAdmins.class) public interface RestUser { } diff --git a/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/user/controller/DefaultUserControllerTest.java b/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/user/controller/DefaultUserControllerTest.java index 4bbf6121539..290f87e10f9 100644 --- a/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/user/controller/DefaultUserControllerTest.java +++ b/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/user/controller/DefaultUserControllerTest.java @@ -20,6 +20,10 @@ package org.sonar.server.v2.api.user.controller; import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -71,7 +75,7 @@ public class DefaultUserControllerTest { private final UsersSearchRestResponseGenerator responseGenerator = mock(UsersSearchRestResponseGenerator.class); private final MockMvc mockMvc = ControllerTester.getMockMvc(new DefaultUserController(userSession, userService, responseGenerator)); - private static final Gson gson = new Gson(); + private static final Gson gson = new GsonBuilder().registerTypeAdapter(RestUser.class, new RestUserDeserializer()).create(); @Test public void search_whenNoParameters_shouldUseDefaultAndForwardToUserService() throws Exception { @@ -114,25 +118,25 @@ public class DefaultUserControllerTest { @Test public void search_whenAdminParametersUsedButNotAdmin_shouldFail() throws Exception { mockMvc.perform(get(USER_ENDPOINT) - .param("sonarQubeLastConnectionDateFrom", "2020-01-01T00:00:00+0100")) + .param("sonarQubeLastConnectionDateFrom", "2020-01-01T00:00:00+0100")) .andExpectAll( status().isForbidden(), content().string("{\"message\":\"parameter sonarQubeLastConnectionDateFrom requires Administer System permission.\"}")); mockMvc.perform(get(USER_ENDPOINT) - .param("sonarQubeLastConnectionDateTo", "2020-01-01T00:00:00+0100")) + .param("sonarQubeLastConnectionDateTo", "2020-01-01T00:00:00+0100")) .andExpectAll( status().isForbidden(), content().string("{\"message\":\"parameter sonarQubeLastConnectionDateTo requires Administer System permission.\"}")); mockMvc.perform(get(USER_ENDPOINT) - .param("sonarLintLastConnectionDateFrom", "2020-01-01T00:00:00+0100")) + .param("sonarLintLastConnectionDateFrom", "2020-01-01T00:00:00+0100")) .andExpectAll( status().isForbidden(), content().string("{\"message\":\"parameter sonarLintLastConnectionDateFrom requires Administer System permission.\"}")); mockMvc.perform(get(USER_ENDPOINT) - .param("sonarLintLastConnectionDateTo", "2020-01-01T00:00:00+0100")) + .param("sonarLintLastConnectionDateTo", "2020-01-01T00:00:00+0100")) .andExpectAll( status().isForbidden(), content().string("{\"message\":\"parameter sonarLintLastConnectionDateTo requires Administer System permission.\"}")); @@ -162,6 +166,19 @@ public class DefaultUserControllerTest { } + static class RestUserDeserializer extends TypeAdapter { + + @Override + public void write(JsonWriter out, RestUser value) { + throw new IllegalStateException("not implemented"); + } + + @Override + public RestUser read(JsonReader reader) { + return gson.fromJson(reader, RestUserForAdmins.class); + } + } + private UserSearchResult generateUserSearchResult(String id, boolean active, boolean local, boolean managed, int groupsCount, int tokensCount) { UserDto userDto = new UserDto() .setLogin("login_" + id) @@ -311,9 +328,9 @@ public class DefaultUserControllerTest { userSession.logIn().setNonSystemAdministrator(); mockMvc.perform( - post(USER_ENDPOINT) - .contentType(MediaType.APPLICATION_JSON_VALUE) - .content(gson.toJson(new UserCreateRestRequest(null, null, "login", "name", null, null)))) + post(USER_ENDPOINT) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .content(gson.toJson(new UserCreateRestRequest(null, null, "login", "name", null, null)))) .andExpectAll( status().isForbidden(), content().json("{\"message\":\"Insufficient privileges\"}")); -- 2.39.5