mirror of https://github.com/halo-dev/halo
Add custom endpoint for listing user conditionally (#3320)
#### What type of PR is this? /kind bug #### What this PR does / why we need it: 为后端用户管理提供更多筛选接口,包括关键词、角色、创建时间排序 #### Which issue(s) this PR fixes: Fixes #3290 ```release-note NONE ```pull/3345/head
parent
3cde340b71
commit
7c075dc5d7
|
@ -1,19 +1,31 @@
|
||||||
package run.halo.app.core.extension.endpoint;
|
package run.halo.app.core.extension.endpoint;
|
||||||
|
|
||||||
|
import static java.util.Comparator.comparing;
|
||||||
import static org.springdoc.core.fn.builders.apiresponse.Builder.responseBuilder;
|
import static org.springdoc.core.fn.builders.apiresponse.Builder.responseBuilder;
|
||||||
import static org.springdoc.core.fn.builders.parameter.Builder.parameterBuilder;
|
import static org.springdoc.core.fn.builders.parameter.Builder.parameterBuilder;
|
||||||
import static org.springdoc.core.fn.builders.requestbody.Builder.requestBodyBuilder;
|
import static org.springdoc.core.fn.builders.requestbody.Builder.requestBodyBuilder;
|
||||||
|
import static run.halo.app.extension.ListResult.generateGenericClass;
|
||||||
|
import static run.halo.app.extension.router.QueryParamBuildUtil.buildParametersFromType;
|
||||||
|
import static run.halo.app.extension.router.selector.SelectorUtil.labelAndFieldSelectorToPredicate;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
import io.micrometer.common.util.StringUtils;
|
import io.micrometer.common.util.StringUtils;
|
||||||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||||
|
import io.swagger.v3.oas.annotations.media.ArraySchema;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import org.springdoc.webflux.core.fn.SpringdocRouteBuilder;
|
import org.springdoc.webflux.core.fn.SpringdocRouteBuilder;
|
||||||
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.lang.NonNull;
|
import org.springframework.lang.NonNull;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
|
@ -23,14 +35,17 @@ import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.reactive.function.server.RouterFunction;
|
import org.springframework.web.reactive.function.server.RouterFunction;
|
||||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
import org.springframework.web.server.ServerWebInputException;
|
import org.springframework.web.server.ServerWebInputException;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import run.halo.app.core.extension.Role;
|
import run.halo.app.core.extension.Role;
|
||||||
import run.halo.app.core.extension.User;
|
import run.halo.app.core.extension.User;
|
||||||
import run.halo.app.core.extension.service.UserService;
|
import run.halo.app.core.extension.service.UserService;
|
||||||
|
import run.halo.app.extension.Comparators;
|
||||||
import run.halo.app.extension.ReactiveExtensionClient;
|
import run.halo.app.extension.ReactiveExtensionClient;
|
||||||
import run.halo.app.extension.exception.ExtensionNotFoundException;
|
import run.halo.app.extension.exception.ExtensionNotFoundException;
|
||||||
|
import run.halo.app.extension.router.IListRequest;
|
||||||
import run.halo.app.infra.exception.UserNotFoundException;
|
import run.halo.app.infra.exception.UserNotFoundException;
|
||||||
import run.halo.app.infra.utils.JsonUtils;
|
import run.halo.app.infra.utils.JsonUtils;
|
||||||
|
|
||||||
|
@ -94,6 +109,13 @@ public class UserEndpoint implements CustomEndpoint {
|
||||||
.response(responseBuilder()
|
.response(responseBuilder()
|
||||||
.implementation(User.class))
|
.implementation(User.class))
|
||||||
)
|
)
|
||||||
|
.GET("users", this::list, builder -> {
|
||||||
|
builder.operationId("ListUsers")
|
||||||
|
.tag(tag)
|
||||||
|
.description("List users")
|
||||||
|
.response(responseBuilder().implementation(generateGenericClass(User.class)));
|
||||||
|
buildParametersFromType(builder, ListRequest.class);
|
||||||
|
})
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,4 +246,104 @@ public class UserEndpoint implements CustomEndpoint {
|
||||||
record UserPermission(@Schema(required = true) Set<Role> roles,
|
record UserPermission(@Schema(required = true) Set<Role> roles,
|
||||||
@Schema(required = true) Set<String> uiPermissions) {
|
@Schema(required = true) Set<String> uiPermissions) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ListRequest extends IListRequest.QueryListRequest {
|
||||||
|
|
||||||
|
private final ServerWebExchange exchange;
|
||||||
|
|
||||||
|
public ListRequest(ServerRequest request) {
|
||||||
|
super(request.queryParams());
|
||||||
|
this.exchange = request.exchange();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Schema(name = "keyword")
|
||||||
|
public String getKeyword() {
|
||||||
|
return queryParams.getFirst("keyword");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Schema(name = "role")
|
||||||
|
public String getRole() {
|
||||||
|
return queryParams.getFirst("role");
|
||||||
|
}
|
||||||
|
|
||||||
|
@ArraySchema(uniqueItems = true,
|
||||||
|
arraySchema = @Schema(name = "sort",
|
||||||
|
description = "Sort property and direction of the list result. Supported fields: "
|
||||||
|
+ "creationTimestamp"),
|
||||||
|
schema = @Schema(description = "like field,asc or field,desc",
|
||||||
|
implementation = String.class,
|
||||||
|
example = "creationTimestamp,desc"))
|
||||||
|
public Sort getSort() {
|
||||||
|
return SortResolver.defaultInstance.resolve(exchange);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Predicate<User> toPredicate() {
|
||||||
|
Predicate<User> displayNamePredicate = user -> {
|
||||||
|
var keyword = getKeyword();
|
||||||
|
if (!org.springframework.util.StringUtils.hasText(keyword)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
var displayName = user.getSpec().getDisplayName();
|
||||||
|
if (!org.springframework.util.StringUtils.hasText(displayName)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return displayName.toLowerCase().contains(keyword.trim().toLowerCase());
|
||||||
|
};
|
||||||
|
Predicate<User> rolePredicate = user -> {
|
||||||
|
var role = getRole();
|
||||||
|
if (role == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
var annotations = user.getMetadata().getAnnotations();
|
||||||
|
if (annotations == null || !annotations.containsKey(User.ROLE_NAMES_ANNO)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
Pattern pattern = Pattern.compile("\\[\"([^\"]*)\"\\]");
|
||||||
|
Matcher matcher = pattern.matcher(annotations.get(User.ROLE_NAMES_ANNO));
|
||||||
|
if (matcher.find()) {
|
||||||
|
return matcher.group(1).equals(role);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return displayNamePredicate
|
||||||
|
.and(rolePredicate)
|
||||||
|
.and(labelAndFieldSelectorToPredicate(getLabelSelector(), getFieldSelector()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Comparator<User> toComparator() {
|
||||||
|
var sort = getSort();
|
||||||
|
var ctOrder = sort.getOrderFor("creationTimestamp");
|
||||||
|
List<Comparator<User>> comparators = new ArrayList<>();
|
||||||
|
if (ctOrder != null) {
|
||||||
|
Comparator<User> comparator =
|
||||||
|
comparing(user -> user.getMetadata().getCreationTimestamp());
|
||||||
|
if (ctOrder.isDescending()) {
|
||||||
|
comparator = comparator.reversed();
|
||||||
|
}
|
||||||
|
comparators.add(comparator);
|
||||||
|
}
|
||||||
|
comparators.add(Comparators.compareCreationTimestamp(false));
|
||||||
|
comparators.add(Comparators.compareName(true));
|
||||||
|
return comparators.stream()
|
||||||
|
.reduce(Comparator::thenComparing)
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Mono<ServerResponse> list(ServerRequest request) {
|
||||||
|
return Mono.just(request)
|
||||||
|
.map(UserEndpoint.ListRequest::new)
|
||||||
|
.flatMap(listRequest -> {
|
||||||
|
var predicate = listRequest.toPredicate();
|
||||||
|
var comparator = listRequest.toComparator();
|
||||||
|
return client.list(User.class,
|
||||||
|
predicate,
|
||||||
|
comparator,
|
||||||
|
listRequest.getPage(),
|
||||||
|
listRequest.getSize());
|
||||||
|
})
|
||||||
|
.flatMap(listResult -> ServerResponse.ok().bodyValue(listResult));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package run.halo.app.core.extension.endpoint;
|
package run.halo.app.core.extension.endpoint;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.ArgumentMatchers.argThat;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.ArgumentMatchers.same;
|
import static org.mockito.ArgumentMatchers.same;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
|
@ -8,15 +10,20 @@ import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.csrf;
|
import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.csrf;
|
||||||
|
import static org.springframework.test.web.reactive.server.WebTestClient.bindToRouterFunction;
|
||||||
import static run.halo.app.extension.GroupVersionKind.fromExtension;
|
import static run.halo.app.extension.GroupVersionKind.fromExtension;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.DisplayName;
|
import org.junit.jupiter.api.DisplayName;
|
||||||
import org.junit.jupiter.api.Nested;
|
import org.junit.jupiter.api.Nested;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
|
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
@ -30,6 +37,7 @@ import run.halo.app.core.extension.RoleBinding;
|
||||||
import run.halo.app.core.extension.User;
|
import run.halo.app.core.extension.User;
|
||||||
import run.halo.app.core.extension.service.RoleService;
|
import run.halo.app.core.extension.service.RoleService;
|
||||||
import run.halo.app.core.extension.service.UserService;
|
import run.halo.app.core.extension.service.UserService;
|
||||||
|
import run.halo.app.extension.ListResult;
|
||||||
import run.halo.app.extension.Metadata;
|
import run.halo.app.extension.Metadata;
|
||||||
import run.halo.app.extension.ReactiveExtensionClient;
|
import run.halo.app.extension.ReactiveExtensionClient;
|
||||||
import run.halo.app.extension.exception.ExtensionNotFoundException;
|
import run.halo.app.extension.exception.ExtensionNotFoundException;
|
||||||
|
@ -40,18 +48,20 @@ import run.halo.app.infra.utils.JsonUtils;
|
||||||
@WithMockUser(username = "fake-user", password = "fake-password", roles = "fake-super-role")
|
@WithMockUser(username = "fake-user", password = "fake-password", roles = "fake-super-role")
|
||||||
class UserEndpointTest {
|
class UserEndpointTest {
|
||||||
|
|
||||||
@Autowired
|
|
||||||
WebTestClient webClient;
|
WebTestClient webClient;
|
||||||
|
|
||||||
@MockBean
|
@MockBean
|
||||||
RoleService roleService;
|
RoleService roleService;
|
||||||
|
|
||||||
@MockBean
|
@Mock
|
||||||
ReactiveExtensionClient client;
|
ReactiveExtensionClient client;
|
||||||
|
|
||||||
@MockBean
|
@Mock
|
||||||
UserService userService;
|
UserService userService;
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
UserEndpoint endpoint;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() {
|
void setUp() {
|
||||||
// disable authorization
|
// disable authorization
|
||||||
|
@ -63,9 +73,199 @@ class UserEndpointTest {
|
||||||
var role = new Role();
|
var role = new Role();
|
||||||
role.setRules(List.of(rule));
|
role.setRules(List.of(rule));
|
||||||
when(roleService.getMonoRole("authenticated")).thenReturn(Mono.just(role));
|
when(roleService.getMonoRole("authenticated")).thenReturn(Mono.just(role));
|
||||||
|
webClient = WebTestClient.bindToRouterFunction(endpoint.endpoint())
|
||||||
|
.build();
|
||||||
webClient = webClient.mutateWith(csrf());
|
webClient = webClient.mutateWith(csrf());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
class UserListTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldListEmptyUsersWhenNoUsers() {
|
||||||
|
when(client.list(same(User.class), any(), any(), anyInt(), anyInt()))
|
||||||
|
.thenReturn(Mono.just(ListResult.emptyResult()));
|
||||||
|
|
||||||
|
bindToRouterFunction(endpoint.endpoint())
|
||||||
|
.build()
|
||||||
|
.get().uri("/users")
|
||||||
|
.exchange()
|
||||||
|
.expectStatus().isOk()
|
||||||
|
.expectBody()
|
||||||
|
.jsonPath("$.items.length()").isEqualTo(0)
|
||||||
|
.jsonPath("$.total").isEqualTo(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldListUsersWhenUserPresent() {
|
||||||
|
var users = List.of(
|
||||||
|
createUser("fake-user-1"),
|
||||||
|
createUser("fake-user-2"),
|
||||||
|
createUser("fake-user-3")
|
||||||
|
);
|
||||||
|
var expectResult = new ListResult<>(users);
|
||||||
|
when(client.list(same(User.class), any(), any(), anyInt(), anyInt()))
|
||||||
|
.thenReturn(Mono.just(expectResult));
|
||||||
|
|
||||||
|
bindToRouterFunction(endpoint.endpoint())
|
||||||
|
.build()
|
||||||
|
.get().uri("/users")
|
||||||
|
.exchange()
|
||||||
|
.expectStatus().isOk()
|
||||||
|
.expectBody()
|
||||||
|
.jsonPath("$.items.length()").isEqualTo(3)
|
||||||
|
.jsonPath("$.total").isEqualTo(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldFilterUsersWhenKeywordProvided() {
|
||||||
|
var expectUser =
|
||||||
|
createUser("fake-user-2", "expected display name");
|
||||||
|
var unexpectedUser1 =
|
||||||
|
createUser("fake-user-1", "first fake display name");
|
||||||
|
var unexpectedUser2 =
|
||||||
|
createUser("fake-user-3", "second fake display name");
|
||||||
|
var users = List.of(
|
||||||
|
expectUser
|
||||||
|
);
|
||||||
|
var expectResult = new ListResult<>(users);
|
||||||
|
when(client.list(same(User.class), any(), any(), anyInt(), anyInt()))
|
||||||
|
.thenReturn(Mono.just(expectResult));
|
||||||
|
|
||||||
|
bindToRouterFunction(endpoint.endpoint())
|
||||||
|
.build()
|
||||||
|
.get().uri("/users?keyword=Expected")
|
||||||
|
.exchange()
|
||||||
|
.expectStatus().isOk();
|
||||||
|
|
||||||
|
verify(client).list(same(User.class), argThat(
|
||||||
|
predicate -> predicate.test(expectUser)
|
||||||
|
&& !predicate.test(unexpectedUser1)
|
||||||
|
&& !predicate.test(unexpectedUser2)),
|
||||||
|
any(), anyInt(), anyInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldFilterUsersWhenRoleProvided() {
|
||||||
|
var expectUser =
|
||||||
|
JsonUtils.jsonToObject("""
|
||||||
|
{
|
||||||
|
"apiVersion": "v1alpha1",
|
||||||
|
"kind": "User",
|
||||||
|
"metadata": {
|
||||||
|
"name": "alice",
|
||||||
|
"annotations": {
|
||||||
|
"rbac.authorization.halo.run/role-names": "[\\"guest\\"]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""", User.class);
|
||||||
|
var unexpectedUser1 =
|
||||||
|
JsonUtils.jsonToObject("""
|
||||||
|
{
|
||||||
|
"apiVersion": "v1alpha1",
|
||||||
|
"kind": "User",
|
||||||
|
"metadata": {
|
||||||
|
"name": "admin",
|
||||||
|
"annotations": {
|
||||||
|
"rbac.authorization.halo.run/role-names": "[\\"super-role\\"]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""", User.class);
|
||||||
|
var unexpectedUser2 =
|
||||||
|
JsonUtils.jsonToObject("""
|
||||||
|
{
|
||||||
|
"apiVersion": "v1alpha1",
|
||||||
|
"kind": "User",
|
||||||
|
"metadata": {
|
||||||
|
"name": "joey",
|
||||||
|
"annotations": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""", User.class);
|
||||||
|
var users = List.of(
|
||||||
|
expectUser
|
||||||
|
);
|
||||||
|
var expectResult = new ListResult<>(users);
|
||||||
|
when(client.list(same(User.class), any(), any(), anyInt(), anyInt()))
|
||||||
|
.thenReturn(Mono.just(expectResult));
|
||||||
|
|
||||||
|
bindToRouterFunction(endpoint.endpoint())
|
||||||
|
.build()
|
||||||
|
.get().uri("/users?role=guest")
|
||||||
|
.exchange()
|
||||||
|
.expectStatus().isOk();
|
||||||
|
|
||||||
|
verify(client).list(same(User.class), argThat(
|
||||||
|
predicate -> predicate.test(expectUser)
|
||||||
|
&& !predicate.test(unexpectedUser1)
|
||||||
|
&& !predicate.test(unexpectedUser2)),
|
||||||
|
any(), anyInt(), anyInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldSortUsersWhenCreationTimestampSet() {
|
||||||
|
var expectUser =
|
||||||
|
createUser("fake-user-2", "expected display name");
|
||||||
|
var unexpectedUser1 =
|
||||||
|
createUser("fake-user-1", "first fake display name");
|
||||||
|
var unexpectedUser2 =
|
||||||
|
createUser("fake-user-3", "second fake display name");
|
||||||
|
var expectResult = new ListResult<>(List.of(expectUser));
|
||||||
|
when(client.list(same(User.class), any(), any(), anyInt(), anyInt()))
|
||||||
|
.thenReturn(Mono.just(expectResult));
|
||||||
|
|
||||||
|
bindToRouterFunction(endpoint.endpoint())
|
||||||
|
.build()
|
||||||
|
.get().uri("/users?sort=creationTimestamp,desc")
|
||||||
|
.exchange()
|
||||||
|
.expectStatus().isOk();
|
||||||
|
|
||||||
|
verify(client).list(same(User.class), any(), argThat(comparator -> {
|
||||||
|
var now = Instant.now();
|
||||||
|
var users = new ArrayList<>(List.of(
|
||||||
|
createUser("fake-user-a", now),
|
||||||
|
createUser("fake-user-b", now.plusSeconds(1)),
|
||||||
|
createUser("fake-user-c", now.plusSeconds(2))
|
||||||
|
));
|
||||||
|
users.sort(comparator);
|
||||||
|
return Objects.deepEquals(users, List.of(
|
||||||
|
createUser("fake-user-c", now.plusSeconds(2)),
|
||||||
|
createUser("fake-user-b", now.plusSeconds(1)),
|
||||||
|
createUser("fake-user-a", now)
|
||||||
|
));
|
||||||
|
}), anyInt(), anyInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
User createUser(String name) {
|
||||||
|
return createUser(name, "fake display name");
|
||||||
|
}
|
||||||
|
|
||||||
|
User createUser(String name, String displayName) {
|
||||||
|
var metadata = new Metadata();
|
||||||
|
metadata.setName(name);
|
||||||
|
metadata.setCreationTimestamp(Instant.now());
|
||||||
|
var spec = new User.UserSpec();
|
||||||
|
spec.setDisplayName(displayName);
|
||||||
|
var user = new User();
|
||||||
|
user.setMetadata(metadata);
|
||||||
|
user.setSpec(spec);
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
User createUser(String name, Instant creationTimestamp) {
|
||||||
|
var metadata = new Metadata();
|
||||||
|
metadata.setName(name);
|
||||||
|
metadata.setCreationTimestamp(creationTimestamp);
|
||||||
|
var spec = new User.UserSpec();
|
||||||
|
var user = new User();
|
||||||
|
user.setMetadata(metadata);
|
||||||
|
user.setSpec(spec);
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@DisplayName("GetUserDetail")
|
@DisplayName("GetUserDetail")
|
||||||
class GetUserDetailTest {
|
class GetUserDetailTest {
|
||||||
|
@ -75,7 +275,7 @@ class UserEndpointTest {
|
||||||
when(client.get(User.class, "fake-user"))
|
when(client.get(User.class, "fake-user"))
|
||||||
.thenReturn(Mono.error(
|
.thenReturn(Mono.error(
|
||||||
new ExtensionNotFoundException(fromExtension(User.class), "fake-user")));
|
new ExtensionNotFoundException(fromExtension(User.class), "fake-user")));
|
||||||
webClient.get().uri("/apis/api.console.halo.run/v1alpha1/users/-")
|
webClient.get().uri("/users/-")
|
||||||
.exchange()
|
.exchange()
|
||||||
.expectStatus().isNotFound();
|
.expectStatus().isNotFound();
|
||||||
|
|
||||||
|
@ -89,7 +289,7 @@ class UserEndpointTest {
|
||||||
var user = new User();
|
var user = new User();
|
||||||
user.setMetadata(metadata);
|
user.setMetadata(metadata);
|
||||||
when(client.get(User.class, "fake-user")).thenReturn(Mono.just(user));
|
when(client.get(User.class, "fake-user")).thenReturn(Mono.just(user));
|
||||||
webClient.get().uri("/apis/api.console.halo.run/v1alpha1/users/-")
|
webClient.get().uri("/users/-")
|
||||||
.exchange()
|
.exchange()
|
||||||
.expectStatus().isOk()
|
.expectStatus().isOk()
|
||||||
.expectHeader().contentType(MediaType.APPLICATION_JSON)
|
.expectHeader().contentType(MediaType.APPLICATION_JSON)
|
||||||
|
@ -111,7 +311,7 @@ class UserEndpointTest {
|
||||||
when(client.get(User.class, "fake-user")).thenReturn(Mono.just(currentUser));
|
when(client.get(User.class, "fake-user")).thenReturn(Mono.just(currentUser));
|
||||||
when(client.update(currentUser)).thenReturn(Mono.just(updatedUser));
|
when(client.update(currentUser)).thenReturn(Mono.just(updatedUser));
|
||||||
|
|
||||||
webClient.put().uri("/apis/api.console.halo.run/v1alpha1/users/-")
|
webClient.put().uri("/users/-")
|
||||||
.bodyValue(requestUser)
|
.bodyValue(requestUser)
|
||||||
.exchange()
|
.exchange()
|
||||||
.expectStatus().isOk()
|
.expectStatus().isOk()
|
||||||
|
@ -131,7 +331,7 @@ class UserEndpointTest {
|
||||||
when(client.get(User.class, "fake-user")).thenReturn(Mono.just(currentUser));
|
when(client.get(User.class, "fake-user")).thenReturn(Mono.just(currentUser));
|
||||||
when(client.update(currentUser)).thenReturn(Mono.just(updatedUser));
|
when(client.update(currentUser)).thenReturn(Mono.just(updatedUser));
|
||||||
|
|
||||||
webClient.put().uri("/apis/api.console.halo.run/v1alpha1/users/-")
|
webClient.put().uri("/users/-")
|
||||||
.bodyValue(requestUser)
|
.bodyValue(requestUser)
|
||||||
.exchange()
|
.exchange()
|
||||||
.expectStatus().isBadRequest();
|
.expectStatus().isBadRequest();
|
||||||
|
@ -166,7 +366,7 @@ class UserEndpointTest {
|
||||||
var user = new User();
|
var user = new User();
|
||||||
when(userService.updateWithRawPassword("fake-user", "new-password"))
|
when(userService.updateWithRawPassword("fake-user", "new-password"))
|
||||||
.thenReturn(Mono.just(user));
|
.thenReturn(Mono.just(user));
|
||||||
webClient.put().uri("/apis/api.console.halo.run/v1alpha1/users/-/password")
|
webClient.put().uri("/users/-/password")
|
||||||
.bodyValue(new UserEndpoint.ChangePasswordRequest("new-password"))
|
.bodyValue(new UserEndpoint.ChangePasswordRequest("new-password"))
|
||||||
.exchange()
|
.exchange()
|
||||||
.expectStatus().isOk()
|
.expectStatus().isOk()
|
||||||
|
@ -182,7 +382,7 @@ class UserEndpointTest {
|
||||||
when(userService.updateWithRawPassword("another-fake-user", "new-password"))
|
when(userService.updateWithRawPassword("another-fake-user", "new-password"))
|
||||||
.thenReturn(Mono.just(user));
|
.thenReturn(Mono.just(user));
|
||||||
webClient.put()
|
webClient.put()
|
||||||
.uri("/apis/api.console.halo.run/v1alpha1/users/another-fake-user/password")
|
.uri("/users/another-fake-user/password")
|
||||||
.bodyValue(new UserEndpoint.ChangePasswordRequest("new-password"))
|
.bodyValue(new UserEndpoint.ChangePasswordRequest("new-password"))
|
||||||
.exchange()
|
.exchange()
|
||||||
.expectStatus().isOk()
|
.expectStatus().isOk()
|
||||||
|
@ -209,7 +409,7 @@ class UserEndpointTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldGetBadRequestIfRequestBodyIsEmpty() {
|
void shouldGetBadRequestIfRequestBodyIsEmpty() {
|
||||||
webClient.post().uri("/apis/api.console.halo.run/v1alpha1/users/fake-user/permissions")
|
webClient.post().uri("/users/fake-user/permissions")
|
||||||
.contentType(MediaType.APPLICATION_JSON)
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
.exchange()
|
.exchange()
|
||||||
.expectStatus().isBadRequest();
|
.expectStatus().isBadRequest();
|
||||||
|
@ -223,7 +423,7 @@ class UserEndpointTest {
|
||||||
void shouldGrantPermission() {
|
void shouldGrantPermission() {
|
||||||
when(userService.grantRoles("fake-user", Set.of("fake-role"))).thenReturn(Mono.empty());
|
when(userService.grantRoles("fake-user", Set.of("fake-role"))).thenReturn(Mono.empty());
|
||||||
|
|
||||||
webClient.post().uri("/apis/api.console.halo.run/v1alpha1/users/fake-user/permissions")
|
webClient.post().uri("/users/fake-user/permissions")
|
||||||
.contentType(MediaType.APPLICATION_JSON)
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
.bodyValue(new UserEndpoint.GrantRequest(Set.of("fake-role")))
|
.bodyValue(new UserEndpoint.GrantRequest(Set.of("fake-role")))
|
||||||
.exchange()
|
.exchange()
|
||||||
|
@ -250,7 +450,7 @@ class UserEndpointTest {
|
||||||
when(userService.listRoles(eq("fake-user"))).thenReturn(
|
when(userService.listRoles(eq("fake-user"))).thenReturn(
|
||||||
Flux.fromIterable(List.of(roleA)));
|
Flux.fromIterable(List.of(roleA)));
|
||||||
|
|
||||||
webClient.get().uri("/apis/api.console.halo.run/v1alpha1/users/fake-user/permissions")
|
webClient.get().uri("/users/fake-user/permissions")
|
||||||
.exchange()
|
.exchange()
|
||||||
.expectStatus()
|
.expectStatus()
|
||||||
.isOk()
|
.isOk()
|
||||||
|
|
Loading…
Reference in New Issue