mirror of https://github.com/halo-dev/halo
Add role template for managing cache (#4153)
#### What type of PR is this? /kind feature /area core /milestone 2.7.x #### What this PR does / why we need it: Add role template for managing cache. Anyone with role `role-template-manage-cache` can see the `Refresh Page Cache` button. #### Which issue(s) this PR fixes: Fixes https://github.com/halo-dev/halo/issues/4143 #### Does this PR introduce a user-facing change? ```release-note None ```pull/4155/head
parent
9a0c52fb2a
commit
4685bf4052
|
@ -2,14 +2,16 @@ package run.halo.app.cache;
|
||||||
|
|
||||||
import static io.swagger.v3.oas.annotations.enums.ParameterIn.PATH;
|
import static io.swagger.v3.oas.annotations.enums.ParameterIn.PATH;
|
||||||
import static org.springdoc.core.fn.builders.parameter.Builder.parameterBuilder;
|
import static org.springdoc.core.fn.builders.parameter.Builder.parameterBuilder;
|
||||||
|
import static org.springdoc.webflux.core.fn.SpringdocRouteBuilder.route;
|
||||||
import static org.springframework.http.HttpStatus.NO_CONTENT;
|
import static org.springframework.http.HttpStatus.NO_CONTENT;
|
||||||
|
|
||||||
import org.springdoc.core.fn.builders.apiresponse.Builder;
|
import org.springdoc.core.fn.builders.apiresponse.Builder;
|
||||||
import org.springdoc.webflux.core.fn.SpringdocRouteBuilder;
|
|
||||||
import org.springframework.cache.CacheManager;
|
import org.springframework.cache.CacheManager;
|
||||||
import org.springframework.stereotype.Component;
|
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.ServerResponse;
|
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.core.extension.endpoint.CustomEndpoint;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
|
@ -23,21 +25,11 @@ public class CacheEndpoint implements CustomEndpoint {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RouterFunction<ServerResponse> endpoint() {
|
public RouterFunction<ServerResponse> endpoint() {
|
||||||
return SpringdocRouteBuilder
|
return route()
|
||||||
.route()
|
.DELETE("/caches/{name}", this::evictCache, builder -> builder
|
||||||
.POST("/caches/{name}/invalidation", request -> {
|
|
||||||
var cacheName = request.pathVariable("name");
|
|
||||||
if (cacheManager.getCacheNames().contains(cacheName)) {
|
|
||||||
var cache = cacheManager.getCache(cacheName);
|
|
||||||
if (cache != null) {
|
|
||||||
cache.invalidate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ServerResponse.noContent().build();
|
|
||||||
}, builder -> builder
|
|
||||||
.tag("v1alpha1/Cache")
|
.tag("v1alpha1/Cache")
|
||||||
.operationId("InvalidCache")
|
.operationId("EvictCache")
|
||||||
.description("Invalidate a cache.")
|
.description("Evict a cache.")
|
||||||
.parameter(parameterBuilder()
|
.parameter(parameterBuilder()
|
||||||
.name("name")
|
.name("name")
|
||||||
.in(PATH)
|
.in(PATH)
|
||||||
|
@ -49,4 +41,14 @@ public class CacheEndpoint implements CustomEndpoint {
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Mono<ServerResponse> evictCache(ServerRequest request) {
|
||||||
|
var cacheName = request.pathVariable("name");
|
||||||
|
if (cacheManager.getCacheNames().contains(cacheName)) {
|
||||||
|
var cache = cacheManager.getCache(cacheName);
|
||||||
|
if (cache != null) {
|
||||||
|
cache.invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ServerResponse.accepted().build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
apiVersion: v1alpha1
|
||||||
|
kind: "Role"
|
||||||
|
metadata:
|
||||||
|
name: role-template-manage-cache
|
||||||
|
labels:
|
||||||
|
halo.run/role-template: "true"
|
||||||
|
annotations:
|
||||||
|
rbac.authorization.halo.run/module: "Cache Management"
|
||||||
|
rbac.authorization.halo.run/display-name: "Cache Manage"
|
||||||
|
rbac.authorization.halo.run/ui-permissions: |
|
||||||
|
["system:caches:manage"]
|
||||||
|
rules:
|
||||||
|
- apiGroups: ["api.console.halo.run"]
|
||||||
|
resources: ["caches"]
|
||||||
|
verbs: ["delete"]
|
|
@ -46,19 +46,19 @@ export const V1alpha1CacheApiAxiosParamCreator = function (
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
* Invalidate a cache.
|
* Evict a cache.
|
||||||
* @param {string} name Cache name
|
* @param {string} name Cache name
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
invalidCache: async (
|
evictCache: async (
|
||||||
name: string,
|
name: string,
|
||||||
options: AxiosRequestConfig = {}
|
options: AxiosRequestConfig = {}
|
||||||
): Promise<RequestArgs> => {
|
): Promise<RequestArgs> => {
|
||||||
// verify required parameter 'name' is not null or undefined
|
// verify required parameter 'name' is not null or undefined
|
||||||
assertParamExists("invalidCache", "name", name);
|
assertParamExists("evictCache", "name", name);
|
||||||
const localVarPath =
|
const localVarPath =
|
||||||
`/apis/api.console.halo.run/v1alpha1/caches/{name}/invalidation`.replace(
|
`/apis/api.console.halo.run/v1alpha1/caches/{name}`.replace(
|
||||||
`{${"name"}}`,
|
`{${"name"}}`,
|
||||||
encodeURIComponent(String(name))
|
encodeURIComponent(String(name))
|
||||||
);
|
);
|
||||||
|
@ -70,7 +70,7 @@ export const V1alpha1CacheApiAxiosParamCreator = function (
|
||||||
}
|
}
|
||||||
|
|
||||||
const localVarRequestOptions = {
|
const localVarRequestOptions = {
|
||||||
method: "POST",
|
method: "DELETE",
|
||||||
...baseOptions,
|
...baseOptions,
|
||||||
...options,
|
...options,
|
||||||
};
|
};
|
||||||
|
@ -111,18 +111,18 @@ export const V1alpha1CacheApiFp = function (configuration?: Configuration) {
|
||||||
V1alpha1CacheApiAxiosParamCreator(configuration);
|
V1alpha1CacheApiAxiosParamCreator(configuration);
|
||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
* Invalidate a cache.
|
* Evict a cache.
|
||||||
* @param {string} name Cache name
|
* @param {string} name Cache name
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
async invalidCache(
|
async evictCache(
|
||||||
name: string,
|
name: string,
|
||||||
options?: AxiosRequestConfig
|
options?: AxiosRequestConfig
|
||||||
): Promise<
|
): Promise<
|
||||||
(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>
|
(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>
|
||||||
> {
|
> {
|
||||||
const localVarAxiosArgs = await localVarAxiosParamCreator.invalidCache(
|
const localVarAxiosArgs = await localVarAxiosParamCreator.evictCache(
|
||||||
name,
|
name,
|
||||||
options
|
options
|
||||||
);
|
);
|
||||||
|
@ -148,32 +148,32 @@ export const V1alpha1CacheApiFactory = function (
|
||||||
const localVarFp = V1alpha1CacheApiFp(configuration);
|
const localVarFp = V1alpha1CacheApiFp(configuration);
|
||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
* Invalidate a cache.
|
* Evict a cache.
|
||||||
* @param {V1alpha1CacheApiInvalidCacheRequest} requestParameters Request parameters.
|
* @param {V1alpha1CacheApiEvictCacheRequest} requestParameters Request parameters.
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
invalidCache(
|
evictCache(
|
||||||
requestParameters: V1alpha1CacheApiInvalidCacheRequest,
|
requestParameters: V1alpha1CacheApiEvictCacheRequest,
|
||||||
options?: AxiosRequestConfig
|
options?: AxiosRequestConfig
|
||||||
): AxiosPromise<void> {
|
): AxiosPromise<void> {
|
||||||
return localVarFp
|
return localVarFp
|
||||||
.invalidCache(requestParameters.name, options)
|
.evictCache(requestParameters.name, options)
|
||||||
.then((request) => request(axios, basePath));
|
.then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request parameters for invalidCache operation in V1alpha1CacheApi.
|
* Request parameters for evictCache operation in V1alpha1CacheApi.
|
||||||
* @export
|
* @export
|
||||||
* @interface V1alpha1CacheApiInvalidCacheRequest
|
* @interface V1alpha1CacheApiEvictCacheRequest
|
||||||
*/
|
*/
|
||||||
export interface V1alpha1CacheApiInvalidCacheRequest {
|
export interface V1alpha1CacheApiEvictCacheRequest {
|
||||||
/**
|
/**
|
||||||
* Cache name
|
* Cache name
|
||||||
* @type {string}
|
* @type {string}
|
||||||
* @memberof V1alpha1CacheApiInvalidCache
|
* @memberof V1alpha1CacheApiEvictCache
|
||||||
*/
|
*/
|
||||||
readonly name: string;
|
readonly name: string;
|
||||||
}
|
}
|
||||||
|
@ -186,18 +186,18 @@ export interface V1alpha1CacheApiInvalidCacheRequest {
|
||||||
*/
|
*/
|
||||||
export class V1alpha1CacheApi extends BaseAPI {
|
export class V1alpha1CacheApi extends BaseAPI {
|
||||||
/**
|
/**
|
||||||
* Invalidate a cache.
|
* Evict a cache.
|
||||||
* @param {V1alpha1CacheApiInvalidCacheRequest} requestParameters Request parameters.
|
* @param {V1alpha1CacheApiEvictCacheRequest} requestParameters Request parameters.
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
* @memberof V1alpha1CacheApi
|
* @memberof V1alpha1CacheApi
|
||||||
*/
|
*/
|
||||||
public invalidCache(
|
public evictCache(
|
||||||
requestParameters: V1alpha1CacheApiInvalidCacheRequest,
|
requestParameters: V1alpha1CacheApiEvictCacheRequest,
|
||||||
options?: AxiosRequestConfig
|
options?: AxiosRequestConfig
|
||||||
) {
|
) {
|
||||||
return V1alpha1CacheApiFp(this.configuration)
|
return V1alpha1CacheApiFp(this.configuration)
|
||||||
.invalidCache(requestParameters.name, options)
|
.evictCache(requestParameters.name, options)
|
||||||
.then((request) => request(this.axios, this.basePath));
|
.then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,7 +124,7 @@ core:
|
||||||
dialog_title: Do you want to refresh the search engine index?
|
dialog_title: Do you want to refresh the search engine index?
|
||||||
dialog_content: This operation will recreate search engine indexes for all published posts.
|
dialog_content: This operation will recreate search engine indexes for all published posts.
|
||||||
success_message: Refresh search engine index successfully.
|
success_message: Refresh search engine index successfully.
|
||||||
refresh_page_cache:
|
evict_page_cache:
|
||||||
title: Refresh Page Cache
|
title: Refresh Page Cache
|
||||||
dialog_title: Do you want to refresh the page cache?
|
dialog_title: Do you want to refresh the page cache?
|
||||||
dialog_content: This operation will clear the cache for all pages.
|
dialog_content: This operation will clear the cache for all pages.
|
||||||
|
|
|
@ -124,7 +124,7 @@ core:
|
||||||
dialog_title: 确定要刷新搜索引擎索引吗?
|
dialog_title: 确定要刷新搜索引擎索引吗?
|
||||||
dialog_content: 此操作会对所有已发布的文章重新创建搜索引擎索引。
|
dialog_content: 此操作会对所有已发布的文章重新创建搜索引擎索引。
|
||||||
success_message: 刷新成功
|
success_message: 刷新成功
|
||||||
refresh_page_cache:
|
evict_page_cache:
|
||||||
title: 刷新页面缓存
|
title: 刷新页面缓存
|
||||||
dialog_title: 确定要刷新页面缓存吗?
|
dialog_title: 确定要刷新页面缓存吗?
|
||||||
dialog_content: 此操作会清空所有页面的缓存。
|
dialog_content: 此操作会清空所有页面的缓存。
|
||||||
|
|
|
@ -124,7 +124,7 @@ core:
|
||||||
dialog_title: 確定要刷新搜尋引擎索引嗎?
|
dialog_title: 確定要刷新搜尋引擎索引嗎?
|
||||||
dialog_content: 此操作會對所有已發布的文章重新創建搜尋引擎索引。
|
dialog_content: 此操作會對所有已發布的文章重新創建搜尋引擎索引。
|
||||||
success_message: 刷新成功
|
success_message: 刷新成功
|
||||||
refresh_page_cache:
|
evict_page_cache:
|
||||||
title: 重新整理頁面快取
|
title: 重新整理頁面快取
|
||||||
dialog_title: 確定要重新整理頁面快取嗎?
|
dialog_title: 確定要重新整理頁面快取嗎?
|
||||||
dialog_content: 這個操作會清空所有頁面的快取。
|
dialog_content: 這個操作會清空所有頁面的快取。
|
||||||
|
|
|
@ -160,28 +160,29 @@ const actions: Action[] = [
|
||||||
{
|
{
|
||||||
icon: markRaw(IconDatabase2Line),
|
icon: markRaw(IconDatabase2Line),
|
||||||
title: t(
|
title: t(
|
||||||
"core.dashboard.widgets.presets.quicklink.actions.refresh_page_cache.title"
|
"core.dashboard.widgets.presets.quicklink.actions.evict_page_cache.title"
|
||||||
),
|
),
|
||||||
action: () => {
|
action: () => {
|
||||||
Dialog.warning({
|
Dialog.warning({
|
||||||
title: t(
|
title: t(
|
||||||
"core.dashboard.widgets.presets.quicklink.actions.refresh_page_cache.dialog_title"
|
"core.dashboard.widgets.presets.quicklink.actions.evict_page_cache.dialog_title"
|
||||||
),
|
),
|
||||||
description: t(
|
description: t(
|
||||||
"core.dashboard.widgets.presets.quicklink.actions.refresh_page_cache.dialog_content"
|
"core.dashboard.widgets.presets.quicklink.actions.evict_page_cache.dialog_content"
|
||||||
),
|
),
|
||||||
confirmText: t("core.common.buttons.confirm"),
|
confirmText: t("core.common.buttons.confirm"),
|
||||||
cancelText: t("core.common.buttons.cancel"),
|
cancelText: t("core.common.buttons.cancel"),
|
||||||
onConfirm: async () => {
|
onConfirm: async () => {
|
||||||
await apiClient.cache.invalidCache({ name: "page" });
|
await apiClient.cache.evictCache({ name: "page" });
|
||||||
Toast.success(
|
Toast.success(
|
||||||
t(
|
t(
|
||||||
"core.dashboard.widgets.presets.quicklink.actions.refresh_page_cache.success_message"
|
"core.dashboard.widgets.presets.quicklink.actions.evict_page_cache.success_message"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
permissions: ["system:caches:manage"],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
</script>
|
</script>
|
||||||
|
|
Loading…
Reference in New Issue