Skip to content

Commit

Permalink
Merge pull request #6729 from guqing/feature/5851
Browse files Browse the repository at this point in the history
feat: support deleting posts in user center
  • Loading branch information
JohnNiang authored Oct 7, 2024
2 parents f78f7da + 5b2bdfd commit dfbab28
Show file tree
Hide file tree
Showing 11 changed files with 233 additions and 3 deletions.
32 changes: 32 additions & 0 deletions api-docs/openapi/v3_0/aggregated.json
Original file line number Diff line number Diff line change
Expand Up @@ -15117,6 +15117,38 @@
]
}
},
"/apis/uc.api.content.halo.run/v1alpha1/posts/{name}/recycle": {
"delete": {
"description": "Move my post to recycle bin.",
"operationId": "RecycleMyPost",
"parameters": [
{
"description": "Post name",
"in": "path",
"name": "name",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"default": {
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/Post"
}
}
},
"description": "default response"
}
},
"tags": [
"PostV1alpha1Uc"
]
}
},
"/apis/uc.api.content.halo.run/v1alpha1/posts/{name}/unpublish": {
"put": {
"description": "Unpublish my post.",
Expand Down
32 changes: 32 additions & 0 deletions api-docs/openapi/v3_0/apis_uc.api_v1alpha1.json
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,38 @@
]
}
},
"/apis/uc.api.content.halo.run/v1alpha1/posts/{name}/recycle": {
"delete": {
"description": "Move my post to recycle bin.",
"operationId": "RecycleMyPost",
"parameters": [
{
"description": "Post name",
"in": "path",
"name": "name",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"default": {
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/Post"
}
}
},
"description": "default response"
}
},
"tags": [
"PostV1alpha1Uc"
]
}
},
"/apis/uc.api.content.halo.run/v1alpha1/posts/{name}/unpublish": {
"put": {
"description": "Unpublish my post.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,6 @@ public interface PostService {
Mono<Post> revertToSpecifiedSnapshot(String postName, String snapshotName);

Mono<ContentWrapper> deleteContent(String postName, String snapshotName);

Mono<Post> recycleBy(String postName, String username);
}
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,15 @@ public Mono<ContentWrapper> deleteContent(String postName, String snapshotName)
});
}

@Override
public Mono<Post> recycleBy(String postName, String username) {
return getByUsername(postName, username)
.flatMap(post -> updatePostWithRetry(post, record -> {
record.getSpec().setDeleted(true);
return record;
}));
}

private Mono<Post> updatePostWithRetry(Post post, UnaryOperator<Post> func) {
return client.update(func.apply(post))
.onErrorResume(OptimisticLockingFailureException.class,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,27 @@ public RouterFunction<ServerResponse> endpoint() {
.operationId("UnpublishMyPost")
.description("Unpublish my post.")
.parameter(namePathParam)
.response(responseBuilder().implementation(Post.class)))
.response(responseBuilder().implementation(Post.class))
)
.DELETE("/{name}/recycle", this::recycleMyPost, builder -> builder.tag(tag)
.operationId("RecycleMyPost")
.description("Move my post to recycle bin.")
.parameter(namePathParam)
.response(responseBuilder().implementation(Post.class))
)
.build(),
builder -> {
})
.build();
}

private Mono<ServerResponse> recycleMyPost(ServerRequest request) {
final var name = request.pathVariable("name");
return getCurrentUser()
.flatMap(username -> postService.recycleBy(name, username))
.flatMap(post -> ServerResponse.ok().bodyValue(post));
}

