From 0dcab3271222bfaf525b179403be3c867f47bf11 Mon Sep 17 00:00:00 2001 From: guqing Date: Mon, 23 Sep 2024 15:55:16 +0800 Subject: [PATCH 1/3] feat: add API to fetch system configs by group --- .../core/endpoint/SystemConfigEndpoint.java | 61 +++++++++++++++++++ .../extensions/role-template-menu.yaml | 4 ++ 2 files changed, 65 insertions(+) create mode 100644 application/src/main/java/run/halo/app/core/endpoint/SystemConfigEndpoint.java diff --git a/application/src/main/java/run/halo/app/core/endpoint/SystemConfigEndpoint.java b/application/src/main/java/run/halo/app/core/endpoint/SystemConfigEndpoint.java new file mode 100644 index 000000000..57734e336 --- /dev/null +++ b/application/src/main/java/run/halo/app/core/endpoint/SystemConfigEndpoint.java @@ -0,0 +1,61 @@ +package run.halo.app.core.endpoint; + +import static org.springdoc.core.fn.builders.apiresponse.Builder.responseBuilder; +import static org.springdoc.core.fn.builders.content.Builder.contentBuilder; +import static org.springdoc.core.fn.builders.parameter.Builder.parameterBuilder; + +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import lombok.RequiredArgsConstructor; +import org.springdoc.webflux.core.fn.SpringdocRouteBuilder; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Mono; +import run.halo.app.core.extension.endpoint.CustomEndpoint; +import run.halo.app.extension.GroupVersion; +import run.halo.app.infra.SystemConfigurableEnvironmentFetcher; + +@Component +@RequiredArgsConstructor +public class SystemConfigEndpoint implements CustomEndpoint { + private final SystemConfigurableEnvironmentFetcher configurableEnvironmentFetcher; + + @Override + public RouterFunction endpoint() { + final var tag = "SystemConfigV1alpha1Console"; + return SpringdocRouteBuilder.route() + .GET("/systemconfigs/{group}", this::getConfigByGroup, + builder -> builder.operationId("getSystemConfigByGroup") + .description("Get system config by group") + .tag(tag) + .response(responseBuilder() + .content(contentBuilder() + .mediaType(MediaType.APPLICATION_JSON_VALUE) + ) + .implementation(ObjectNode.class)) + .parameter(parameterBuilder() + .in(ParameterIn.PATH) + .name("group") + .required(true) + .description("Group of the system config") + ) + ) + .build(); + } + + private Mono getConfigByGroup(ServerRequest request) { + final var group = request.pathVariable("group"); + return configurableEnvironmentFetcher.fetch(group, ObjectNode.class) + .switchIfEmpty(Mono.fromSupplier(JsonNodeFactory.instance::objectNode)) + .flatMap(json -> ServerResponse.ok().bodyValue(json)); + } + + @Override + public GroupVersion groupVersion() { + return new GroupVersion("console.api.halo.run", "v1alpha1"); + } +} diff --git a/application/src/main/resources/extensions/role-template-menu.yaml b/application/src/main/resources/extensions/role-template-menu.yaml index 24a4d71df..9ac960867 100644 --- a/application/src/main/resources/extensions/role-template-menu.yaml +++ b/application/src/main/resources/extensions/role-template-menu.yaml @@ -30,3 +30,7 @@ rules: - apiGroups: [ "" ] resources: [ "menus", "menuitems" ] verbs: [ "get", "list" ] + - apiGroups: [ "console.api.halo.run" ] + resources: [ "systemconfigs" ] + resourceNames: [ "menu" ] + verbs: [ "get" ] From dd2080c3aeb1186c4152e83c122d3c6b7efb9caf Mon Sep 17 00:00:00 2001 From: guqing Date: Tue, 24 Sep 2024 12:10:30 +0800 Subject: [PATCH 2/3] feat: add API to update system config by group --- .../core/endpoint/SystemConfigEndpoint.java | 41 +++++++++++++++++++ .../extensions/role-template-menu.yaml | 4 ++ 2 files changed, 45 insertions(+) diff --git a/application/src/main/java/run/halo/app/core/endpoint/SystemConfigEndpoint.java b/application/src/main/java/run/halo/app/core/endpoint/SystemConfigEndpoint.java index 57734e336..d6ceb690f 100644 --- a/application/src/main/java/run/halo/app/core/endpoint/SystemConfigEndpoint.java +++ b/application/src/main/java/run/halo/app/core/endpoint/SystemConfigEndpoint.java @@ -3,26 +3,34 @@ package run.halo.app.core.endpoint; import static org.springdoc.core.fn.builders.apiresponse.Builder.responseBuilder; import static org.springdoc.core.fn.builders.content.Builder.contentBuilder; import static org.springdoc.core.fn.builders.parameter.Builder.parameterBuilder; +import static org.springdoc.core.fn.builders.requestbody.Builder.requestBodyBuilder; import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.ObjectNode; import io.swagger.v3.oas.annotations.enums.ParameterIn; +import java.time.Duration; import lombok.RequiredArgsConstructor; import org.springdoc.webflux.core.fn.SpringdocRouteBuilder; +import org.springframework.dao.OptimisticLockingFailureException; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Mono; +import reactor.util.retry.Retry; import run.halo.app.core.extension.endpoint.CustomEndpoint; import run.halo.app.extension.GroupVersion; +import run.halo.app.extension.ReactiveExtensionClient; import run.halo.app.infra.SystemConfigurableEnvironmentFetcher; +import run.halo.app.infra.utils.JsonUtils; @Component @RequiredArgsConstructor public class SystemConfigEndpoint implements CustomEndpoint { private final SystemConfigurableEnvironmentFetcher configurableEnvironmentFetcher; + private final ReactiveExtensionClient client; @Override public RouterFunction endpoint() { @@ -44,9 +52,42 @@ public class SystemConfigEndpoint implements CustomEndpoint { .description("Group of the system config") ) ) + .PUT("/systemconfigs/{group}", this::updateConfigByGroup, + builder -> builder.operationId("updateSystemConfigByGroup") + .description("Update system config by group") + .tag(tag) + .parameter(parameterBuilder() + .in(ParameterIn.PATH) + .name("group") + .required(true) + .description("Group of the system config") + ) + .requestBody(requestBodyBuilder() + .implementation(ObjectNode.class) + ) + .response(responseBuilder() + .responseCode(String.valueOf(HttpStatus.NO_CONTENT)) + .implementation(Void.class) + ) + ) .build(); } + private Mono updateConfigByGroup(ServerRequest request) { + final var group = request.pathVariable("group"); + return request.bodyToMono(ObjectNode.class) + .flatMap(objectNode -> configurableEnvironmentFetcher.getConfigMap() + .flatMap(configMap -> { + var data = configMap.getData(); + data.put(group, JsonUtils.objectToJson(objectNode)); + return client.update(configMap); + }) + ) + .retryWhen(Retry.backoff(5, Duration.ofMillis(100)) + .filter(OptimisticLockingFailureException.class::isInstance)) + .then(ServerResponse.noContent().build()); + } + private Mono getConfigByGroup(ServerRequest request) { final var group = request.pathVariable("group"); return configurableEnvironmentFetcher.fetch(group, ObjectNode.class) diff --git a/application/src/main/resources/extensions/role-template-menu.yaml b/application/src/main/resources/extensions/role-template-menu.yaml index 9ac960867..a94f33e35 100644 --- a/application/src/main/resources/extensions/role-template-menu.yaml +++ b/application/src/main/resources/extensions/role-template-menu.yaml @@ -14,6 +14,10 @@ rules: - apiGroups: [ "" ] resources: [ "menus", "menuitems" ] verbs: [ "*" ] + - apiGroups: [ "console.api.halo.run" ] + resources: [ "systemconfigs" ] + resourceNames: [ "menu" ] + verbs: [ "update" ] --- apiVersion: v1alpha1 kind: "Role" From c945a9443cbf59900a8e945b60719de7b97413c5 Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Tue, 24 Sep 2024 12:50:25 +0800 Subject: [PATCH 3/3] Refine UI --- api-docs/openapi/v3_0/aggregated.json | 66 +++++ .../v3_0/apis_console.api_v1alpha1.json | 66 +++++ .../interface/menus/components/MenuList.vue | 42 ++- ui/packages/api-client/entry/api-client.ts | 11 +- .../api-client/src/.openapi-generator/FILES | 1 + ui/packages/api-client/src/api.ts | 1 + .../api/system-config-v1alpha1-console-api.ts | 246 ++++++++++++++++++ 7 files changed, 407 insertions(+), 26 deletions(-) create mode 100644 ui/packages/api-client/src/api/system-config-v1alpha1-console-api.ts diff --git a/api-docs/openapi/v3_0/aggregated.json b/api-docs/openapi/v3_0/aggregated.json index 700654713..dfdd9790f 100644 --- a/api-docs/openapi/v3_0/aggregated.json +++ b/api-docs/openapi/v3_0/aggregated.json @@ -7434,6 +7434,72 @@ ] } }, + "/apis/console.api.halo.run/v1alpha1/systemconfigs/{group}": { + "get": { + "description": "Get system config by group", + "operationId": "getSystemConfigByGroup", + "parameters": [ + { + "description": "Group of the system config", + "in": "path", + "name": "group", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "default": { + "content": { + "*/*": { + "schema": { + "type": "object" + } + }, + "application/json": {} + }, + "description": "default response" + } + }, + "tags": [ + "SystemConfigV1alpha1Console" + ] + }, + "put": { + "description": "Update system config by group", + "operationId": "updateSystemConfigByGroup", + "parameters": [ + { + "description": "Group of the system config", + "in": "path", + "name": "group", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "*/*": { + "schema": { + "type": "object" + } + } + } + }, + "responses": { + "204 NO_CONTENT": { + "content": {}, + "description": "default response" + } + }, + "tags": [ + "SystemConfigV1alpha1Console" + ] + } + }, "/apis/console.api.migration.halo.run/v1alpha1/backup-files": { "get": { "description": "Get backup files from backup root.", diff --git a/api-docs/openapi/v3_0/apis_console.api_v1alpha1.json b/api-docs/openapi/v3_0/apis_console.api_v1alpha1.json index 9ff6d788c..de0068c62 100644 --- a/api-docs/openapi/v3_0/apis_console.api_v1alpha1.json +++ b/api-docs/openapi/v3_0/apis_console.api_v1alpha1.json @@ -3136,6 +3136,72 @@ ] } }, + "/apis/console.api.halo.run/v1alpha1/systemconfigs/{group}": { + "get": { + "description": "Get system config by group", + "operationId": "getSystemConfigByGroup", + "parameters": [ + { + "description": "Group of the system config", + "in": "path", + "name": "group", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "default": { + "content": { + "*/*": { + "schema": { + "type": "object" + } + }, + "application/json": {} + }, + "description": "default response" + } + }, + "tags": [ + "SystemConfigV1alpha1Console" + ] + }, + "put": { + "description": "Update system config by group", + "operationId": "updateSystemConfigByGroup", + "parameters": [ + { + "description": "Group of the system config", + "in": "path", + "name": "group", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "*/*": { + "schema": { + "type": "object" + } + } + } + }, + "responses": { + "204 NO_CONTENT": { + "content": {}, + "description": "default response" + } + }, + "tags": [ + "SystemConfigV1alpha1Console" + ] + } + }, "/apis/console.api.migration.halo.run/v1alpha1/backup-files": { "get": { "description": "Get backup files from backup root.", diff --git a/ui/console-src/modules/interface/menus/components/MenuList.vue b/ui/console-src/modules/interface/menus/components/MenuList.vue index cd4fb1e1e..352ec73b8 100644 --- a/ui/console-src/modules/interface/menus/components/MenuList.vue +++ b/ui/console-src/modules/interface/menus/components/MenuList.vue @@ -1,7 +1,7 @@