mirror of https://github.com/halo-dev/halo
refactor: add custom API for create user (#3803)
#### What type of PR is this? /kind improvement /area core /milestone 2.5.x /kind api-change #### What this PR does / why we need it: 提供自定义 API 用于创建用户账号 简化了创建用户账号需要先创建账号,再分配角色再重置密码的复杂流程。 需要 Console 端适配此 PR #### Which issue(s) this PR fixes: Fixes #2852 #### Does this PR introduce a user-facing change? ```release-note 优化用户账号创建流程 ```pull/3838/head
parent
6ca2cabffb
commit
fc77d51c48
|
@ -2,6 +2,8 @@ package run.halo.app.core.extension.endpoint;
|
||||||
|
|
||||||
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
|
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
|
||||||
import static java.util.Comparator.comparing;
|
import static java.util.Comparator.comparing;
|
||||||
|
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
|
||||||
|
import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
|
||||||
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;
|
||||||
|
@ -13,8 +15,10 @@ import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
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.ArraySchema;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import java.time.Duration;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -28,6 +32,7 @@ import java.util.regex.Pattern;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springdoc.webflux.core.fn.SpringdocRouteBuilder;
|
import org.springdoc.webflux.core.fn.SpringdocRouteBuilder;
|
||||||
|
import org.springframework.dao.OptimisticLockingFailureException;
|
||||||
import org.springframework.data.domain.Sort;
|
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;
|
||||||
|
@ -43,12 +48,14 @@ 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 reactor.util.retry.Retry;
|
||||||
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.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.Comparators;
|
import run.halo.app.extension.Comparators;
|
||||||
import run.halo.app.extension.ListResult;
|
import run.halo.app.extension.ListResult;
|
||||||
|
import run.halo.app.extension.Metadata;
|
||||||
import run.halo.app.extension.MetadataUtil;
|
import run.halo.app.extension.MetadataUtil;
|
||||||
import run.halo.app.extension.ReactiveExtensionClient;
|
import run.halo.app.extension.ReactiveExtensionClient;
|
||||||
import run.halo.app.extension.router.IListRequest;
|
import run.halo.app.extension.router.IListRequest;
|
||||||
|
@ -99,6 +106,14 @@ public class UserEndpoint implements CustomEndpoint {
|
||||||
.required(true)
|
.required(true)
|
||||||
.implementation(GrantRequest.class))
|
.implementation(GrantRequest.class))
|
||||||
.response(responseBuilder().implementation(User.class)))
|
.response(responseBuilder().implementation(User.class)))
|
||||||
|
.POST("/users", this::createUser,
|
||||||
|
builder -> builder.operationId("CreateUser")
|
||||||
|
.description("Creates a new user.")
|
||||||
|
.tag(tag)
|
||||||
|
.requestBody(requestBodyBuilder()
|
||||||
|
.required(true)
|
||||||
|
.implementation(CreateUserRequest.class))
|
||||||
|
.response(responseBuilder().implementation(User.class)))
|
||||||
.GET("/users/{name}/permissions", this::getUserPermission,
|
.GET("/users/{name}/permissions", this::getUserPermission,
|
||||||
builder -> builder.operationId("GetPermissions")
|
builder -> builder.operationId("GetPermissions")
|
||||||
.description("Get permissions of user")
|
.description("Get permissions of user")
|
||||||
|
@ -133,13 +148,77 @@ public class UserEndpoint implements CustomEndpoint {
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Mono<ServerResponse> createUser(ServerRequest request) {
|
||||||
|
return request.bodyToMono(CreateUserRequest.class)
|
||||||
|
.doOnNext(createUserRequest -> {
|
||||||
|
if (StringUtils.isBlank(createUserRequest.name())) {
|
||||||
|
throw new ServerWebInputException("Name is required");
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(createUserRequest.email())) {
|
||||||
|
throw new ServerWebInputException("Email is required");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.flatMap(userRequest -> {
|
||||||
|
User newUser = CreateUserRequest.from(userRequest);
|
||||||
|
return userService.createUser(newUser, userRequest.roles())
|
||||||
|
.then(Mono.defer(() -> userService.updateWithRawPassword(userRequest.name(),
|
||||||
|
userRequest.password()))
|
||||||
|
.retryWhen(Retry.backoff(5, Duration.ofMillis(100))
|
||||||
|
.filter(OptimisticLockingFailureException.class::isInstance)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.flatMap(user -> ServerResponse.ok()
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.bodyValue(user)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private Mono<ServerResponse> getUserByName(ServerRequest request) {
|
private Mono<ServerResponse> getUserByName(ServerRequest request) {
|
||||||
final var name = request.pathVariable("name");
|
final var name = request.pathVariable("name");
|
||||||
return userService.getUser(name)
|
return userService.getUser(name)
|
||||||
.flatMap(this::toDetailedUser)
|
.flatMap(this::toDetailedUser)
|
||||||
.flatMap(user -> ServerResponse.ok()
|
.flatMap(user -> ServerResponse.ok()
|
||||||
.contentType(MediaType.APPLICATION_JSON)
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
.bodyValue(user));
|
.bodyValue(user)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
record CreateUserRequest(@Schema(requiredMode = REQUIRED) String name,
|
||||||
|
@Schema(requiredMode = REQUIRED) String email,
|
||||||
|
String displayName,
|
||||||
|
String avatar,
|
||||||
|
String phone,
|
||||||
|
String password,
|
||||||
|
String bio,
|
||||||
|
Map<String, String> annotations,
|
||||||
|
Set<String> roles) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Creates a new user from {@link CreateUserRequest}.</p>
|
||||||
|
* Note: this method will not set password.
|
||||||
|
*
|
||||||
|
* @param userRequest user request
|
||||||
|
* @return user from request
|
||||||
|
*/
|
||||||
|
public static User from(CreateUserRequest userRequest) {
|
||||||
|
var user = new User();
|
||||||
|
user.setMetadata(new Metadata());
|
||||||
|
user.getMetadata().setName(userRequest.name());
|
||||||
|
user.getMetadata().setAnnotations(new HashMap<>());
|
||||||
|
Map<String, String> annotations =
|
||||||
|
defaultIfNull(userRequest.annotations(), Map.of());
|
||||||
|
user.getMetadata().getAnnotations().putAll(annotations);
|
||||||
|
|
||||||
|
var spec = new User.UserSpec();
|
||||||
|
user.setSpec(spec);
|
||||||
|
spec.setEmail(userRequest.email());
|
||||||
|
spec.setDisplayName(defaultIfBlank(userRequest.displayName(), userRequest.name()));
|
||||||
|
spec.setAvatar(userRequest.avatar());
|
||||||
|
spec.setPhone(userRequest.phone());
|
||||||
|
spec.setBio(userRequest.bio());
|
||||||
|
return user;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<ServerResponse> updateProfile(ServerRequest request) {
|
private Mono<ServerResponse> updateProfile(ServerRequest request) {
|
||||||
|
@ -165,7 +244,8 @@ public class UserEndpoint implements CustomEndpoint {
|
||||||
spec.setEmail(newSpec.getEmail());
|
spec.setEmail(newSpec.getEmail());
|
||||||
spec.setPhone(newSpec.getPhone());
|
spec.setPhone(newSpec.getPhone());
|
||||||
return currentUser;
|
return currentUser;
|
||||||
}))
|
})
|
||||||
|
)
|
||||||
.flatMap(client::update)
|
.flatMap(client::update)
|
||||||
.flatMap(updatedUser -> ServerResponse.ok().bodyValue(updatedUser));
|
.flatMap(updatedUser -> ServerResponse.ok().bodyValue(updatedUser));
|
||||||
}
|
}
|
||||||
|
@ -240,12 +320,6 @@ public class UserEndpoint implements CustomEndpoint {
|
||||||
.then(ServerResponse.ok().build()));
|
.then(ServerResponse.ok().build()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<GrantRequest> checkRoles(GrantRequest request) {
|
|
||||||
return Flux.fromIterable(request.roles)
|
|
||||||
.flatMap(role -> client.get(Role.class, role))
|
|
||||||
.then(Mono.just(request));
|
|
||||||
}
|
|
||||||
|
|
||||||
record GrantRequest(Set<String> roles) {
|
record GrantRequest(Set<String> roles) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,4 +21,6 @@ public interface UserService {
|
||||||
Mono<User> grantRoles(String username, Set<String> roles);
|
Mono<User> grantRoles(String username, Set<String> roles);
|
||||||
|
|
||||||
Mono<User> signUp(User user, String password);
|
Mono<User> signUp(User user, String password);
|
||||||
|
|
||||||
|
Mono<User> createUser(User user, Set<String> roles);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
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;
|
||||||
|
@ -145,12 +146,14 @@ public class UserServiceImpl implements UserService {
|
||||||
}
|
}
|
||||||
String encodedPassword = passwordEncoder.encode(password);
|
String encodedPassword = passwordEncoder.encode(password);
|
||||||
user.getSpec().setPassword(encodedPassword);
|
user.getSpec().setPassword(encodedPassword);
|
||||||
return createNewUser(user, defaultRole);
|
return createUser(user, Set.of(defaultRole));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<User> createNewUser(User user, String defaultRole) {
|
@Override
|
||||||
|
public Mono<User> createUser(User user, Set<String> roleNames) {
|
||||||
Assert.notNull(user, "User must not be null");
|
Assert.notNull(user, "User must not be null");
|
||||||
|
Assert.notNull(roleNames, "Roles must not be null");
|
||||||
return client.fetch(User.class, user.getMetadata().getName())
|
return client.fetch(User.class, user.getMetadata().getName())
|
||||||
.hasElement()
|
.hasElement()
|
||||||
.flatMap(hasUser -> {
|
.flatMap(hasUser -> {
|
||||||
|
@ -160,10 +163,17 @@ public class UserServiceImpl implements UserService {
|
||||||
"problemDetail.user.duplicateName",
|
"problemDetail.user.duplicateName",
|
||||||
new Object[] {user.getMetadata().getName()}));
|
new Object[] {user.getMetadata().getName()}));
|
||||||
}
|
}
|
||||||
return client.create(user)
|
// Check if all roles exist
|
||||||
.flatMap(newUser -> grantRoles(user.getMetadata().getName(),
|
return Flux.fromIterable(roleNames)
|
||||||
Set.of(defaultRole))
|
.flatMap(roleName -> client.fetch(Role.class, roleName)
|
||||||
);
|
.switchIfEmpty(Mono.error(() -> new ServerWebInputException(
|
||||||
});
|
"Role [" + roleName + "] is not found."))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.then();
|
||||||
|
})
|
||||||
|
.then(Mono.defer(() -> client.create(user)
|
||||||
|
.flatMap(newUser -> grantRoles(user.getMetadata().getName(), roleNames)))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,9 @@ rules:
|
||||||
- apiGroups: [ "" ]
|
- apiGroups: [ "" ]
|
||||||
resources: [ "users" ]
|
resources: [ "users" ]
|
||||||
verbs: [ "create", "patch", "update", "delete", "deletecollection" ]
|
verbs: [ "create", "patch", "update", "delete", "deletecollection" ]
|
||||||
|
- apiGroups: [ "api.console.halo.run" ]
|
||||||
|
resources: [ "users", "users/permissions", "users/password" ]
|
||||||
|
verbs: [ "*" ]
|
||||||
---
|
---
|
||||||
apiVersion: v1alpha1
|
apiVersion: v1alpha1
|
||||||
kind: "Role"
|
kind: "Role"
|
||||||
|
|
|
@ -3,6 +3,7 @@ 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.anyInt;
|
||||||
import static org.mockito.ArgumentMatchers.anySet;
|
import static org.mockito.ArgumentMatchers.anySet;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
import static org.mockito.ArgumentMatchers.argThat;
|
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;
|
||||||
|
@ -491,4 +492,24 @@ class UserEndpointTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
@Test
|
||||||
|
void createWhenNameDuplicate() {
|
||||||
|
when(userService.createUser(any(User.class), anySet()))
|
||||||
|
.thenReturn(Mono.just(new User()));
|
||||||
|
when(userService.updateWithRawPassword(anyString(), anyString()))
|
||||||
|
.thenReturn(Mono.just(new User()));
|
||||||
|
var userRequest = new UserEndpoint.CreateUserRequest("fake-user",
|
||||||
|
"fake-email",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
Map.of(),
|
||||||
|
Set.of());
|
||||||
|
webClient.post().uri("/users")
|
||||||
|
.bodyValue(userRequest)
|
||||||
|
.exchange()
|
||||||
|
.expectStatus().isOk();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -458,6 +458,7 @@ class UserServiceImplTest {
|
||||||
|
|
||||||
User fakeUser = fakeSignUpUser("fake-user", "fake-password");
|
User fakeUser = fakeSignUpUser("fake-user", "fake-password");
|
||||||
|
|
||||||
|
when(client.fetch(eq(Role.class), anyString())).thenReturn(Mono.just(new Role()));
|
||||||
when(client.create(any(User.class))).thenReturn(Mono.just(fakeUser));
|
when(client.create(any(User.class))).thenReturn(Mono.just(fakeUser));
|
||||||
UserServiceImpl spyUserService = spy(userService);
|
UserServiceImpl spyUserService = spy(userService);
|
||||||
doReturn(Mono.just(fakeUser)).when(spyUserService).grantRoles(eq("fake-user"),
|
doReturn(Mono.just(fakeUser)).when(spyUserService).grantRoles(eq("fake-user"),
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
"prettier": "prettier --write './src/**/*.{js,jsx,ts,tsx,json,yml,yaml}'",
|
"prettier": "prettier --write './src/**/*.{js,jsx,ts,tsx,json,yml,yaml}'",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
"release": "bumpp",
|
"release": "bumpp",
|
||||||
"gen": "openapi-generator-cli generate -i http://localhost:8090/v3/api-docs/all-api -g typescript-axios -c ./src/.openapi_config.yaml -o ./src --type-mappings='set=Array' && pnpm lint && pnpm prettier"
|
"gen": "openapi-generator-cli generate -i http://localhost:8090/v3/api-docs/all-api -g typescript-axios -c ./src/.openapi_config.yaml -o ./src --type-mappings='set=Array' --skip-validate-spec && pnpm lint && pnpm prettier"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "@halo-dev",
|
"author": "@halo-dev",
|
||||||
|
|
|
@ -89,6 +89,7 @@ models/contributor.ts
|
||||||
models/counter-list.ts
|
models/counter-list.ts
|
||||||
models/counter-request.ts
|
models/counter-request.ts
|
||||||
models/counter.ts
|
models/counter.ts
|
||||||
|
models/create-user-request.ts
|
||||||
models/custom-templates.ts
|
models/custom-templates.ts
|
||||||
models/dashboard-stats.ts
|
models/dashboard-stats.ts
|
||||||
models/detailed-user.ts
|
models/detailed-user.ts
|
||||||
|
@ -118,7 +119,6 @@ models/listed-reply-list.ts
|
||||||
models/listed-reply.ts
|
models/listed-reply.ts
|
||||||
models/listed-single-page-list.ts
|
models/listed-single-page-list.ts
|
||||||
models/listed-single-page.ts
|
models/listed-single-page.ts
|
||||||
models/listed-user-list.ts
|
|
||||||
models/listed-user.ts
|
models/listed-user.ts
|
||||||
models/login-history.ts
|
models/login-history.ts
|
||||||
models/menu-item-list.ts
|
models/menu-item-list.ts
|
||||||
|
@ -201,6 +201,7 @@ models/theme.ts
|
||||||
models/user-connection-list.ts
|
models/user-connection-list.ts
|
||||||
models/user-connection-spec.ts
|
models/user-connection-spec.ts
|
||||||
models/user-connection.ts
|
models/user-connection.ts
|
||||||
|
models/user-endpoint-listed-user-list.ts
|
||||||
models/user-list.ts
|
models/user-list.ts
|
||||||
models/user-permission.ts
|
models/user-permission.ts
|
||||||
models/user-spec.ts
|
models/user-spec.ts
|
||||||
|
|
|
@ -40,14 +40,16 @@ import {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { ChangePasswordRequest } from "../models";
|
import { ChangePasswordRequest } from "../models";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
import { CreateUserRequest } from "../models";
|
||||||
|
// @ts-ignore
|
||||||
import { DetailedUser } from "../models";
|
import { DetailedUser } from "../models";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { GrantRequest } from "../models";
|
import { GrantRequest } from "../models";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { ListedUserList } from "../models";
|
|
||||||
// @ts-ignore
|
|
||||||
import { User } from "../models";
|
import { User } from "../models";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
import { UserEndpointListedUserList } from "../models";
|
||||||
|
// @ts-ignore
|
||||||
import { UserPermission } from "../models";
|
import { UserPermission } from "../models";
|
||||||
/**
|
/**
|
||||||
* ApiConsoleHaloRunV1alpha1UserApi - axios parameter creator
|
* ApiConsoleHaloRunV1alpha1UserApi - axios parameter creator
|
||||||
|
@ -126,6 +128,63 @@ export const ApiConsoleHaloRunV1alpha1UserApiAxiosParamCreator = function (
|
||||||
options: localVarRequestOptions,
|
options: localVarRequestOptions,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Creates a new user.
|
||||||
|
* @param {CreateUserRequest} createUserRequest
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
createUser: async (
|
||||||
|
createUserRequest: CreateUserRequest,
|
||||||
|
options: AxiosRequestConfig = {}
|
||||||
|
): Promise<RequestArgs> => {
|
||||||
|
// verify required parameter 'createUserRequest' is not null or undefined
|
||||||
|
assertParamExists("createUser", "createUserRequest", createUserRequest);
|
||||||
|
const localVarPath = `/apis/api.console.halo.run/v1alpha1/users`;
|
||||||
|
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||||
|
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||||
|
let baseOptions;
|
||||||
|
if (configuration) {
|
||||||
|
baseOptions = configuration.baseOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
const localVarRequestOptions = {
|
||||||
|
method: "POST",
|
||||||
|
...baseOptions,
|
||||||
|
...options,
|
||||||
|
};
|
||||||
|
const localVarHeaderParameter = {} as any;
|
||||||
|
const localVarQueryParameter = {} as any;
|
||||||
|
|
||||||
|
// authentication BasicAuth required
|
||||||
|
// http basic authentication required
|
||||||
|
setBasicAuthToObject(localVarRequestOptions, configuration);
|
||||||
|
|
||||||
|
// authentication BearerAuth required
|
||||||
|
// http bearer authentication required
|
||||||
|
await setBearerAuthToObject(localVarHeaderParameter, configuration);
|
||||||
|
|
||||||
|
localVarHeaderParameter["Content-Type"] = "application/json";
|
||||||
|
|
||||||
|
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||||
|
let headersFromBaseOptions =
|
||||||
|
baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
|
localVarRequestOptions.headers = {
|
||||||
|
...localVarHeaderParameter,
|
||||||
|
...headersFromBaseOptions,
|
||||||
|
...options.headers,
|
||||||
|
};
|
||||||
|
localVarRequestOptions.data = serializeDataIfNeeded(
|
||||||
|
createUserRequest,
|
||||||
|
localVarRequestOptions,
|
||||||
|
configuration
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: toPathString(localVarUrlObj),
|
||||||
|
options: localVarRequestOptions,
|
||||||
|
};
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* Get current user detail
|
* Get current user detail
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
|
@ -348,23 +407,23 @@ export const ApiConsoleHaloRunV1alpha1UserApiAxiosParamCreator = function (
|
||||||
/**
|
/**
|
||||||
* List users
|
* List users
|
||||||
* @param {Array<string>} [sort] Sort property and direction of the list result. Supported fields: creationTimestamp
|
* @param {Array<string>} [sort] Sort property and direction of the list result. Supported fields: creationTimestamp
|
||||||
* @param {string} [keyword]
|
|
||||||
* @param {string} [role]
|
* @param {string} [role]
|
||||||
|
* @param {string} [keyword]
|
||||||
* @param {number} [size] Size of one page. Zero indicates no limit.
|
* @param {number} [size] Size of one page. Zero indicates no limit.
|
||||||
|
* @param {number} [page] The page number. Zero indicates no page.
|
||||||
* @param {Array<string>} [labelSelector] Label selector for filtering.
|
* @param {Array<string>} [labelSelector] Label selector for filtering.
|
||||||
* @param {Array<string>} [fieldSelector] Field selector for filtering.
|
* @param {Array<string>} [fieldSelector] Field selector for filtering.
|
||||||
* @param {number} [page] The page number. Zero indicates no page.
|
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
listUsers: async (
|
listUsers: async (
|
||||||
sort?: Array<string>,
|
sort?: Array<string>,
|
||||||
keyword?: string,
|
|
||||||
role?: string,
|
role?: string,
|
||||||
|
keyword?: string,
|
||||||
size?: number,
|
size?: number,
|
||||||
|
page?: number,
|
||||||
labelSelector?: Array<string>,
|
labelSelector?: Array<string>,
|
||||||
fieldSelector?: Array<string>,
|
fieldSelector?: Array<string>,
|
||||||
page?: number,
|
|
||||||
options: AxiosRequestConfig = {}
|
options: AxiosRequestConfig = {}
|
||||||
): Promise<RequestArgs> => {
|
): Promise<RequestArgs> => {
|
||||||
const localVarPath = `/apis/api.console.halo.run/v1alpha1/users`;
|
const localVarPath = `/apis/api.console.halo.run/v1alpha1/users`;
|
||||||
|
@ -395,18 +454,22 @@ export const ApiConsoleHaloRunV1alpha1UserApiAxiosParamCreator = function (
|
||||||
localVarQueryParameter["sort"] = Array.from(sort);
|
localVarQueryParameter["sort"] = Array.from(sort);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyword !== undefined) {
|
|
||||||
localVarQueryParameter["keyword"] = keyword;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (role !== undefined) {
|
if (role !== undefined) {
|
||||||
localVarQueryParameter["role"] = role;
|
localVarQueryParameter["role"] = role;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (keyword !== undefined) {
|
||||||
|
localVarQueryParameter["keyword"] = keyword;
|
||||||
|
}
|
||||||
|
|
||||||
if (size !== undefined) {
|
if (size !== undefined) {
|
||||||
localVarQueryParameter["size"] = size;
|
localVarQueryParameter["size"] = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (page !== undefined) {
|
||||||
|
localVarQueryParameter["page"] = page;
|
||||||
|
}
|
||||||
|
|
||||||
if (labelSelector) {
|
if (labelSelector) {
|
||||||
localVarQueryParameter["labelSelector"] = labelSelector;
|
localVarQueryParameter["labelSelector"] = labelSelector;
|
||||||
}
|
}
|
||||||
|
@ -415,10 +478,6 @@ export const ApiConsoleHaloRunV1alpha1UserApiAxiosParamCreator = function (
|
||||||
localVarQueryParameter["fieldSelector"] = fieldSelector;
|
localVarQueryParameter["fieldSelector"] = fieldSelector;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (page !== undefined) {
|
|
||||||
localVarQueryParameter["page"] = page;
|
|
||||||
}
|
|
||||||
|
|
||||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||||
let headersFromBaseOptions =
|
let headersFromBaseOptions =
|
||||||
baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
|
@ -529,6 +588,29 @@ export const ApiConsoleHaloRunV1alpha1UserApiFp = function (
|
||||||
configuration
|
configuration
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Creates a new user.
|
||||||
|
* @param {CreateUserRequest} createUserRequest
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async createUser(
|
||||||
|
createUserRequest: CreateUserRequest,
|
||||||
|
options?: AxiosRequestConfig
|
||||||
|
): Promise<
|
||||||
|
(axios?: AxiosInstance, basePath?: string) => AxiosPromise<User>
|
||||||
|
> {
|
||||||
|
const localVarAxiosArgs = await localVarAxiosParamCreator.createUser(
|
||||||
|
createUserRequest,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
return createRequestFunction(
|
||||||
|
localVarAxiosArgs,
|
||||||
|
globalAxios,
|
||||||
|
BASE_PATH,
|
||||||
|
configuration
|
||||||
|
);
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* Get current user detail
|
* Get current user detail
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
|
@ -623,35 +705,38 @@ export const ApiConsoleHaloRunV1alpha1UserApiFp = function (
|
||||||
/**
|
/**
|
||||||
* List users
|
* List users
|
||||||
* @param {Array<string>} [sort] Sort property and direction of the list result. Supported fields: creationTimestamp
|
* @param {Array<string>} [sort] Sort property and direction of the list result. Supported fields: creationTimestamp
|
||||||
* @param {string} [keyword]
|
|
||||||
* @param {string} [role]
|
* @param {string} [role]
|
||||||
|
* @param {string} [keyword]
|
||||||
* @param {number} [size] Size of one page. Zero indicates no limit.
|
* @param {number} [size] Size of one page. Zero indicates no limit.
|
||||||
|
* @param {number} [page] The page number. Zero indicates no page.
|
||||||
* @param {Array<string>} [labelSelector] Label selector for filtering.
|
* @param {Array<string>} [labelSelector] Label selector for filtering.
|
||||||
* @param {Array<string>} [fieldSelector] Field selector for filtering.
|
* @param {Array<string>} [fieldSelector] Field selector for filtering.
|
||||||
* @param {number} [page] The page number. Zero indicates no page.
|
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
async listUsers(
|
async listUsers(
|
||||||
sort?: Array<string>,
|
sort?: Array<string>,
|
||||||
keyword?: string,
|
|
||||||
role?: string,
|
role?: string,
|
||||||
|
keyword?: string,
|
||||||
size?: number,
|
size?: number,
|
||||||
|
page?: number,
|
||||||
labelSelector?: Array<string>,
|
labelSelector?: Array<string>,
|
||||||
fieldSelector?: Array<string>,
|
fieldSelector?: Array<string>,
|
||||||
page?: number,
|
|
||||||
options?: AxiosRequestConfig
|
options?: AxiosRequestConfig
|
||||||
): Promise<
|
): Promise<
|
||||||
(axios?: AxiosInstance, basePath?: string) => AxiosPromise<ListedUserList>
|
(
|
||||||
|
axios?: AxiosInstance,
|
||||||
|
basePath?: string
|
||||||
|
) => AxiosPromise<UserEndpointListedUserList>
|
||||||
> {
|
> {
|
||||||
const localVarAxiosArgs = await localVarAxiosParamCreator.listUsers(
|
const localVarAxiosArgs = await localVarAxiosParamCreator.listUsers(
|
||||||
sort,
|
sort,
|
||||||
keyword,
|
|
||||||
role,
|
role,
|
||||||
|
keyword,
|
||||||
size,
|
size,
|
||||||
|
page,
|
||||||
labelSelector,
|
labelSelector,
|
||||||
fieldSelector,
|
fieldSelector,
|
||||||
page,
|
|
||||||
options
|
options
|
||||||
);
|
);
|
||||||
return createRequestFunction(
|
return createRequestFunction(
|
||||||
|
@ -714,6 +799,20 @@ export const ApiConsoleHaloRunV1alpha1UserApiFactory = function (
|
||||||
)
|
)
|
||||||
.then((request) => request(axios, basePath));
|
.then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Creates a new user.
|
||||||
|
* @param {ApiConsoleHaloRunV1alpha1UserApiCreateUserRequest} requestParameters Request parameters.
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
createUser(
|
||||||
|
requestParameters: ApiConsoleHaloRunV1alpha1UserApiCreateUserRequest,
|
||||||
|
options?: AxiosRequestConfig
|
||||||
|
): AxiosPromise<User> {
|
||||||
|
return localVarFp
|
||||||
|
.createUser(requestParameters.createUserRequest, options)
|
||||||
|
.then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* Get current user detail
|
* Get current user detail
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
|
@ -781,16 +880,16 @@ export const ApiConsoleHaloRunV1alpha1UserApiFactory = function (
|
||||||
listUsers(
|
listUsers(
|
||||||
requestParameters: ApiConsoleHaloRunV1alpha1UserApiListUsersRequest = {},
|
requestParameters: ApiConsoleHaloRunV1alpha1UserApiListUsersRequest = {},
|
||||||
options?: AxiosRequestConfig
|
options?: AxiosRequestConfig
|
||||||
): AxiosPromise<ListedUserList> {
|
): AxiosPromise<UserEndpointListedUserList> {
|
||||||
return localVarFp
|
return localVarFp
|
||||||
.listUsers(
|
.listUsers(
|
||||||
requestParameters.sort,
|
requestParameters.sort,
|
||||||
requestParameters.keyword,
|
|
||||||
requestParameters.role,
|
requestParameters.role,
|
||||||
|
requestParameters.keyword,
|
||||||
requestParameters.size,
|
requestParameters.size,
|
||||||
|
requestParameters.page,
|
||||||
requestParameters.labelSelector,
|
requestParameters.labelSelector,
|
||||||
requestParameters.fieldSelector,
|
requestParameters.fieldSelector,
|
||||||
requestParameters.page,
|
|
||||||
options
|
options
|
||||||
)
|
)
|
||||||
.then((request) => request(axios, basePath));
|
.then((request) => request(axios, basePath));
|
||||||
|
@ -833,6 +932,20 @@ export interface ApiConsoleHaloRunV1alpha1UserApiChangePasswordRequest {
|
||||||
readonly changePasswordRequest: ChangePasswordRequest;
|
readonly changePasswordRequest: ChangePasswordRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request parameters for createUser operation in ApiConsoleHaloRunV1alpha1UserApi.
|
||||||
|
* @export
|
||||||
|
* @interface ApiConsoleHaloRunV1alpha1UserApiCreateUserRequest
|
||||||
|
*/
|
||||||
|
export interface ApiConsoleHaloRunV1alpha1UserApiCreateUserRequest {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {CreateUserRequest}
|
||||||
|
* @memberof ApiConsoleHaloRunV1alpha1UserApiCreateUser
|
||||||
|
*/
|
||||||
|
readonly createUserRequest: CreateUserRequest;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request parameters for getPermissions operation in ApiConsoleHaloRunV1alpha1UserApi.
|
* Request parameters for getPermissions operation in ApiConsoleHaloRunV1alpha1UserApi.
|
||||||
* @export
|
* @export
|
||||||
|
@ -900,14 +1013,14 @@ export interface ApiConsoleHaloRunV1alpha1UserApiListUsersRequest {
|
||||||
* @type {string}
|
* @type {string}
|
||||||
* @memberof ApiConsoleHaloRunV1alpha1UserApiListUsers
|
* @memberof ApiConsoleHaloRunV1alpha1UserApiListUsers
|
||||||
*/
|
*/
|
||||||
readonly keyword?: string;
|
readonly role?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
* @memberof ApiConsoleHaloRunV1alpha1UserApiListUsers
|
* @memberof ApiConsoleHaloRunV1alpha1UserApiListUsers
|
||||||
*/
|
*/
|
||||||
readonly role?: string;
|
readonly keyword?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Size of one page. Zero indicates no limit.
|
* Size of one page. Zero indicates no limit.
|
||||||
|
@ -916,6 +1029,13 @@ export interface ApiConsoleHaloRunV1alpha1UserApiListUsersRequest {
|
||||||
*/
|
*/
|
||||||
readonly size?: number;
|
readonly size?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The page number. Zero indicates no page.
|
||||||
|
* @type {number}
|
||||||
|
* @memberof ApiConsoleHaloRunV1alpha1UserApiListUsers
|
||||||
|
*/
|
||||||
|
readonly page?: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Label selector for filtering.
|
* Label selector for filtering.
|
||||||
* @type {Array<string>}
|
* @type {Array<string>}
|
||||||
|
@ -929,13 +1049,6 @@ export interface ApiConsoleHaloRunV1alpha1UserApiListUsersRequest {
|
||||||
* @memberof ApiConsoleHaloRunV1alpha1UserApiListUsers
|
* @memberof ApiConsoleHaloRunV1alpha1UserApiListUsers
|
||||||
*/
|
*/
|
||||||
readonly fieldSelector?: Array<string>;
|
readonly fieldSelector?: Array<string>;
|
||||||
|
|
||||||
/**
|
|
||||||
* The page number. Zero indicates no page.
|
|
||||||
* @type {number}
|
|
||||||
* @memberof ApiConsoleHaloRunV1alpha1UserApiListUsers
|
|
||||||
*/
|
|
||||||
readonly page?: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -979,6 +1092,22 @@ export class ApiConsoleHaloRunV1alpha1UserApi extends BaseAPI {
|
||||||
.then((request) => request(this.axios, this.basePath));
|
.then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new user.
|
||||||
|
* @param {ApiConsoleHaloRunV1alpha1UserApiCreateUserRequest} requestParameters Request parameters.
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
* @memberof ApiConsoleHaloRunV1alpha1UserApi
|
||||||
|
*/
|
||||||
|
public createUser(
|
||||||
|
requestParameters: ApiConsoleHaloRunV1alpha1UserApiCreateUserRequest,
|
||||||
|
options?: AxiosRequestConfig
|
||||||
|
) {
|
||||||
|
return ApiConsoleHaloRunV1alpha1UserApiFp(this.configuration)
|
||||||
|
.createUser(requestParameters.createUserRequest, options)
|
||||||
|
.then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get current user detail
|
* Get current user detail
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
|
@ -1057,12 +1186,12 @@ export class ApiConsoleHaloRunV1alpha1UserApi extends BaseAPI {
|
||||||
return ApiConsoleHaloRunV1alpha1UserApiFp(this.configuration)
|
return ApiConsoleHaloRunV1alpha1UserApiFp(this.configuration)
|
||||||
.listUsers(
|
.listUsers(
|
||||||
requestParameters.sort,
|
requestParameters.sort,
|
||||||
requestParameters.keyword,
|
|
||||||
requestParameters.role,
|
requestParameters.role,
|
||||||
|
requestParameters.keyword,
|
||||||
requestParameters.size,
|
requestParameters.size,
|
||||||
|
requestParameters.page,
|
||||||
requestParameters.labelSelector,
|
requestParameters.labelSelector,
|
||||||
requestParameters.fieldSelector,
|
requestParameters.fieldSelector,
|
||||||
requestParameters.page,
|
|
||||||
options
|
options
|
||||||
)
|
)
|
||||||
.then((request) => request(this.axios, this.basePath));
|
.then((request) => request(this.axios, this.basePath));
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Halo Next API
|
||||||
|
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 2.0.0
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface CreateUserRequest
|
||||||
|
*/
|
||||||
|
export interface CreateUserRequest {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {{ [key: string]: string; }}
|
||||||
|
* @memberof CreateUserRequest
|
||||||
|
*/
|
||||||
|
annotations?: { [key: string]: string };
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof CreateUserRequest
|
||||||
|
*/
|
||||||
|
avatar?: string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof CreateUserRequest
|
||||||
|
*/
|
||||||
|
bio?: string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof CreateUserRequest
|
||||||
|
*/
|
||||||
|
displayName?: string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof CreateUserRequest
|
||||||
|
*/
|
||||||
|
email: string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof CreateUserRequest
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof CreateUserRequest
|
||||||
|
*/
|
||||||
|
password?: string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof CreateUserRequest
|
||||||
|
*/
|
||||||
|
phone?: string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {Array<string>}
|
||||||
|
* @memberof CreateUserRequest
|
||||||
|
*/
|
||||||
|
roles?: Array<string>;
|
||||||
|
}
|
|
@ -35,6 +35,7 @@ export * from "./contributor";
|
||||||
export * from "./counter";
|
export * from "./counter";
|
||||||
export * from "./counter-list";
|
export * from "./counter-list";
|
||||||
export * from "./counter-request";
|
export * from "./counter-request";
|
||||||
|
export * from "./create-user-request";
|
||||||
export * from "./custom-templates";
|
export * from "./custom-templates";
|
||||||
export * from "./dashboard-stats";
|
export * from "./dashboard-stats";
|
||||||
export * from "./detailed-user";
|
export * from "./detailed-user";
|
||||||
|
@ -64,7 +65,6 @@ export * from "./listed-reply-list";
|
||||||
export * from "./listed-single-page";
|
export * from "./listed-single-page";
|
||||||
export * from "./listed-single-page-list";
|
export * from "./listed-single-page-list";
|
||||||
export * from "./listed-user";
|
export * from "./listed-user";
|
||||||
export * from "./listed-user-list";
|
|
||||||
export * from "./login-history";
|
export * from "./login-history";
|
||||||
export * from "./menu";
|
export * from "./menu";
|
||||||
export * from "./menu-item";
|
export * from "./menu-item";
|
||||||
|
@ -147,6 +147,7 @@ export * from "./user";
|
||||||
export * from "./user-connection";
|
export * from "./user-connection";
|
||||||
export * from "./user-connection-list";
|
export * from "./user-connection-list";
|
||||||
export * from "./user-connection-spec";
|
export * from "./user-connection-spec";
|
||||||
|
export * from "./user-endpoint-listed-user-list";
|
||||||
export * from "./user-list";
|
export * from "./user-list";
|
||||||
export * from "./user-permission";
|
export * from "./user-permission";
|
||||||
export * from "./user-spec";
|
export * from "./user-spec";
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Halo Next API
|
||||||
|
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 2.0.0
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// May contain unused imports in some cases
|
||||||
|
// @ts-ignore
|
||||||
|
import { ListedUser } from "./listed-user";
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface UserEndpointListedUserList
|
||||||
|
*/
|
||||||
|
export interface UserEndpointListedUserList {
|
||||||
|
/**
|
||||||
|
* Indicates whether current page is the first page.
|
||||||
|
* @type {boolean}
|
||||||
|
* @memberof UserEndpointListedUserList
|
||||||
|
*/
|
||||||
|
first: boolean;
|
||||||
|
/**
|
||||||
|
* Indicates whether current page has previous page.
|
||||||
|
* @type {boolean}
|
||||||
|
* @memberof UserEndpointListedUserList
|
||||||
|
*/
|
||||||
|
hasNext: boolean;
|
||||||
|
/**
|
||||||
|
* Indicates whether current page has previous page.
|
||||||
|
* @type {boolean}
|
||||||
|
* @memberof UserEndpointListedUserList
|
||||||
|
*/
|
||||||
|
hasPrevious: boolean;
|
||||||
|
/**
|
||||||
|
* A chunk of items.
|
||||||
|
* @type {Array<ListedUser>}
|
||||||
|
* @memberof UserEndpointListedUserList
|
||||||
|
*/
|
||||||
|
items: Array<ListedUser>;
|
||||||
|
/**
|
||||||
|
* Indicates whether current page is the last page.
|
||||||
|
* @type {boolean}
|
||||||
|
* @memberof UserEndpointListedUserList
|
||||||
|
*/
|
||||||
|
last: boolean;
|
||||||
|
/**
|
||||||
|
* Page number, starts from 1. If not set or equal to 0, it means no pagination.
|
||||||
|
* @type {number}
|
||||||
|
* @memberof UserEndpointListedUserList
|
||||||
|
*/
|
||||||
|
page: number;
|
||||||
|
/**
|
||||||
|
* Size of each page. If not set or equal to 0, it means no pagination.
|
||||||
|
* @type {number}
|
||||||
|
* @memberof UserEndpointListedUserList
|
||||||
|
*/
|
||||||
|
size: number;
|
||||||
|
/**
|
||||||
|
* Total elements.
|
||||||
|
* @type {number}
|
||||||
|
* @memberof UserEndpointListedUserList
|
||||||
|
*/
|
||||||
|
total: number;
|
||||||
|
/**
|
||||||
|
* Indicates total pages.
|
||||||
|
* @type {number}
|
||||||
|
* @memberof UserEndpointListedUserList
|
||||||
|
*/
|
||||||
|
totalPages: number;
|
||||||
|
}
|
|
@ -40,12 +40,14 @@ import { useFetchRole } from "../roles/composables/use-role";
|
||||||
import FilterCleanButton from "@/components/filter/FilterCleanButton.vue";
|
import FilterCleanButton from "@/components/filter/FilterCleanButton.vue";
|
||||||
import { useQuery } from "@tanstack/vue-query";
|
import { useQuery } from "@tanstack/vue-query";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
import UserCreationModal from "./components/UserCreationModal.vue";
|
||||||
|
|
||||||
const { currentUserHasPermission } = usePermission();
|
const { currentUserHasPermission } = usePermission();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const checkedAll = ref(false);
|
const checkedAll = ref(false);
|
||||||
const editingModal = ref<boolean>(false);
|
const editingModal = ref<boolean>(false);
|
||||||
|
const creationModal = ref<boolean>(false);
|
||||||
const passwordChangeModal = ref<boolean>(false);
|
const passwordChangeModal = ref<boolean>(false);
|
||||||
const grantPermissionModal = ref<boolean>(false);
|
const grantPermissionModal = ref<boolean>(false);
|
||||||
|
|
||||||
|
@ -233,11 +235,6 @@ const handleOpenCreateModal = (user: User) => {
|
||||||
editingModal.value = true;
|
editingModal.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const onEditingModalClose = () => {
|
|
||||||
routeQueryAction.value = undefined;
|
|
||||||
refetch();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleOpenPasswordChangeModal = (user: User) => {
|
const handleOpenPasswordChangeModal = (user: User) => {
|
||||||
selectedUser.value = user;
|
selectedUser.value = user;
|
||||||
passwordChangeModal.value = true;
|
passwordChangeModal.value = true;
|
||||||
|
@ -252,19 +249,17 @@ const handleOpenGrantPermissionModal = (user: User) => {
|
||||||
const routeQueryAction = useRouteQuery<string | undefined>("action");
|
const routeQueryAction = useRouteQuery<string | undefined>("action");
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (!routeQueryAction.value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (routeQueryAction.value === "create") {
|
if (routeQueryAction.value === "create") {
|
||||||
editingModal.value = true;
|
creationModal.value = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<UserEditingModal
|
<UserEditingModal v-model:visible="editingModal" :user="selectedUser" />
|
||||||
v-model:visible="editingModal"
|
|
||||||
:user="selectedUser"
|
<UserCreationModal
|
||||||
@close="onEditingModalClose"
|
v-model:visible="creationModal"
|
||||||
|
@close="routeQueryAction = undefined"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<UserPasswordChangeModal
|
<UserPasswordChangeModal
|
||||||
|
@ -305,7 +300,7 @@ onMounted(() => {
|
||||||
<VButton
|
<VButton
|
||||||
v-permission="['system:users:manage']"
|
v-permission="['system:users:manage']"
|
||||||
type="secondary"
|
type="secondary"
|
||||||
@click="editingModal = true"
|
@click="creationModal = true"
|
||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<IconAddCircle class="h-full w-full" />
|
<IconAddCircle class="h-full w-full" />
|
||||||
|
|
|
@ -0,0 +1,196 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
// core libs
|
||||||
|
import { ref, watch } from "vue";
|
||||||
|
import { apiClient } from "@/utils/api-client";
|
||||||
|
import type { CreateUserRequest } from "@halo-dev/api-client";
|
||||||
|
|
||||||
|
// components
|
||||||
|
import { Toast, VButton, VModal, VSpace } from "@halo-dev/components";
|
||||||
|
import SubmitButton from "@/components/button/SubmitButton.vue";
|
||||||
|
|
||||||
|
// libs
|
||||||
|
import cloneDeep from "lodash.clonedeep";
|
||||||
|
import { reset } from "@formkit/core";
|
||||||
|
|
||||||
|
// hooks
|
||||||
|
import { setFocus } from "@/formkit/utils/focus";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useQueryClient } from "@tanstack/vue-query";
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
visible: boolean;
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
visible: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(event: "update:visible", visible: boolean): void;
|
||||||
|
(event: "close"): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const initialFormState: CreateUserRequest = {
|
||||||
|
avatar: "",
|
||||||
|
bio: "",
|
||||||
|
displayName: "",
|
||||||
|
email: "",
|
||||||
|
name: "",
|
||||||
|
password: "",
|
||||||
|
phone: "",
|
||||||
|
roles: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const formState = ref<CreateUserRequest>(cloneDeep(initialFormState));
|
||||||
|
const selectedRole = ref("");
|
||||||
|
const saving = ref(false);
|
||||||
|
|
||||||
|
const handleResetForm = () => {
|
||||||
|
formState.value = cloneDeep(initialFormState);
|
||||||
|
reset("user-creation-form");
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.visible,
|
||||||
|
(visible) => {
|
||||||
|
if (visible) {
|
||||||
|
setFocus("creationUserNameInput");
|
||||||
|
} else {
|
||||||
|
handleResetForm();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const onVisibleChange = (visible: boolean) => {
|
||||||
|
emit("update:visible", visible);
|
||||||
|
if (!visible) {
|
||||||
|
emit("close");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCreateUser = async () => {
|
||||||
|
try {
|
||||||
|
saving.value = true;
|
||||||
|
|
||||||
|
if (selectedRole.value) {
|
||||||
|
formState.value.roles = [selectedRole.value];
|
||||||
|
}
|
||||||
|
|
||||||
|
await apiClient.user.createUser({
|
||||||
|
createUserRequest: formState.value,
|
||||||
|
});
|
||||||
|
|
||||||
|
onVisibleChange(false);
|
||||||
|
|
||||||
|
Toast.success(t("core.common.toast.save_success"));
|
||||||
|
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["users"] });
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to create or update user", e);
|
||||||
|
} finally {
|
||||||
|
saving.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<VModal
|
||||||
|
:title="$t('core.user.editing_modal.titles.create')"
|
||||||
|
:visible="visible"
|
||||||
|
:width="650"
|
||||||
|
@update:visible="onVisibleChange"
|
||||||
|
>
|
||||||
|
<FormKit
|
||||||
|
id="user-creation-form"
|
||||||
|
name="user-creation-form"
|
||||||
|
:config="{ validationVisibility: 'submit' }"
|
||||||
|
type="form"
|
||||||
|
@submit="handleCreateUser"
|
||||||
|
>
|
||||||
|
<FormKit
|
||||||
|
id="creationUserNameInput"
|
||||||
|
v-model="formState.name"
|
||||||
|
:label="$t('core.user.editing_modal.fields.username.label')"
|
||||||
|
type="text"
|
||||||
|
name="name"
|
||||||
|
:validation="[
|
||||||
|
['required'],
|
||||||
|
['length:0,63'],
|
||||||
|
[
|
||||||
|
'matches',
|
||||||
|
/^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$/,
|
||||||
|
],
|
||||||
|
]"
|
||||||
|
:validation-messages="{
|
||||||
|
matches: $t('core.user.editing_modal.fields.username.validation'),
|
||||||
|
}"
|
||||||
|
></FormKit>
|
||||||
|
<FormKit
|
||||||
|
v-model="formState.displayName"
|
||||||
|
:label="$t('core.user.editing_modal.fields.display_name.label')"
|
||||||
|
type="text"
|
||||||
|
name="displayName"
|
||||||
|
validation="required|length:0,50"
|
||||||
|
></FormKit>
|
||||||
|
<FormKit
|
||||||
|
v-model="formState.email"
|
||||||
|
:label="$t('core.user.editing_modal.fields.email.label')"
|
||||||
|
type="email"
|
||||||
|
name="email"
|
||||||
|
validation="required|email|length:0,100"
|
||||||
|
></FormKit>
|
||||||
|
<FormKit
|
||||||
|
v-model="formState.phone"
|
||||||
|
:label="$t('core.user.editing_modal.fields.phone.label')"
|
||||||
|
type="text"
|
||||||
|
name="phone"
|
||||||
|
validation="length:0,20"
|
||||||
|
></FormKit>
|
||||||
|
<FormKit
|
||||||
|
v-model="formState.avatar"
|
||||||
|
:label="$t('core.user.editing_modal.fields.avatar.label')"
|
||||||
|
type="attachment"
|
||||||
|
name="avatar"
|
||||||
|
validation="url|length:0,1024"
|
||||||
|
></FormKit>
|
||||||
|
<FormKit
|
||||||
|
v-model="formState.password"
|
||||||
|
:label="$t('core.user.change_password_modal.fields.new_password.label')"
|
||||||
|
type="password"
|
||||||
|
name="password"
|
||||||
|
validation="required|length:0,100"
|
||||||
|
></FormKit>
|
||||||
|
<FormKit
|
||||||
|
v-model="selectedRole"
|
||||||
|
:label="$t('core.user.grant_permission_modal.fields.role.label')"
|
||||||
|
type="roleSelect"
|
||||||
|
></FormKit>
|
||||||
|
<FormKit
|
||||||
|
v-model="formState.bio"
|
||||||
|
:label="$t('core.user.editing_modal.fields.bio.label')"
|
||||||
|
type="textarea"
|
||||||
|
name="bio"
|
||||||
|
validation="length:0,2048"
|
||||||
|
></FormKit>
|
||||||
|
</FormKit>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<VSpace>
|
||||||
|
<SubmitButton
|
||||||
|
v-if="visible"
|
||||||
|
:loading="saving"
|
||||||
|
type="secondary"
|
||||||
|
:text="$t('core.common.buttons.submit')"
|
||||||
|
@submit="$formkit.submit('user-creation-form')"
|
||||||
|
>
|
||||||
|
</SubmitButton>
|
||||||
|
<VButton @click="onVisibleChange(false)">
|
||||||
|
{{ $t("core.common.buttons.cancel_and_shortcut") }}
|
||||||
|
</VButton>
|
||||||
|
</VSpace>
|
||||||
|
</template>
|
||||||
|
</VModal>
|
||||||
|
</template>
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
// core libs
|
// core libs
|
||||||
import { computed, nextTick, ref, watch } from "vue";
|
import { nextTick, ref, watch } from "vue";
|
||||||
import { apiClient } from "@/utils/api-client";
|
import { apiClient } from "@/utils/api-client";
|
||||||
import type { User } from "@halo-dev/api-client";
|
import type { User } from "@halo-dev/api-client";
|
||||||
|
|
||||||
|
@ -17,9 +17,11 @@ import { setFocus } from "@/formkit/utils/focus";
|
||||||
import AnnotationsForm from "@/components/form/AnnotationsForm.vue";
|
import AnnotationsForm from "@/components/form/AnnotationsForm.vue";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useQueryClient } from "@tanstack/vue-query";
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
|
@ -58,16 +60,6 @@ const initialFormState: User = {
|
||||||
const formState = ref<User>(cloneDeep(initialFormState));
|
const formState = ref<User>(cloneDeep(initialFormState));
|
||||||
const saving = ref(false);
|
const saving = ref(false);
|
||||||
|
|
||||||
const isUpdateMode = computed(() => {
|
|
||||||
return !!formState.value.metadata.creationTimestamp;
|
|
||||||
});
|
|
||||||
|
|
||||||
const creationModalTitle = computed(() => {
|
|
||||||
return isUpdateMode.value
|
|
||||||
? t("core.user.editing_modal.titles.update")
|
|
||||||
: t("core.user.editing_modal.titles.create");
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleResetForm = () => {
|
const handleResetForm = () => {
|
||||||
formState.value = cloneDeep(initialFormState);
|
formState.value = cloneDeep(initialFormState);
|
||||||
reset("user-form");
|
reset("user-form");
|
||||||
|
@ -78,7 +70,7 @@ watch(
|
||||||
(visible) => {
|
(visible) => {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
if (props.user) formState.value = cloneDeep(props.user);
|
if (props.user) formState.value = cloneDeep(props.user);
|
||||||
setFocus(isUpdateMode.value ? "displayNameInput" : "userNameInput");
|
setFocus("displayNameInput");
|
||||||
} else {
|
} else {
|
||||||
handleResetForm();
|
handleResetForm();
|
||||||
}
|
}
|
||||||
|
@ -94,7 +86,7 @@ const onVisibleChange = (visible: boolean) => {
|
||||||
|
|
||||||
const annotationsFormRef = ref<InstanceType<typeof AnnotationsForm>>();
|
const annotationsFormRef = ref<InstanceType<typeof AnnotationsForm>>();
|
||||||
|
|
||||||
const handleCreateUser = async () => {
|
const handleUpdateUser = async () => {
|
||||||
annotationsFormRef.value?.handleSubmit();
|
annotationsFormRef.value?.handleSubmit();
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
|
||||||
|
@ -111,25 +103,23 @@ const handleCreateUser = async () => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
saving.value = true;
|
saving.value = true;
|
||||||
if (isUpdateMode.value) {
|
|
||||||
if (props.user?.metadata.name === userStore.currentUser?.metadata.name) {
|
if (props.user?.metadata.name === userStore.currentUser?.metadata.name) {
|
||||||
await apiClient.user.updateCurrentUser({
|
await apiClient.user.updateCurrentUser({
|
||||||
user: formState.value,
|
user: formState.value,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
await apiClient.extension.user.updatev1alpha1User({
|
|
||||||
name: formState.value.metadata.name,
|
|
||||||
user: formState.value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
await apiClient.extension.user.createv1alpha1User({
|
await apiClient.extension.user.updatev1alpha1User({
|
||||||
|
name: formState.value.metadata.name,
|
||||||
user: formState.value,
|
user: formState.value,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onVisibleChange(false);
|
onVisibleChange(false);
|
||||||
|
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["users"] });
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["user-detail"] });
|
||||||
|
|
||||||
Toast.success(t("core.common.toast.save_success"));
|
Toast.success(t("core.common.toast.save_success"));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Failed to create or update user", e);
|
console.error("Failed to create or update user", e);
|
||||||
|
@ -140,7 +130,7 @@ const handleCreateUser = async () => {
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<VModal
|
<VModal
|
||||||
:title="creationModalTitle"
|
:title="$t('core.user.editing_modal.titles.update')"
|
||||||
:visible="visible"
|
:visible="visible"
|
||||||
:width="700"
|
:width="700"
|
||||||
@update:visible="onVisibleChange"
|
@update:visible="onVisibleChange"
|
||||||
|
@ -150,7 +140,7 @@ const handleCreateUser = async () => {
|
||||||
name="user-form"
|
name="user-form"
|
||||||
:config="{ validationVisibility: 'submit' }"
|
:config="{ validationVisibility: 'submit' }"
|
||||||
type="form"
|
type="form"
|
||||||
@submit="handleCreateUser"
|
@submit="handleUpdateUser"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<div class="md:grid md:grid-cols-4 md:gap-6">
|
<div class="md:grid md:grid-cols-4 md:gap-6">
|
||||||
|
@ -165,7 +155,7 @@ const handleCreateUser = async () => {
|
||||||
<FormKit
|
<FormKit
|
||||||
id="userNameInput"
|
id="userNameInput"
|
||||||
v-model="formState.metadata.name"
|
v-model="formState.metadata.name"
|
||||||
:disabled="isUpdateMode"
|
:disabled="true"
|
||||||
:label="$t('core.user.editing_modal.fields.username.label')"
|
:label="$t('core.user.editing_modal.fields.username.label')"
|
||||||
type="text"
|
type="text"
|
||||||
name="name"
|
name="name"
|
||||||
|
|
|
@ -120,7 +120,7 @@ const handleChangePassword = async () => {
|
||||||
"
|
"
|
||||||
name="password_confirm"
|
name="password_confirm"
|
||||||
type="password"
|
type="password"
|
||||||
validation="required|confirm|length:0,50"
|
validation="required|confirm|length:0,100"
|
||||||
></FormKit>
|
></FormKit>
|
||||||
</FormKit>
|
</FormKit>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
|
|
|
@ -107,16 +107,14 @@ const handleTabChange = (id: string) => {
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<BasicLayout>
|
<BasicLayout>
|
||||||
<UserEditingModal
|
<UserEditingModal v-model:visible="editingModal" :user="user?.user" />
|
||||||
v-model:visible="editingModal"
|
|
||||||
:user="user?.user"
|
|
||||||
@close="refetch"
|
|
||||||
/>
|
|
||||||
<UserPasswordChangeModal
|
<UserPasswordChangeModal
|
||||||
v-model:visible="passwordChangeModal"
|
v-model:visible="passwordChangeModal"
|
||||||
:user="user?.user"
|
:user="user?.user"
|
||||||
@close="refetch"
|
@close="refetch"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<header class="bg-white">
|
<header class="bg-white">
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
|
|
Loading…
Reference in New Issue