Commit Graph

5159 Commits (d68dca931b3c42632794e61e8a3f2be7c4f94a85)

Author SHA1 Message Date
Ryan Wang 2ae5d222d9
feat: add batch setting for partial post fields (#6142)
#### What type of PR is this?

/kind feature
/area ui
/milestone 2.17.x

#### What this PR does / why we need it:

支持批量为文章设置部分属性。

![image](https://github.com/halo-dev/halo/assets/21301288/cc4aa912-20ba-4b50-869b-705702f56d7d)

#### Which issue(s) this PR fixes:

Fixes https://github.com/halo-dev/halo/issues/4631

#### Special notes for your reviewer:

#### Does this PR introduce a user-facing change?

```release-note
支持批量为文章设置部分属性。
```
2024-06-26 09:58:50 +00:00
Takagi 5d5df7c7a9
feat: add dynamic list input (#6146)
#### What type of PR is this?

/kind feature
/area ui
/milestone 2.17.x

#### What this PR does / why we need it:

为 formkit 增加动态列表的 input。

使用方式:

```
- $formkit: list
  name: users
  label: Users
  addLabel: Add User
  min: 1
  max: 3
  itemType: string
  children:
    - $formkit: text
      index: "$index"
      validation: required
```

> [!NOTE]
> `list` 组件有且只有一个子节点,并且必须为子节点传递 `index` 属性。若想提供多个字段,则建议使用 `group` 组件包裹。

#### How to test it?

测试动态数组是否正常可用。保存的结果是否为 `{users: ["", ""]}`

#### Which issue(s) this PR fixes:

Fixes #6098

#### Does this PR introduce a user-facing change?
```release-note
为 Formkit 增加动态列表的 input 组件 list
```
2024-06-26 09:48:49 +00:00
guqing ae6724a2b6
feat: implement persistent token based remember me mechanism (#6131)
#### What type of PR is this?
/kind feature
/area core
/milestone 2.17.x

#### What this PR does / why we need it:
新增基于持久化 Token 的 RememberMe 机制

本次更新引入了一种新的 RememberMe 机制,该机制基于持久化 Token,以增强安全性和管理灵活性。在此之前,RememberMe 功能通过以下方式生成 Token,并将其作为 cookie 发送回客户端:
```
 username + ":" + expiryTime + ":" + algorithmName + ":"
   + algorithmHex(username + ":" + expiryTime + ":" + password + ":" + key)
```
此方法的优点在于无需存储 Token 就可以进行验证,并且用户密码的更改会自动使 Token 失效。然而,它的主要缺点是缺乏管理能力,例如无法手动撤销 Token。

鉴于最新的设备管理需求(见 PR #6100),我们需要一种支持设备撤销(revoke)的机制。因此,我们采用了持久化 Token 的方式,并通过随机生成的方法来提高安全性,而不将用户名和密码直接签名在 Token 中。新的 Token 格式如下:
```
base64(tokenValue:series)
```
此更改将为系统带来更高的安全保障和更灵活的管理选项,特别是在需要高度控制和监管设备访问时。

#### Does this PR introduce a user-facing change?
```release-note
引入基于持久化 Token 的新 RememberMe 机制以增强安全性和管理灵活性,升级后需要重新登录
```
2024-06-26 08:40:49 +00:00
guqing 3f94cfc9a8
refactor: add list options for sync all synchronizer (#6145)
#### What type of PR is this?
/kind improvement
/area core
/milestone 2.17.x

#### What this PR does / why we need it:
为启动时同步添加 ListOptions 选项为后续保持 ExtensionMatcher 的纯粹做准备,后续将移除 ExtensionMatcher 中多余的方法声明,只保留 match 方法,最终的结果希望是
```java
@FunctionalInterface
public interface ExtensionMatcher {
    boolean match(Extension extension);
}
```
以前构建 Controller 的写法
```java
public Controller setupWith(ControllerBuilder builder) {
         return builder
            .extension(new Post())
            .onAddMatcher(DefaultExtensionMatcher.builder(client, Post.GVK)
                .fieldSelector(FieldSelector.of(
                    equal(Post.REQUIRE_SYNC_ON_STARTUP_INDEX_NAME, TRUE))
                )
                .build()
            )
           .build();
}
```
现在的写法
```java
public Controller setupWith(ControllerBuilder builder) {
        var post = new Post();
        return builder
            .extension(post)
            // 当有新数据添加时
            .onAddMatcher(extension -> "fake-post".equals(extension.getMetadata().getName()))
            // 使用 syncAllListOptions 作为启动时同步的查询条件过滤不需要的数据
            .syncAllListOptions(ListOptions.builder()
                .fieldQuery(equal(Post.REQUIRE_SYNC_ON_STARTUP_INDEX_NAME, TRUE))
                .build()
            )
            .build();
    }
```

#### Does this PR introduce a user-facing change?
```release-note
开发者相关:重构 ControllerBuilder 的匹配条件并增加 syncAllListOptions 作为启动时同步的查询条件
```
2024-06-26 06:50:50 +00:00
guqing 50f751dda2
refactor: add builder for list options (#6148)
#### What type of PR is this?
/kind improvement
/area core
/milestone 2.17.x

#### What this PR does / why we need it:
为 ListOptions 增加 Builder 以方便构建 ListOptions 对象,可以通过以下形式创建
```java
var listOptions = ListOptions.builder()
                .labelSelector()// 构建 LabelSelector
                .eq("key-1", "value-1")
                .notEq("key-2", "value-1")
                .exists("key-3")
                .end()// 结束构建 LabelSelector
                .fieldQuery(equal("spec.title", "fake-title"))  // 构建 FieldSelector
                .andQuery(equal("spec.slug", "fake-slug"))
                .orQuery(equal("spec.slug", "test"))
                .build();
```

#### Does this PR introduce a user-facing change?
```release-note
开发者相关:支持通过 Builder 来简化 ListOptions 的构建
```
2024-06-26 06:44:49 +00:00
Takagi ba2987b585
feat: range selection feature to default editor (#6117)
#### What type of PR is this?

/kind feature
/area editor
/milestone 2.17.x

#### What this PR does / why we need it:

为默认编辑器添加 `RangeSelection` 选择器。

<img width="989" alt="image" src="https://github.com/halo-dev/halo/assets/31335418/c976cf99-0d6e-4346-9b05-8b9b0dc95183">


它的功能基本与 TextSelection 相反,例如:

1. TextSelection 支持光标展示,RangeSelection 不允许空内容,即它并不支持光标。
2. TextSelection 会抛弃被选择的 Node 节点部分偏移量,而 RangeSelection 会扩展偏移量至 Node 节点结束。
3. TextSelection 支持 Text 而 RangeSelection 支持 Node 节点。

`RangeSelection` 可以用于范围选中块节点并进行操作,可用于全选内容并进行删除操作。

#### How to test it?

测试使用点击,拖拽,释放鼠标的操作,能否选中某些节点。
测试删除选中的节点。

#### Which issue(s) this PR fixes:

Fixes #5194

#### Does this PR introduce a user-facing change?
```release-note
为默认编辑器添加 RangeSelection 选择器
```
2024-06-26 06:14:50 +00:00
Takagi c1ba566e08
fix: autosave content feature not working (#6147)
#### What type of PR is this?

/kind bug
/area ui
/milestone 2.17.x

#### What this PR does / why we need it:

解决自动保存失效的问题

#### How to test it?

测试文章、页面输入内容后,点击其他页面是否能够自动保存。

#### Which issue(s) this PR fixes:

Fixes #6129 

#### Does this PR introduce a user-facing change?
```release-note
解决文章自动保存失效的问题
```
2024-06-26 06:10:49 +00:00
Ryan Wang 88db1976c8
refactor: hide move group button when no attachment groups are present (#6138)
#### What type of PR is this?

/area ui
/kind improvement
/milestone 2.17.x

#### What this PR does / why we need it:

选择附件时,如果当前没有分组,改为不显示移动按钮。

<img width="385" alt="image" src="https://github.com/halo-dev/halo/assets/21301288/2d805f29-ecea-4469-b305-e217bd17db8b">

<img width="497" alt="image" src="https://github.com/halo-dev/halo/assets/21301288/34800eb1-8fae-42fa-b875-929a3d912967">


#### Which issue(s) this PR fixes:

Fixes #6124 

#### Does this PR introduce a user-facing change?

```release-note
None
```
2024-06-26 04:26:49 +00:00
Ryan Wang f09b685d28
refactor: remove phone field for user form (#6139)
#### What type of PR is this?

/area ui
/kind improvement
/milestone 2.17.x

#### What this PR does / why we need it:

移除用户创建/编辑表单的手机号字段,当前手机号在系统中没有任何使用。

#### Does this PR introduce a user-facing change?

```release-note
None
```
2024-06-26 03:56:48 +00:00
Ryan Wang aee39906a4
refactor: preserve post title when opening settings (#6122)
#### What type of PR is this?

/area ui
/kind improvement
/milestone 2.17.x

#### What this PR does / why we need it:

在文章编辑页面,打开文章设置时,支持保存标题,防止已修改的标题恢复为之前的值。

#### Which issue(s) this PR fixes:

Fixes https://github.com/halo-dev/halo/issues/6058

#### Does this PR introduce a user-facing change?

```release-note
优化文章编辑页面自动保存标题的功能
```
2024-06-26 03:52:48 +00:00
guqing d6da4c6bba
chore: upgrade pf4j version to 3.12.0 (#6143)
#### What type of PR is this?
/kind bug
/area core
/milestone 2.17.x

#### What this PR does / why we need it:
升级 pf4j 至 3.12.0 版本以解决插件依赖解析不正确的问题

#### Which issue(s) this PR fixes:
Fixes #5616

#### Does this PR introduce a user-facing change?
```release-note
升级 pf4j 至 3.12.0 版本以解决插件依赖解析不正确的问题
```
2024-06-26 03:40:48 +00:00
Ryan Wang c0d38a99ed
feat: support batch publish/unpublish posts (#6123)
#### What type of PR is this?

/area ui
/kind feature
/milestone 2.17.x

#### What this PR does / why we need it:

支持批量发布/取消发布文章。

<img width="475" alt="image" src="https://github.com/halo-dev/halo/assets/21301288/5b79123b-5917-4b5e-9eaa-41c0cf5c8cdb">

#### Which issue(s) this PR fixes:

Fixes https://github.com/halo-dev/halo/issues/6085

#### Does this PR introduce a user-facing change?

```release-note
支持批量发布/取消发布文章。
```
2024-06-26 03:38:48 +00:00
Ryan Wang 8302c21bb6
feat: add avatar group component (#6128)
#### What type of PR is this?

/area ui
/kind feature
/milestone 2.17.x

#### What this PR does / why we need it:

添加 AvatarGroup 组件,用于堆叠多个 Avatar 组件。

<img width="243" alt="image" src="https://github.com/halo-dev/halo/assets/21301288/2d202e95-e735-4635-b16e-cdcf1f94f69a">
<img width="352" alt="image" src="https://github.com/halo-dev/halo/assets/21301288/da4a293d-eb3f-40b4-94b2-10dcf54d3305">

#### Which issue(s) this PR fixes:

Fixes #6079 

#### Does this PR introduce a user-facing change?

```release-note
添加 AvatarGroup 组件,用于堆叠多个头像。
```
2024-06-26 02:24:48 +00:00
John Niang e4cce918f7
Refactor ExtensionGetter for enabling or disabling extensions (#6134)
#### What type of PR is this?

/kind improvement
/kind api-change
/area core

#### What this PR does / why we need it:

This PR refactors ExtensionGetter implementation to add a support of enabling extension point(s). Here is an example of data field of `system` config map:

```json
{
  "data": {
    "extensionPointEnabled": "{  \"search-engine\": [\"search-engine-algolia\"]}"
  },
```

> 1. The `search-engine` is a name of extension point definition.
> 2. The `search-engine-algolia` is a name of extension definition.

#### Does this PR introduce a user-facing change?

```release-note
None
```
2024-06-25 07:46:45 +00:00
Ryan Wang 705bd235c3
fix: incorrect root path in API client requests (#6136)
#### What type of PR is this?

/area ui
/kind bug

#### What this PR does / why we need it:

修复 api client 默认请求根地址不正确的问题。

#### Does this PR introduce a user-facing change?

```release-note
None
```
2024-06-25 06:42:45 +00:00
John Niang 9b02bc3405
Merge pull request #6132 from halo-dev/refactor/api-client 2024-06-25 12:48:12 +08:00
Ryan Wang c74187c066 feat: add requests library as a global shared dependency 2024-06-25 12:31:44 +08:00
JohnNiang ecc0a70249 Refactor api client using separated OpenAPI groups 2024-06-25 12:31:25 +08:00
Ryan Wang af73a69e69
fix: resolve phantom dependency issue for iconify (#6120)
#### What type of PR is this?

/kind bug
/area ui
/milestone 2.17.x

#### What this PR does / why we need it:

修复关于 iconify 图标包的幽灵依赖问题,某些情况下,可能导致无法正常导入模块。

#### Which issue(s) this PR fixes:

Fixes https://github.com/halo-dev/halo/issues/6102

#### Does this PR introduce a user-facing change?

```release-note
None
```
2024-06-25 04:24:44 +00:00
Ryan Wang 4f63352b47
chore: bump mariadb driver to 1.2.1 to fix crash issue (#6133)
#### What type of PR is this?

/area core
/kind bug
/milestone 2.17.x

#### What this PR does / why we need it:

升级 MariaDB 的原生驱动版本至 [1.2.1](https://github.com/mariadb-corporation/mariadb-connector-r2dbc/releases/tag/1.2.1),以解决无法正常部署的问题。

#### Which issue(s) this PR fixes:

Fixes https://github.com/halo-dev/halo/issues/5534

#### Special notes for your reviewer:

测试方式:

```shell
./gradlew clean build -x check -x test --refresh-dependencies
```

```shell
docker build -t halohub/halo:mariadb-fix .
```

```yaml
services:
  halo:
    image: halohub/halo:mariadb-fix
    restart: on-failure:3
    networks:
      halo_network:
    volumes:
      - ./halo2:/root/.halo2
    ports:
      - "8090:8090"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8090/actuator/health/readiness"]
      interval: 30s
      timeout: 5s
      retries: 5
      start_period: 30s
    command:
      - --spring.r2dbc.url=r2dbc:pool:mariadb://halodb:3306/halo
      - --spring.r2dbc.username=root
      - --spring.r2dbc.password=jzm3h9t9jggo6ww
      - --spring.sql.init.platform=mariadb
      - --halo.external-url=http://localhost:8090/

  halodb:
    image: mariadb:latest
    container_name: mariadb
    restart: always
    networks:
      halo_network:
    environment:
      MYSQL_ROOT_PASSWORD: jzm3h9t9jggo6ww
      MYSQL_DATABASE: halo
    volumes:
      - ./db:/var/lib/mysql
networks:
  halo_network:
```

```shell
docker compose up
```

#### Does this PR introduce a user-facing change?

```release-note
升级 MariaDB 的原生驱动版本至 [1.2.1](https://github.com/mariadb-corporation/mariadb-connector-r2dbc/releases/tag/1.2.1),以解决使用 MariaDB 无法正常部署的问题。
```
2024-06-24 16:16:44 +00:00
Ryan Wang 9604262378
Refactor attachment moving using the patch api (#6111)
#### What type of PR is this?

/area ui
/kind improvement
/milestone 2.17.x

#### What this PR does / why we need it:

使用新的 [patch](https://github.com/halo-dev/halo/pull/6031) 接口重构附件的移动功能。

#### Special notes for your reviewer:

1. 测试附件移动至其他分组的功能是否正常。
2. 测试删除附件分组,选择 **删除并将附件移动至未分组** 选项,观察删除分组之后,其中的附件是否已经移动到未分组。

#### Does this PR introduce a user-facing change?

```release-note
None
```
2024-06-24 04:12:42 +00:00
Ryan Wang 6a1ade375d
refactor: simplify the plugin startup logic (#6113)
#### What type of PR is this?

/area ui
/kind improvement
/milestone 2.17.x

#### What this PR does / why we need it:

简化插件启动的接口,改为之前单独提供的修改插件状态的接口,而不是修改 `spec.enabled`。

#### Special notes for your reviewer:

需要测试:

1. 手动安装插件之后,启动插件。

#### Does this PR introduce a user-facing change?

```release-note
None
```
2024-06-24 03:58:43 +00:00
Ryan Wang f45ffdeca1
Refactor comment data update using the patch api (#6112)
#### What type of PR is this?

/area ui
/kind improvement
/milestone 2.17.x

#### What this PR does / why we need it:

使用新的 patch 接口重构评论相关的逻辑。

#### Special notes for your reviewer:

需要测试:

1. 审核评论和回复功能。
2. 批量审核评论和回复功能。

#### Does this PR introduce a user-facing change?

```release-note
None
```
2024-06-23 16:16:33 +00:00
Ryan Wang ae7dcbb317
fix: not remembering the selected attachment policy in upload modal (#6115)
#### What type of PR is this?

/area ui
/kind bug
/milestone 2.17.x

#### What this PR does / why we need it:

修复首次上传附件时,没有默认选择第一个存储策略的问题。

#### Which issue(s) this PR fixes:

Fixes https://github.com/halo-dev/halo/issues/6094

#### Does this PR introduce a user-facing change?

```release-note
修复首次上传附件时,没有默认选择第一个存储策略的问题。
```
2024-06-23 03:48:29 +00:00
Ryan Wang 373229e9de
fix: not remembering the selected editor (#6114)
#### What type of PR is this?

/area ui
/kind bug
/milestone 2.17.x

#### What this PR does / why we need it:

修复新建文章时,没有自动选择之前所选编辑器的问题。

#### Which issue(s) this PR fixes:

Fixes https://github.com/halo-dev/halo/issues/6091

#### Special notes for your reviewer:

#### Does this PR introduce a user-facing change?

```release-note
修复新建文章时,没有自动选择之前所选编辑器的问题。
```
2024-06-23 03:46:29 +00:00
guqing c10862d6fe
refactor: index mechanism to enhance overall performance (#6039)
#### What type of PR is this?
/kind improvement
/area core
/milestone 2.17.x

#### What this PR does / why we need it:
重构索引机制的查询和排序以提升整体性能

**how to test it?**
使用 postgre 数据库,初始化 Halo ,然后执行以下脚本创建 30w 文章数据进行测试:
<details>
<summary>点击展开查看 SQL</summary>

```sql
DO $$
DECLARE
    i integer;
    postNameIndex integer;
    snapshotName varchar;
    totalRecords integer;
BEGIN
    postNameIndex := 1;
    totalRecords := 300000;

    FOR i IN 1..3 LOOP
      INSERT INTO "public"."extensions" ("name", "data", "version")
      VALUES (
          '/registry/content.halo.run/categories/category-'||i,
          convert_to(
              jsonb_build_object(
                  'spec', jsonb_build_object(
                      'displayName', '分类-'||i,
                      'slug', 'category-'||i,
                      'description', '测试分类',
                      'cover', '',
                      'template', '',
                      'priority', 0,
                      'children', '[]'::jsonb
                  ),
                  'status', jsonb_build_object(
                      'permalink', '/categories/category-'||i,
                      'postCount', totalRecords,
                      'visiblePostCount', totalRecords
                  ),
                  'apiVersion', 'content.halo.run/v1alpha1',
                  'kind', 'Category',
                  'metadata', jsonb_build_object(
                      'finalizers', jsonb_build_array('category-protection'),
                      'name', 'category-' || i,
                      'annotations', jsonb_build_object(
                          'content.halo.run/permalink-pattern', 'categories'
                      ),
                      'version', 0,
                      'creationTimestamp', '2024-06-12T03:56:40.315592Z'
                  )
          )::text, 'UTF8'),
          0
      );
    END LOOP;


    FOR i IN 1..3 LOOP
      INSERT INTO "public"."extensions" ("name", "data", "version")
        VALUES (
            '/registry/content.halo.run/tags/tag-' || i,
            convert_to(
               jsonb_build_object(
               'spec', jsonb_build_object(
                   'displayName', 'Halo tag ' || i,
                   'slug', 'tag-'||i,
                   'color', '#ffffff',
                   'cover', ''
               ),
               'status', jsonb_build_object(
                   'permalink', '/tags/tag-' || i,
                   'visiblePostCount', totalRecords,
                   'postCount', totalRecords,
                   'observedVersion', 0
               ),
               'apiVersion', 'content.halo.run/v1alpha1',
               'kind', 'Tag',
               'metadata', jsonb_build_object(
                   'finalizers', jsonb_build_array('tag-protection'),
                   'name', 'tag-'||i,
                   'annotations', jsonb_build_object(
                       'content.halo.run/permalink-pattern', 'tags'
                   ),
                   'version', 0,
                   'creationTimestamp', '2024-06-12T03:56:40.406407Z'
               )
       )::text, 'UTF8'),
       0);
    END LOOP;

    FOR i IN postNameIndex..totalRecords LOOP
        -- Generate snapshotName
        snapshotName := 'snapshot-' || i;

        -- Insert post data
        INSERT INTO "public"."extensions" ("name", "data", "version")
        VALUES (
            '/registry/content.halo.run/posts/post-' || postNameIndex,
            convert_to(
                jsonb_build_object(
                    'spec', jsonb_build_object(
                        'title', 'title-' || postNameIndex,
                        'slug', 'slug-' || postNameIndex,
                        'releaseSnapshot', snapshotName,
                        'headSnapshot', snapshotName,
                        'baseSnapshot', snapshotName,
                        'owner', 'admin',
                        'template', '',
                        'cover', '',
                        'deleted', false,
                        'publish', true,
                        'pinned', false,
                        'allowComment', true,
                        'visible', 'PUBLIC',
                        'priority', 0,
                        'excerpt', jsonb_build_object(
                            'autoGenerate', true,
                            'raw', ''
                        ),
                        'categories', ARRAY['category-kEvDb', 'category-XcRVk', 'category-adca'],
                        'tags', ARRAY['tag-RtKos', 'tag-vEsTR', 'tag-UBKCc'],
                        'htmlMetas', '[]'::jsonb
                    ),
                    'status', jsonb_build_object(
                        'phase', 'PUBLISHED',
                        'conditions', ARRAY[
                            jsonb_build_object(
                                'type', 'PUBLISHED',
                                'status', 'TRUE',
                                'lastTransitionTime', '2024-06-11T10:16:15.617748Z',
                                'message', 'Post published successfully.',
                                'reason', 'Published'
                            ),
                            jsonb_build_object(
                                'type', 'DRAFT',
                                'status', 'TRUE',
                                'lastTransitionTime', '2024-06-11T10:16:15.457668Z',
                                'message', 'Drafted post successfully.',
                                'reason', 'DraftedSuccessfully'
                            )
                        ],
                        'permalink', '/archives/slug-' || postNameIndex,
                        'excerpt', '如果你看到了这一篇文章,那么证明你已经安装成功了,感谢使用 Halo 进行创作,希望能够使用愉快。',
                        'inProgress', false,
                        'contributors', ARRAY['admin'],
                        'lastModifyTime', '2024-06-11T10:16:15.421467Z',
                        'observedVersion', 0
                    ),
                    'apiVersion', 'content.halo.run/v1alpha1',
                    'kind', 'Post',
                    'metadata', jsonb_build_object(
                        'finalizers', ARRAY['post-protection'],
                        'name', 'post-' || postNameIndex,
                        'labels', jsonb_build_object(
                            'content.halo.run/published', 'true',
                            'content.halo.run/deleted', 'false',
                            'content.halo.run/owner', 'admin',
                            'content.halo.run/visible', 'PUBLIC',
                            'content.halo.run/archive-year', '2024',
                            'content.halo.run/archive-month', '06',
                            'content.halo.run/archive-day', '11'
                        ),
                        'annotations', jsonb_build_object(
                            'content.halo.run/permalink-pattern', '/archives/{slug}',
                            'content.halo.run/last-released-snapshot', snapshotName,
                            'checksum/config', '73e40d4115f5a7d1e74fcc9228861c53d2ef60468e1e606e367b01efef339309'
                        ),
                        'version', 0,
                        'creationTimestamp', '2024-06-11T05:51:46.059292Z'
                    )
                )::text, 'UTF8'),
            1
        );

        -- Insert content data
        INSERT INTO "public"."extensions" ("name", "data", "version")
        VALUES (
            '/registry/content.halo.run/snapshots/' || snapshotName,
            convert_to(
                jsonb_build_object(
                    'spec', jsonb_build_object(
                        'subjectRef', jsonb_build_object(
                            'group', 'content.halo.run',
                            'version', 'v1alpha1',
                            'kind', 'Post',
                            'name', 'post-' || postNameIndex
                        ),
                        'rawType', 'HTML',
                        'rawPatch', '<p style=\"\">测试内容</p>',
                        'contentPatch', '<p style=\"\">测试内容</p>',
                        'lastModifyTime', '2024-06-11T06:01:25.748755Z',
                        'owner', 'admin',
                        'contributors', ARRAY['admin']
                    ),
                    'apiVersion', 'content.halo.run/v1alpha1',
                    'kind', 'Snapshot',
                    'metadata', jsonb_build_object(
                        'name', snapshotName,
                        'annotations', jsonb_build_object(
                            'content.halo.run/keep-raw', 'true'
                        ),
                        'creationTimestamp', '2024-06-11T06:01:25.748925Z'
                    )
                )::text, 'UTF8'),
            1
        );

        postNameIndex := postNameIndex + 1;
    END LOOP;
END $$;
```

</details>

使用以下 API 查询文章
```
curl 'http://localhost:8090/apis/api.console.halo.run/v1alpha1/posts?page=1&size=20&labelSelector=content.halo.run%2Fdeleted%3Dfalse&labelSelector=content.halo.run%2Fpublished%3Dtrue&fieldSelector=spec.categories%3Dcategory-1&fieldSelector=spec.tags%3Dc33ceabb-d8f1-4711-8991-bb8f5c92ad7c&fieldSelector=status.contributors%3Dadmin&fieldSelector=spec.visible%3DPUBLIC' \
--header 'Authorization: Basic YWRtaW46YWRtaW4='
```
Before:

![SCR-20240612-o20](https://github.com/halo-dev/halo/assets/38999863/fc27a265-6571-4361-a707-a683ea040837)
After:

![SCR-20240612-q1c](https://github.com/halo-dev/halo/assets/38999863/c0a241b8-5ed4-4973-8dfc-c260ffccd727)

#### Does this PR introduce a user-facing change?
```release-note
重构索引机制的查询和排序使整体性能提升 50% 以上
```
2024-06-21 08:04:11 +00:00
guqing 8bdde317e5
feat: add preventParentPostCascadeQuery option to control visibility of child category posts (#6083)
#### What type of PR is this?
/kind feature
/area core
/milestone 2.17.x

#### What this PR does / why we need it:
此次变更为文章分类引入了一个新的 `preventParentPostCascadeQuery` 布尔属性,用于控制分类及其子分类下的文章显示方式。具体变更包括:

- 在分类结构中增加了 `preventParentPostCascadeQuery` 属性。
- 当分类的 `preventParentPostCascadeQuery` 属性设置为 `true` 时,该分类的文章数量不会汇总到父分类中。
- 更新了树结构遍历逻辑,以支持对 `preventParentPostCascadeQuery` 属性的处理。
- 确保独立分类中的文章显示受控,不向上级分类进行聚合。
- 增加了相应的测试用例,以验证在不同树结构中 `preventParentPostCascadeQuery` 属性的功能性。

#### Which issue(s) this PR fixes:
Fixes #5663 
Fixes #4923
Fixes https://github.com/halo-dev/halo/issues/3418

#### Does this PR introduce a user-facing change?
```release-note
新增独立分类选项用于控制关联的子分类下的文章显示以提供更灵活的内容管理方式
```
2024-06-21 04:08:10 +00:00
John Niang db9e0f4ac7
Upgrade SpringBoot to 3.3.1 (#6110)
#### What type of PR is this?

/kind improvement
/area core

#### What this PR does / why we need it:

This PR upgrades Spring Boot to [3.3.1](https://github.com/spring-projects/spring-boot/releases/tag/v3.3.1) and Dependency Management Plugin to [1.1.5](https://github.com/spring-gradle-plugins/dependency-management-plugin/releases/tag/v1.1.5).

#### Does this PR introduce a user-facing change?

```release-note
None
```
2024-06-20 15:10:07 +00:00
John Niang c0ac2f37d7
Add support for patching extensions (#6031)
#### What type of PR is this?

/kind feature
/area core
/milestone 2.17.x

#### What this PR does / why we need it:

This PR adds patch method for all extensions API.

Patch example:

```bash
http -a admin:admin PATCH http://localhost:8090/apis/plugin.halo.run/v1alpha1/plugins/app-store-integration \
  Content-Type:application/json-patch+json \
  --raw='[{"op": "replace", "path": "/spec/enabled", "value": false}]'
```

#### Which issue(s) this PR fixes:

Fixes #2311 

#### Does this PR introduce a user-facing change?

```release-note
None
```
2024-06-20 09:32:06 +00:00
guqing b5f9010e60
feat: support setting rendering templates for related posts on category (#6106)
#### What type of PR is this?
/kind feature
/area core
/milestone 2.17.x

#### What this PR does / why we need it:
支持在分类上为关联的文章统一设置渲染模板

现在文章的模板生效顺序为:
1. 文章关联的分类上设置的文章模板,如果有多个则选择第一个
2. 文章上设置的自定义模板
3. 文章的默认模板

#### Which issue(s) this PR fixes:
Fixes #6101

#### Does this PR introduce a user-facing change?
```release-note
支持在分类上为关联的文章统一设置渲染模板
```
2024-06-20 08:12:07 +00:00
guqing 6d3a157d35
fix: a verified email can be reused (#6064)
#### What type of PR is this?
/kind bug
/area core
/milestone 2.17.x

#### What this PR does / why we need it:
修复已验证邮箱可以重复的问题

如果出现多个重复的已验证邮箱,则只保留一个其他的设置为未验证

#### Does this PR introduce a user-facing change?
```release-note
修复已验证邮箱可以重复的问题
```
2024-06-20 08:10:07 +00:00
John Niang a94596a9f8
Add support for publishing events among plugins (#6081)
#### What type of PR is this?

/kind feature
/area core
/area plugin

#### What this PR does / why we need it:

This PR enhance usage of SharedEvent annotation to add support for publishing events among plugins.

#### How to test?

1. Clone repository https://github.com/halo-dev/plugin-starter
2. Change build.gradle as following:

	```gradle
	dependencies {
	    implementation platform('run.halo.tools.platform:plugin:2.17.0-SNAPSHOT')
	```

3. Change StarterPlugin as following:

	```java
	@Component
	public class StarterPlugin extends BasePlugin {
	
	    private final ApplicationContext appContext;
	
	    public StarterPlugin(PluginContext pluginContext, ApplicationContext appContext) {
	        super(pluginContext);
	        this.appContext = appContext;
	    }
	
	    @Override
	    public void start() {
	        appContext.publishEvent(new PostDeletedEvent(this, "fake-plugin"));
	    }
	
	    @Override
	    public void stop() {
	    }

	    @EventListener(PostDeletedEvent.class)
	    public void onApplicationEvent(PostDeletedEvent event) {
	        System.out.println("Post deleted event received in plugin: " + event.getName());
	    }
	}
	```
4. Add a listener to Halo core
```java
	    @EventListener(PostDeletedEvent.class)
	    public void onApplicationEvent(PostDeletedEvent event) {
	        System.out.println("Post deleted event received in core: " + event.getName());
	    }
```
5. Build plugin and install plugin
6. Enable the plugin and see the result

#### Does this PR introduce a user-facing change?

```release-note
None
```
2024-06-19 16:11:00 +00:00
Takagi b445b505be
feat: add import and export theme configuration (#6071)
#### What type of PR is this?

/kind feature
/area ui
/milestone 2.17.x

#### What this PR does / why we need it:

为主题增加导入及导出配置的功能。

<img width="1666" alt="image" src="https://github.com/halo-dev/halo/assets/31335418/3574b33e-0293-427c-9036-5d82948aa7f2">

#### How to test it?

测试主题导入及导出功能是否正常可用。
测试当前主题下的不同版本导入导出后数据是否正常。
测试在当前主题下使用其他主题导出的配置是否会报错。

#### Which issue(s) this PR fixes:

Fixes #1073 

#### Does this PR introduce a user-facing change?
```release-note
为单个主题配置增加导入与导出的功能。
```
2024-06-19 10:55:00 +00:00
BugKing 0f87ed8370
docs: add image linked to video in README.md (#6084)
#### What type of PR is this?


#### What this PR does / why we need it:

#### Which issue(s) this PR fixes:

Fixes #

#### Special notes for your reviewer:

#### Does this PR introduce a user-facing change?


```release-note
```
2024-06-19 07:54:57 +00:00
Takagi c956533160
pref: default code block indentation from Tab to 2 Spaces in editor (#6090)
#### What type of PR is this?

/kind improvement
/area editor
/milestone 2.17.x

#### What this PR does / why we need it:

将默认编辑器中代码块的缩进由一个制表符(\t),更改为两个空格` {2}`。

#### How to test it?

测试使用 `Tab` 即 `Shift + Tab` 缩进时,是否每次缩进两个空格而不是一个制表符。

#### Does this PR introduce a user-facing change?
```release-note
优化默认编辑器代码块缩进为两个空格。
```
2024-06-18 06:02:53 +00:00
Takagi 1e37768b35
pref: improve code block styling in editor (#6089)
#### What type of PR is this?

/kind improvement
/area editor

#### What this PR does / why we need it:

优化编辑器代码块样式。

before:

<img width="907" alt="image" src="https://github.com/halo-dev/halo/assets/31335418/11ad91a9-75ce-42ec-a947-effca7b42f30">

after:

<img width="932" alt="image" src="https://github.com/halo-dev/halo/assets/31335418/d0b3275b-a269-4104-aea8-0d8726ce32e7">

#### How to test it?

测试复制功能是否正常。

#### Does this PR introduce a user-facing change?
```release-note
优化默认编辑器代码块样式
```
2024-06-18 06:00:52 +00:00
Takagi 10f3157258
fix: ensure pasted content auto-generates title id (#6059)
#### What type of PR is this?

/kind bug
/area editor
/milestone 2.17.x

#### What this PR does / why we need it:

当前在编辑器中粘贴内容后,如果不修改任意标题或新增标题,则无法为当前标题自动生成标题 ID,进而导致锚点失效。

本 PR 将在编辑器触发内容更改后,如果是粘贴的内容,则直接触发生成标题 ID。

#### How to test it?

新建一篇文章并粘贴一段带标题的内容后直接发布。

查看发布后的文章是否可以在主题端使用锚点跳转。

#### Which issue(s) this PR fixes:

Fixes #6056 

#### Does this PR introduce a user-facing change?
```release-note
解决在默认编辑器中粘贴的内容无法生成标题 ID 的问题
```
2024-06-17 13:48:50 +00:00
Takagi 3076838f36
fix: default editor focus setting failure (#6062)
#### What type of PR is this?

/kind bug
/area editor
/area ui

#### What this PR does / why we need it:

当前为默认编辑器设置焦点的时机放在 `onMounted` 时,但此时默认编辑器可能还未加载成功且标题也为能成功加载,因此无法保证正确设置标题焦点。

当前 PR 将此时机放置在默认编辑器创建完成之后的 `onCreate` ,此时将能够保证焦点设置成功。

#### How to test it?

测试默认编辑器能否正常设置标题或内容的焦点。

#### Which issue(s) this PR fixes:

Fixes #6060 

#### Does this PR introduce a user-facing change?
```release-note
解决使用默认编辑器时无法正确设置焦点的问题
```
2024-06-14 08:08:39 +00:00
John Niang ebf1a1fe1b
Fix the problem that bundle files are not changed in development mode (#6073)
#### What type of PR is this?

/kind regression
/area plugin
/milestone 2.17.x

#### What this PR does / why we need it:

This PR reverts changes of generating bundle resource version in <https://github.com/halo-dev/halo/pull/6028>.

Because the changes were adapted realtime change of bundle files for plugin developers in plugin development runtime mode, but I ignored it.

#### Special notes for your reviewer:

1. Try to start Halo in plugin development mode
2. Change and rebuild ui resources
3. Refresh console and check the result

#### Does this PR introduce a user-facing change?

```release-note
None
```
2024-06-13 09:28:36 +00:00
John Niang b692db1f57
Move post events into api modules (#6052)
Signed-off-by: JohnNiang <johnniang@foxmail.com>
2024-06-07 18:34:09 +08:00
John Niang ccbe18567f
Fix the problem that theme assets could not be found after the first initialization (#6049)
#### What type of PR is this?

/kind bug
/area core
/milestone 2.17.x

#### What this PR does / why we need it:

When initialized for the first time, the folder `${halo.work-dir}/themes` does not exist, resulting in the `themes` path being ignored when invoking `themeRootResource.createRelative(themeName + "/templates/assets/");`. It works very well after restarting.

This PR fixes the problem by resolving theme resource directly rather than delegating to PathResourceResolver.

#### Which issue(s) this PR fixes:

Fixes #6048 

#### Does this PR introduce a user-facing change?

```release-note
修复首次初始化后无法正常访问主题资源的问题
```
2024-06-07 03:32:22 +00:00
mashirot f2a0c502e3
fix: content offset caused by empty slot (#6040)
#### What type of PR is this?

/area ui
/kind improvement

#### Which issue(s) this PR fixes:

Fixes #5877 

```release-note
修复Tag Icon为空时,后台文章的Tag内容不居中
```
2024-06-06 06:43:21 +00:00
John Niang e446054813
Fix concurrent issue during bundle file concurrent generation testing (#6043)
#### What type of PR is this?

/kind failing-test
/area core
/milestone 2.17.x

#### What this PR does / why we need it:

I wrongly invoked `Arraylist#add`(probes) method in multi threads. So the unit test was unstable and might encounter the problem as follows:

```java
Expected :1
Actual   :0
<Click to see difference>

org.opentest4j.AssertionFailedError: expected: <1> but was: <0>
	at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
	at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
	at org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:197)
	at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:166)
	at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:161)
	at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:632)
	at run.halo.app.core.extension.service.impl.PluginServiceImplTest$BundleCacheTest.concurrentComputeBundleFileIfAbsent(PluginServiceImplTest.java:460)
```

See https://github.com/halo-dev/halo/actions/runs/9382059472/job/25832681545 for more.

This PR moves the invocation outside thread tasks.

#### Does this PR introduce a user-facing change?

```release-note
None
```
2024-06-06 03:42:13 +00:00
Ryan Wang 2841ff8282
fix: missing default values for system settings (#6035)
#### What type of PR is this?

/kind bug
/area core
/milestone 2.16.x

#### What this PR does / why we need it:

补充缺失的系统设置默认值。

#### Does this PR introduce a user-facing change?

```release-note
修复系统设置未保存导致无法正常注册的问题
```
2024-06-05 02:31:18 +00:00
John Niang a188f719cb
Upgrade to Gradle 8.8 (#6033)
#### What type of PR is this?

/kind cleanup
/area core

#### What this PR does / why we need it:

This PR upgrades Gradle to 8.8. See https://github.com/gradle/gradle/releases/tag/v8.8.0 for more.

#### Does this PR introduce a user-facing change?

```release-note
升级 Gradle 至 8.8
```
2024-06-03 15:05:45 +00:00
John Niang 1821829f99
Prepare for developing 2.17.0 (#6032)
#### What type of PR is this?

/kind cleanup
/area core

#### What this PR does / why we need it:

This is a regular update after a release.

#### Does this PR introduce a user-facing change?

```release-note
None
```
2024-06-03 09:53:44 +00:00
John Niang ba96118b4e
Fix the problem that bundle files can be generated arbitrarily (#6028)
#### What type of PR is this?

/kind bug
/area  core
/area plugin
/milestone 2.16.0

#### What this PR does / why we need it:

Before the PR, any user can generate bundle files by providing random query param `v` while requesting bundle files.

This PR refactors the whole bundle file generation method.

1. Do nothing if users provide arbitrary bundle file version
2. Better lock for writing bundle files if not exist

#### Special notes for your reviewer:

1. Request `http://localhost:8090/apis/api.console.halo.run/v1alpha1/plugins/-/bundle.js?v=xyz` 
2. Check if the file `xyz.js` in folder `$TMPDIR/halo-plugin-bundle**`

#### Does this PR introduce a user-facing change?

```release-note
None
```
2024-06-03 02:42:13 +00:00
Ryan Wang a26b73e258
chore: remove unnecessary env (#6022)
#### What type of PR is this?

/area ui
/kind cleanup
/milestone 2.16.x

#### What this PR does / why we need it:

移除 UI 项目中不必要的环境变量配置。

1. VITE_API_URL:当前 Console 不会考虑独立部署,并且在开发环境是后端 Proxy 的 Console 请求,所以此变量没有任何意义。
2. VITE_BASE_URL:无意义,当前不考虑修改。

#### Does this PR introduce a user-facing change?

```release-note
None
```
2024-05-30 08:31:16 +00:00
Ryan Wang 296d8c5833
fix: dropdown component auto-destruction issue (#6021)
#### What type of PR is this?

/area ui
/kind bug
/milestone 2.16.x

#### What this PR does / why we need it:

修复 Dropdown 组件自动销毁的问题,这可能导致部分插件在 Dropdown 中的组件无法正常渲染。

#### Does this PR introduce a user-facing change?

```release-note
None 
```
2024-05-30 08:29:15 +00:00
guqing 9f6a441288
refactor: use index mechanism to query extension point definitions (#6011)
#### What type of PR is this?
/kind improvement
/area core
/kind milestone 2.16.x

#### What this PR does / why we need it:
使用索引机制来查询扩展点定义

#### Does this PR introduce a user-facing change?
```release-note
None
```
2024-05-30 07:49:15 +00:00