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"