diff --git a/README.md b/README.md index 3b18c4e88a..313118682f 100755 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

- - Halo logo + + Halo logo

@@ -14,7 +14,7 @@ Codecov percentage Halo - Powerful and easy-to-use Open-Source website building tool | Product Hunt
-官网 +官网 文档 社区 Gitee @@ -26,7 +26,7 @@ ## 快速开始 ```bash -docker run -it -d --name halo -p 8090:8090 -v ~/.halo2:/root/.halo2 halohub/halo:2.11 +docker run -it -d --name halo -p 8090:8090 -v ~/.halo2:/root/.halo2 halohub/halo:2.12 ``` 以上仅作为体验使用,详细部署文档请查阅: @@ -40,8 +40,7 @@ docker run -it -d --name halo -p 8090:8090 -v ~/.halo2:/root/.halo2 halohub/halo ## 生态 -可访问 [官方应用市场](https://halo.run/store/apps) 或 [awesome-halo 仓库](https://github.com/halo-sigs/awesome-halo) 查看已经适用于 Halo 2.x 的主题和插件,以及适用于 Halo -1.x 的相关仓库。 +可访问 [官方应用市场](https://www.halo.run/store/apps) 或 [awesome-halo 仓库](https://github.com/halo-sigs/awesome-halo) 查看适用于 Halo 2.x 的主题和插件。 ## 许可证 diff --git a/application/src/main/java/run/halo/app/notification/endpoint/UserNotificationPreferencesEndpoint.java b/application/src/main/java/run/halo/app/notification/endpoint/UserNotificationPreferencesEndpoint.java index 90948904d0..9916d90ed5 100644 --- a/application/src/main/java/run/halo/app/notification/endpoint/UserNotificationPreferencesEndpoint.java +++ b/application/src/main/java/run/halo/app/notification/endpoint/UserNotificationPreferencesEndpoint.java @@ -5,17 +5,20 @@ import static org.springdoc.core.fn.builders.parameter.Builder.parameterBuilder; import static org.springdoc.core.fn.builders.requestbody.Builder.requestBodyBuilder; +import com.fasterxml.jackson.core.type.TypeReference; import io.swagger.v3.oas.annotations.enums.ParameterIn; import io.swagger.v3.oas.annotations.media.Schema; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.function.Function; import java.util.function.Supplier; import lombok.Data; import lombok.RequiredArgsConstructor; import lombok.experimental.Accessors; +import org.apache.commons.lang3.StringUtils; import org.springdoc.webflux.core.fn.SpringdocRouteBuilder; import org.springframework.lang.NonNull; import org.springframework.stereotype.Component; @@ -25,12 +28,15 @@ import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Mono; import reactor.util.function.Tuples; +import run.halo.app.core.extension.Role; import run.halo.app.core.extension.endpoint.CustomEndpoint; import run.halo.app.core.extension.notification.NotifierDescriptor; import run.halo.app.core.extension.notification.ReasonType; import run.halo.app.extension.Comparators; import run.halo.app.extension.GroupVersion; +import run.halo.app.extension.MetadataUtil; import run.halo.app.extension.ReactiveExtensionClient; +import run.halo.app.infra.utils.JsonUtils; import run.halo.app.notification.UserNotificationPreference; import run.halo.app.notification.UserNotificationPreferenceService; @@ -135,10 +141,7 @@ private static Map toNameIndexMap(List collection, Mono listReasonTypeNotifierMatrix(String username) { return client.list(ReasonType.class, null, Comparators.defaultComparator()) - .map(reasonType -> new ReasonTypeInfo(reasonType.getMetadata().getName(), - reasonType.getSpec().getDisplayName(), - reasonType.getSpec().getDescription()) - ) + .map(ReasonTypeInfo::from) .collectList() .flatMap(reasonTypes -> client.list(NotifierDescriptor.class, null, Comparators.defaultComparator()) @@ -188,7 +191,23 @@ static class ReasonTypeNotifierMatrix { private boolean[][] stateMatrix; } - record ReasonTypeInfo(String name, String displayName, String description) { + record ReasonTypeInfo(String name, String displayName, String description, + Set uiPermissions) { + + public static ReasonTypeInfo from(ReasonType reasonType) { + var uiPermissions = Optional.of(MetadataUtil.nullSafeAnnotations(reasonType)) + .map(annotations -> annotations.get(Role.UI_PERMISSIONS_ANNO)) + .filter(StringUtils::isNotBlank) + .map(uiPermissionStr -> JsonUtils.jsonToObject(uiPermissionStr, + new TypeReference>() { + }) + ) + .orElse(Set.of()); + return new ReasonTypeInfo(reasonType.getMetadata().getName(), + reasonType.getSpec().getDisplayName(), + reasonType.getSpec().getDescription(), + uiPermissions); + } } record NotifierInfo(String name, String displayName, String description) { diff --git a/application/src/main/resources/extensions/notification.yaml b/application/src/main/resources/extensions/notification.yaml index 23429a95ad..3fd11c9195 100644 --- a/application/src/main/resources/extensions/notification.yaml +++ b/application/src/main/resources/extensions/notification.yaml @@ -64,6 +64,9 @@ apiVersion: notification.halo.run/v1alpha1 kind: ReasonType metadata: name: new-comment-on-post + annotations: + rbac.authorization.halo.run/ui-permissions: | + [ "uc:posts:publish" ] spec: displayName: "我的文章收到新评论" description: "如果有读者在你的文章下方留下了新的评论,你将会收到一条通知,告诉你有新的评论。 @@ -90,6 +93,9 @@ apiVersion: notification.halo.run/v1alpha1 kind: ReasonType metadata: name: new-comment-on-single-page + annotations: + rbac.authorization.halo.run/ui-permissions: | + [ "system:singlepages:manage" ] spec: displayName: "我的自定义页面收到新评论" description: "当你创建的自定义页面收到新评论时,你将会收到一条通知,告诉你有新的评论。" diff --git a/application/src/main/resources/extensions/role-template-authenticated.yaml b/application/src/main/resources/extensions/role-template-authenticated.yaml index 03055e067d..2c2bf3bd54 100644 --- a/application/src/main/resources/extensions/role-template-authenticated.yaml +++ b/application/src/main/resources/extensions/role-template-authenticated.yaml @@ -127,7 +127,7 @@ metadata: halo.run/hidden: "true" rules: - apiGroups: [ "api.security.halo.run" ] - resources: [ "authentications", "authentications/totp" ] + resources: [ "authentications", "authentications/totp", "authentications/settings" ] verbs: [ "*" ] --- apiVersion: v1alpha1 diff --git a/console/packages/api-client/package.json b/console/packages/api-client/package.json index a40dc7f91f..b84c70009f 100644 --- a/console/packages/api-client/package.json +++ b/console/packages/api-client/package.json @@ -1,6 +1,6 @@ { "name": "@halo-dev/api-client", - "version": "2.12.0", + "version": "2.13.0", "description": "", "scripts": { "build": "unbuild", diff --git a/console/packages/api-client/src/models/post-status.ts b/console/packages/api-client/src/models/post-status.ts index dbc5bd93ad..b59635bcce 100644 --- a/console/packages/api-client/src/models/post-status.ts +++ b/console/packages/api-client/src/models/post-status.ts @@ -58,6 +58,12 @@ export interface PostStatus { * @memberof PostStatus */ lastModifyTime?: string; + /** + * + * @type {number} + * @memberof PostStatus + */ + observedVersion?: number; /** * * @type {string} diff --git a/console/packages/api-client/src/models/reason-type-info.ts b/console/packages/api-client/src/models/reason-type-info.ts index 1008af2c5e..422b2cabdc 100644 --- a/console/packages/api-client/src/models/reason-type-info.ts +++ b/console/packages/api-client/src/models/reason-type-info.ts @@ -36,4 +36,10 @@ export interface ReasonTypeInfo { * @memberof ReasonTypeInfo */ name?: string; + /** + * + * @type {Array} + * @memberof ReasonTypeInfo + */ + uiPermissions?: Array; } diff --git a/console/packages/api-client/src/models/single-page-status.ts b/console/packages/api-client/src/models/single-page-status.ts index 29c74e3594..6972c42374 100644 --- a/console/packages/api-client/src/models/single-page-status.ts +++ b/console/packages/api-client/src/models/single-page-status.ts @@ -58,6 +58,12 @@ export interface SinglePageStatus { * @memberof SinglePageStatus */ lastModifyTime?: string; + /** + * + * @type {number} + * @memberof SinglePageStatus + */ + observedVersion?: number; /** * * @type {string} diff --git a/console/packages/components/package.json b/console/packages/components/package.json index 73795bee39..8eabb6dfa6 100644 --- a/console/packages/components/package.json +++ b/console/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@halo-dev/components", - "version": "2.12.0", + "version": "2.13.0", "description": "", "files": [ "dist" diff --git a/console/packages/editor/package.json b/console/packages/editor/package.json index dbdc069546..18a20617e8 100644 --- a/console/packages/editor/package.json +++ b/console/packages/editor/package.json @@ -1,6 +1,6 @@ { "name": "@halo-dev/richtext-editor", - "version": "2.12.0", + "version": "2.13.0", "description": "Default editor for Halo", "homepage": "https://github.com/halo-dev/halo/tree/main/console/packages/editor#readme", "bugs": { diff --git a/console/packages/editor/src/dev/App.vue b/console/packages/editor/src/dev/App.vue index a8f26cd8f3..a9509019ad 100644 --- a/console/packages/editor/src/dev/App.vue +++ b/console/packages/editor/src/dev/App.vue @@ -112,6 +112,9 @@ const editor = useEditor({ ExtensionListKeymap, ExtensionSearchAndReplace, ], + parseOptions: { + preserveWhitespace: true, + }, onUpdate: () => { content.value = editor.value?.getHTML() + ""; }, diff --git a/console/packages/shared/package.json b/console/packages/shared/package.json index 6269ac5fc3..10ba3b5ed7 100644 --- a/console/packages/shared/package.json +++ b/console/packages/shared/package.json @@ -1,6 +1,6 @@ { "name": "@halo-dev/console-shared", - "version": "2.12.0", + "version": "2.13.0", "description": "", "files": [ "dist" diff --git a/console/packages/ui-plugin-bundler-kit/package.json b/console/packages/ui-plugin-bundler-kit/package.json index d88d7409a8..b961b485d9 100644 --- a/console/packages/ui-plugin-bundler-kit/package.json +++ b/console/packages/ui-plugin-bundler-kit/package.json @@ -1,6 +1,6 @@ { "name": "@halo-dev/ui-plugin-bundler-kit", - "version": "2.12.0", + "version": "2.13.0", "homepage": "https://github.com/halo-dev/halo/tree/main/console/packages/ui-plugin-bundler-kit#readme", "bugs": { "url": "https://github.com/halo-dev/halo/issues" diff --git a/console/src/components/editor/DefaultEditor.vue b/console/src/components/editor/DefaultEditor.vue index cd4dfed201..cbead8137d 100644 --- a/console/src/components/editor/DefaultEditor.vue +++ b/console/src/components/editor/DefaultEditor.vue @@ -392,6 +392,9 @@ onMounted(() => { ExtensionSearchAndReplace, ], autofocus: "start", + parseOptions: { + preserveWhitespace: true, + }, onUpdate: () => { debounceOnUpdate(); }, diff --git a/console/src/constants/labels.ts b/console/src/constants/labels.ts index 1cb0ac071b..63939483ca 100644 --- a/console/src/constants/labels.ts +++ b/console/src/constants/labels.ts @@ -6,6 +6,7 @@ export enum pluginLabels { // role export enum roleLabels { TEMPLATE = "halo.run/role-template", + HIDDEN = "halo.run/hidden", SYSTEM_RESERVED = "rbac.authorization.halo.run/system-reserved", } diff --git a/console/uc-src/modules/profile/components/PersonalAccessTokenCreationModal.vue b/console/uc-src/modules/profile/components/PersonalAccessTokenCreationModal.vue index dee7ab2d23..e868a29cab 100644 --- a/console/uc-src/modules/profile/components/PersonalAccessTokenCreationModal.vue +++ b/console/uc-src/modules/profile/components/PersonalAccessTokenCreationModal.vue @@ -7,11 +7,11 @@ import { Dialog, Toast, VButton, VModal, VSpace } from "@halo-dev/components"; import { useMutation, useQueryClient } from "@tanstack/vue-query"; import { useClipboard } from "@vueuse/core"; import type { PatSpec, PersonalAccessToken } from "@halo-dev/api-client"; -import { ref } from "vue"; +import { computed, ref } from "vue"; import { useRoleTemplateSelection } from "@/composables/use-role"; import { useRoleStore } from "@/stores/role"; -import { toRefs } from "vue"; import { useI18n } from "vue-i18n"; +import { roleLabels } from "@/constants/labels"; const queryClient = useQueryClient(); const { t } = useI18n(); @@ -45,8 +45,17 @@ const formState = ref< const { permissions } = useRoleStore(); +const availableRoleTemplates = computed(() => { + return permissions.permissions.filter((role) => { + return ( + role.metadata.labels?.[roleLabels.TEMPLATE] === "true" && + role.metadata.labels?.[roleLabels.HIDDEN] !== "true" + ); + }); +}); + const { roleTemplateGroups, handleRoleTemplateSelect, selectedRoleTemplates } = - useRoleTemplateSelection(toRefs(permissions).permissions); + useRoleTemplateSelection(availableRoleTemplates); const { copy } = useClipboard({ legacy: true, diff --git a/console/uc-src/modules/profile/tabs/NotificationPreferences.vue b/console/uc-src/modules/profile/tabs/NotificationPreferences.vue index 9d96635543..32b3d457ca 100644 --- a/console/uc-src/modules/profile/tabs/NotificationPreferences.vue +++ b/console/uc-src/modules/profile/tabs/NotificationPreferences.vue @@ -8,6 +8,7 @@ import { computed } from "vue"; import { inject } from "vue"; import { cloneDeep } from "lodash-es"; import type { ReasonTypeNotifierRequest } from "@halo-dev/api-client"; +import HasPermission from "@/components/permission/HasPermission.vue"; const queryClient = useQueryClient(); @@ -114,37 +115,41 @@ const { - - - {{ reasonType.displayName }} - - - - - + + + + {{ reasonType.displayName }} + + + + + + + diff --git a/gradle.properties b/gradle.properties index c7eda50352..352c7aad1f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=2.12.0-SNAPSHOT +version=2.13.0-SNAPSHOT