private Mono<ServerResponse> getMyPostDraft(ServerRequest request) {
var name = request.pathVariable("name");
var patched = request.queryParam("patched").map(Boolean::valueOf).orElse(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ metadata:
# Currently, yaml definition does not support i18n, please see https://github.com/halo-dev/halo/issues/3573
rbac.authorization.halo.run/display-name: "Post Author"
rbac.authorization.halo.run/dependencies: |
[ "role-template-post-contributor", "role-template-post-publisher", "role-template-post-attachment-manager" ]
[ "role-template-post-contributor", "role-template-post-publisher", "role-template-recycle-my-post",
"role-template-post-attachment-manager" ]
rules: [ ]

---
Expand Down Expand Up @@ -98,6 +99,23 @@ rules:
resources: [ "posts/publish", "posts/unpublish" ]
verbs: [ "update" ]

---
apiVersion: v1alpha1
kind: Role
metadata:
name: role-template-recycle-my-post
labels:
halo.run/role-template: "true"
annotations:
rbac.authorization.halo.run/module: "Posts Management"
rbac.authorization.halo.run/display-name: "Recycle My Post"
rbac.authorization.halo.run/ui-permissions: |
[ "uc:posts:recycle" ]
rules:
- apiGroups: [ "uc.api.content.halo.run" ]
resources: [ "posts/recycle" ]
verbs: [ "delete" ]

---
apiVersion: v1alpha1
kind: Role
Expand Down
87 changes: 87 additions & 0 deletions ui/packages/api-client/src/api/post-v1alpha1-uc-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,47 @@ export const PostV1alpha1UcApiAxiosParamCreator = function (configuration?: Conf



setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};

return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
* Move my post to recycle bin.
* @param {string} name Post name
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
recycleMyPost: async (name: string, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'name' is not null or undefined
assertParamExists('recycleMyPost', 'name', name)
const localVarPath = `/apis/uc.api.content.halo.run/v1alpha1/posts/{name}/recycle`
.replace(`{${"name"}}`, encodeURIComponent(String(name)));
// 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: 'DELETE', ...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)



setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
Expand Down Expand Up @@ -488,6 +529,18 @@ export const PostV1alpha1UcApiFp = function(configuration?: Configuration) {
const localVarOperationServerBasePath = operationServerMap['PostV1alpha1UcApi.publishMyPost']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
* Move my post to recycle bin.
* @param {string} name Post name
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async recycleMyPost(name: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Post>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.recycleMyPost(name, options);
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
const localVarOperationServerBasePath = operationServerMap['PostV1alpha1UcApi.recycleMyPost']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
* Unpublish my post.
* @param {string} name Post name
Expand Down Expand Up @@ -581,6 +634,15 @@ export const PostV1alpha1UcApiFactory = function (configuration?: Configuration,
publishMyPost(requestParameters: PostV1alpha1UcApiPublishMyPostRequest, options?: RawAxiosRequestConfig): AxiosPromise<Post> {
return localVarFp.publishMyPost(requestParameters.name, options).then((request) => request(axios, basePath));
},
/**
* Move my post to recycle bin.
* @param {PostV1alpha1UcApiRecycleMyPostRequest} requestParameters Request parameters.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
recycleMyPost(requestParameters: PostV1alpha1UcApiRecycleMyPostRequest, options?: RawAxiosRequestConfig): AxiosPromise<Post> {
return localVarFp.recycleMyPost(requestParameters.name, options).then((request) => request(axios, basePath));
},
/**
* Unpublish my post.
* @param {PostV1alpha1UcApiUnpublishMyPostRequest} requestParameters Request parameters.
Expand Down Expand Up @@ -737,6 +799,20 @@ export interface PostV1alpha1UcApiPublishMyPostRequest {
readonly name: string
}

/**
* Request parameters for recycleMyPost operation in PostV1alpha1UcApi.
* @export
* @interface PostV1alpha1UcApiRecycleMyPostRequest
*/
export interface PostV1alpha1UcApiRecycleMyPostRequest {
/**
* Post name
* @type {string}
* @memberof PostV1alpha1UcApiRecycleMyPost
*/
readonly name: string
}

/**
* Request parameters for unpublishMyPost operation in PostV1alpha1UcApi.
* @export
Expand Down Expand Up @@ -855,6 +931,17 @@ export class PostV1alpha1UcApi extends BaseAPI {
return PostV1alpha1UcApiFp(this.configuration).publishMyPost(requestParameters.name, options).then((request) => request(this.axios, this.basePath));
}

/**
* Move my post to recycle bin.
* @param {PostV1alpha1UcApiRecycleMyPostRequest} requestParameters Request parameters.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof PostV1alpha1UcApi
*/
public recycleMyPost(requestParameters: PostV1alpha1UcApiRecycleMyPostRequest, options?: RawAxiosRequestConfig) {
return PostV1alpha1UcApiFp(this.configuration).recycleMyPost(requestParameters.name, options).then((request) => request(this.axios, this.basePath));
}

/**
* Unpublish my post.
* @param {PostV1alpha1UcApiUnpublishMyPostRequest} requestParameters Request parameters.
Expand Down
4 changes: 4 additions & 0 deletions ui/src/locales/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1517,6 +1517,7 @@ core:
Post Author: Allows you to manage your own posts
Post Contributor: Contributions allowed
Post Publisher: Allow to publish own posts
Recycle My Post: Recycle My Post
components:
submit_button:
computed_text: "{text} ({shortcut})"
Expand Down Expand Up @@ -1791,6 +1792,9 @@ core:
cancel_publish:
description: Are you sure you want to cancel publishing?
title: Cancel publish
delete:
title: Delete post
description: This action will move the post to the recycle bin, where it will be managed by the site administrator.
publish_modal:
title: Publish post
setting_modal:
Expand Down
4 changes: 4 additions & 0 deletions ui/src/locales/zh-CN.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,9 @@ core:
cancel_publish:
title: 取消发布
description: 确定要取消发布吗?
delete:
title: 删除文章
description: 该操作会将文章放入回收站,后续由网站管理员进行管理。
post_editor:
title: 文章编辑
untitled: 未命名文章
Expand Down Expand Up @@ -1415,6 +1418,7 @@ core:
Post Author: 允许管理自己的文章
Post Attachment Manager: 允许在文章中上传图片
Post Publisher: 允许发布自己的文章
Recycle My Post: 允许删除自己的文章
components:
submit_button:
computed_text: "{text}({shortcut})"
Expand Down
4 changes: 4 additions & 0 deletions ui/src/locales/zh-TW.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1394,6 +1394,7 @@ core:
Post Author: 允許管理自己的文章
Post Contributor: 允許投稿
Post Publisher: 允許發布自己的文章
Recycle My Post: 允許刪除自己的文章
components:
submit_button:
computed_text: "{text}({shortcut})"
Expand Down Expand Up @@ -1659,6 +1660,9 @@ core:
cancel_publish:
description: 確定要取消發布嗎?
title: 取消發布
delete:
title: 刪除文章
description: 該操作會將文章放入回收站,後續由網站管理員進行管理。
publish_modal:
title: 發布文章
setting_modal:
Expand Down
26 changes: 25 additions & 1 deletion ui/uc-src/modules/contents/posts/components/PostListItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,25 @@ function handleUnpublish() {
},
});
}
function handleDelete() {
Dialog.warning({
title: t("core.uc_post.operations.delete.title"),
description: t("core.uc_post.operations.delete.description"),
confirmType: "danger",
confirmText: t("core.common.buttons.confirm"),
cancelText: t("core.common.buttons.cancel"),
async onConfirm() {
await ucApiClient.content.post.recycleMyPost({
name: props.post.post.metadata.name,
});
Toast.success(t("core.common.toast.delete_success"));
queryClient.invalidateQueries({ queryKey: ["my-posts"] });
},
});
}
</script>

<template>
Expand Down Expand Up @@ -246,11 +265,16 @@ function handleUnpublish() {
{{ $t("core.common.buttons.edit") }}
</VDropdownItem>
<HasPermission v-if="!isPublished" :permissions="['uc:posts:publish']">
<VDropdownDivider />
<VDropdownItem type="danger" @click="handleUnpublish">
{{ $t("core.common.buttons.cancel_publish") }}
</VDropdownItem>
</HasPermission>
<HasPermission :permissions="['uc:posts:recycle']">
<VDropdownDivider />
<VDropdownItem type="danger" @click="handleDelete">
{{ $t("core.common.buttons.delete") }}
</VDropdownItem>
</HasPermission>
</template>
</VEntity>
</template>

0 comments on commit dfbab28

Please sign in to comment.