#### What type of PR is this?
/kind improvement
#### What this PR does / why we need it:
This PR adds UserLoginEvent and UserLogoutEvent which are shared to plugins.
#### Which issue(s) this PR fixes:
Fixes https://github.com/halo-dev/halo/issues/7436
#### Does this PR introduce a user-facing change?
```release-note
添加用户登录/登出事件
```
#### What type of PR is this?
/kind improvement
/area core
/milestone 2.21.x
#### What this PR does / why we need it:
This PR bumps Spring Boot to [3.5.0](https://github.com/spring-projects/spring-boot/releases/tag/v3.5.0).
#### Does this PR introduce a user-facing change?
```release-note
升级依赖 Spring Boot 至 3.5.0
```
* Add support for configuring external URL online
* Fix the problem of timeout on external URL initialization
* Add external URL editing capability to overview page
Signed-off-by: Ryan Wang <i@ryanc.cc>
---------
Signed-off-by: Ryan Wang <i@ryanc.cc>
Co-authored-by: Ryan Wang <i@ryanc.cc>
#### What type of PR is this?
/kind bug
/area core
/milestone 2.21.x
#### What this PR does / why we need it:
This PR check if the locale is undetermined during resolving locale. Or it will cause the error below if locale is `und`:
```java
2025-05-21T17:28:45.953+08:00 ERROR 58760 --- [undedElastic-14] o.s.w.s.adapter.HttpWebHandlerAdapter : [c1824fa5-1] 500 Server Error for HTTP GET "/"
org.thymeleaf.exceptions.TemplateOutputException: An error happened during template rendering
at org.thymeleaf.engine.OutputTemplateHandler.handleText(OutputTemplateHandler.java:75) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.engine.AbstractTemplateHandler.handleText(AbstractTemplateHandler.java:221) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.engine.ProcessorTemplateHandler.handleText(ProcessorTemplateHandler.java:587) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.engine.Text.beHandled(Text.java:97) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.engine.Model.process(Model.java:300) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.engine.GatheringModelProcessable.process(GatheringModelProcessable.java:78) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.engine.ProcessorTemplateHandler.queueProcessable(ProcessorTemplateHandler.java:2106) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.engine.ProcessorTemplateHandler.handleCloseElement(ProcessorTemplateHandler.java:1642) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.engine.CloseElementTag.beHandled(CloseElementTag.java:139) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.engine.Model.process(Model.java:300) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.engine.OpenElementTagModelProcessable.process(OpenElementTagModelProcessable.java:110) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.engine.ProcessorTemplateHandler.queueProcessable(ProcessorTemplateHandler.java:2106) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.engine.ProcessorTemplateHandler.handleOpenElement(ProcessorTemplateHandler.java:1559) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.engine.OpenElementTag.beHandled(OpenElementTag.java:205) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.engine.TemplateModel.process(TemplateModel.java:155) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.engine.ThrottledTemplateProcessor.process(ThrottledTemplateProcessor.java:235) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.engine.ThrottledTemplateProcessor.process(ThrottledTemplateProcessor.java:200) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.spring6.SpringWebFluxTemplateEngine$StreamThrottledTemplateProcessor.process(SpringWebFluxTemplateEngine.java:720) ~[thymeleaf-spring6-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.spring6.SpringWebFluxTemplateEngine.lambda$createChunkedStream$2(SpringWebFluxTemplateEngine.java:269) ~[thymeleaf-spring6-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at reactor.core.publisher.FluxGenerate$GenerateSubscription.slowPath(FluxGenerate.java:271) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.FluxGenerate$GenerateSubscription.request(FluxGenerate.java:213) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.request(FluxPeekFuseable.java:144) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.FluxSubscribeOn$SubscribeOnSubscriber.requestUpstream(FluxSubscribeOn.java:131) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.FluxSubscribeOn$SubscribeOnSubscriber.onSubscribe(FluxSubscribeOn.java:124) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onSubscribe(FluxPeekFuseable.java:178) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.FluxGenerate.subscribe(FluxGenerate.java:85) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.InternalFluxOperator.subscribe(InternalFluxOperator.java:68) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.FluxSubscribeOn$SubscribeOnSubscriber.run(FluxSubscribeOn.java:194) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.scheduler.BoundedElasticThreadPerTaskScheduler$SchedulerTask.run(BoundedElasticThreadPerTaskScheduler.java:1013) ~[reactor-core-3.7.5.jar:3.7.5]
at java.base/java.lang.VirtualThread.run(VirtualThread.java:329) ~[na:na]
Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Locale "" cannot be used as it does not specify a language. (template: "modules/layout" - line 12, col 49)
at org.thymeleaf.messageresolver.StandardMessageResolutionUtils.computeMessageResourceNamesFromBase(StandardMessageResolutionUtils.java:202) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.messageresolver.StandardMessageResolutionUtils.resolveMessagesForTemplate(StandardMessageResolutionUtils.java:69) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.messageresolver.StandardMessageResolver.resolveMessagesForTemplate(StandardMessageResolver.java:380) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.messageresolver.StandardMessageResolver.resolveMessage(StandardMessageResolver.java:282) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.messageresolver.StandardMessageResolver.resolveMessage(StandardMessageResolver.java:227) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.context.AbstractEngineContext.getMessage(AbstractEngineContext.java:134) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.standard.expression.MessageExpression.executeMessageExpression(MessageExpression.java:265) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.standard.expression.SimpleExpression.executeSimple(SimpleExpression.java:69) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.standard.expression.Expression.execute(Expression.java:109) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.standard.expression.Expression.execute(Expression.java:138) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.standard.processor.StandardUtextTagProcessor.doProcess(StandardUtextTagProcessor.java:87) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.processor.element.AbstractAttributeTagProcessor.doProcess(AbstractAttributeTagProcessor.java:74) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.processor.element.AbstractElementTagProcessor.process(AbstractElementTagProcessor.java:95) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.util.ProcessorConfigurationUtils$ElementTagProcessorWrapper.process(ProcessorConfigurationUtils.java:633) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.engine.ProcessorTemplateHandler.handleOpenElement(ProcessorTemplateHandler.java:1314) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.engine.OpenElementTag.beHandled(OpenElementTag.java:205) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.engine.TemplateModel.process(TemplateModel.java:136) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.engine.TemplateManager.process(TemplateManager.java:519) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.util.LazyProcessingCharSequence.writeUnresolved(LazyProcessingCharSequence.java:85) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.util.AbstractLazyCharSequence.write(AbstractLazyCharSequence.java:103) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.engine.AbstractTextualTemplateEvent.writeContent(AbstractTextualTemplateEvent.java:224) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.engine.Text.write(Text.java:78) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
at org.thymeleaf.engine.OutputTemplateHandler.handleText(OutputTemplateHandler.java:71) ~[thymeleaf-3.1.3.RELEASE.jar:3.1.3.RELEASE]
... 29 common frames omitted
```
#### Does this PR introduce a user-facing change?
```release-note
修复因 Locale 解析错误导致无法访问页面的问题
```
#### What type of PR is this?
/kind improvement
/area core
/milestone 2.21.x
#### What this PR does / why we need it:
This PR removes `/uploads/**` from static resources to make it protected by Halo security.
#### Does this PR introduce a user-facing change?
```release-note
None
```
#### What type of PR is this?
/kind improvement
/area core
/milestone 2.21.x
#### What this PR does / why we need it:
This PR sets Java 21 as minimal version. After doing that, Halo can only run on Java 21 or newer version.
Fortunately, all plugins and themes won't be affected by the restriction.
> https://docs.gradle.org/current/userguide/toolchains.html#sec:release-flag-toolchain
#### Which issue(s) this PR fixes:
Fixes https://github.com/halo-dev/halo/issues/6867
#### Does this PR introduce a user-facing change?
```release-note
[Action Required] 更新最低运行环境为 Java 21
```
#### What type of PR is this?
/kind improvement
/area core
/milestone 2.21.x
#### What this PR does / why we need it:
Defining `into` property in `processResources` task is not working, so I create a new copy task to process UI dist.
#### Does this PR introduce a user-facing change?
```release-note
None
```
#### What type of PR is this?
/kind improvement
/area core
/milestone 2.20.x
#### What this PR does / why we need it:
This PR adds support for redirection on logout. We can request <http://localhost:8090/logout?redirect_uri=/archives> with GET method, then click the logout to see the redirection.
#### Which issue(s) this PR fixes:
Fixes https://github.com/halo-dev/halo/issues/7401
#### Does this PR introduce a user-facing change?
```release-note
登出页面支持自定义重定向
```
#### What type of PR is this?
/kind bug
/area core
/milestone 2.20.x
#### What this PR does / why we need it:
1. This PR removes duplicate invocations while resolving handler functions of theme.
2. Throw NotFoundException while post was not found.
#### Which issue(s) this PR fixes:
Fixes https://github.com/halo-dev/halo/issues/7409
#### Does this PR introduce a user-facing change?
```release-note
修复访问不存在的分类或者文章页面时始终抛出异常的问题
```
#### What type of PR is this?
/kind feature
#### What this PR does / why we need it:
标签支持根据文章量排序
#### Does this PR introduce a user-facing change?
```release-note
标签支持根据文章量排序
```
#### What type of PR is this?
/kind bug
/area core
/milestone 2.20.x
#### What this PR does / why we need it:
This PR adds SwitchUserGrantedAuthorityMixin into HaloSecurityJackson2Module to fix the deserialization error.
See https://github.com/halo-dev/halo/issues/7406 for more.
#### Which issue(s) this PR fixes:
Fixes https://github.com/halo-dev/halo/issues/7406
#### Does this PR introduce a user-facing change?
```release-note
修复个人中心处可能出现登录设备查询异常的问题
```
#### What type of PR is this?
/kind bug
/area core
/milestone 2.20.x
#### What this PR does / why we need it:
This PR makes Argon2 password encoder as default to remove password limit of 72.
Please note that there is no compatibility issue for old passwords.
#### Which issue(s) this PR fixes:
Fixes#7405
#### Special notes for your reviewer:
1. Try to login as admin
2. Create a password having the length of 73 or more for a new user
3. See the result
#### Does this PR introduce a user-facing change?
```release-note
修复无法设置长度超过72个字符的密码的问题
```
#### What type of PR is this?
/kind improvement
/area core
/milestone 2.20.x
#### What this PR does / why we need it:
This PR adds therapi-runtime-javadoc dependency and annotationProcessor for api and application projects. After doing that, SpringDoc will introspect Javadoc annotations and comments. See https://springdoc.org/#javadoc-support for more.
For support in plugin, just add an annotationProcessor like below:
```gradle
dependencies {
implementation platform('run.halo.tools.platform:plugin:2.20.8-SNAPSHOT')
compileOnly 'run.halo.app:api'
annotationProcessor 'com.github.therapi:therapi-runtime-javadoc-scribe:0.13.0'
}
```
#### Does this PR introduce a user-facing change?
```release-note
None
```
#### What type of PR is this?
/kind bug
#### What this PR does / why we need it:
This PR manually set UTF-8 charset while loading YAML file to fix the problem "java.nio.charset.MalformedInputException: Input length = 1".
#### Which issue(s) this PR fixes:
Fixes https://github.com/halo-dev/halo/issues/6937
Fixes https://github.com/orgs/halo-dev/discussions/7375
#### Does this PR introduce a user-facing change?
```release-note
修复 Windows 下可能无法正常初始化的问题
```
### What type of PR is this?
/kind bug
/area core
/milestone 2.20.x
#### What this PR does / why we need it:
In PR <https://github.com/halo-dev/halo/pull/7371>, I used strong secure random to generate metadata name, but the random may cause system block in some specific environments. See https://github.com/orgs/lxware-dev/discussions/13#discussioncomment-12907298 for more.
So this PR revert the use of strong secure random.
#### Does this PR introduce a user-facing change?
```release-note
None
```
#### What type of PR is this?
/kind improvement
/area core
/milestone 2.20.x
#### What this PR does / why we need it:
This PR use secure-strong SecureRandom to generate unpredictable metadata name. Meanwhile, the length of generate name suffix is increased to `8` and lower-case is to prevent data conflicts caused by database case sensitivity as possible.
Another improvement is using bounded-elastic thread to run the method `secureString()#nextAlphanumeric` because the method contains blocking operation, which might cause system block.
#### Does this PR introduce a user-facing change?
```release-note
None
```
#### What type of PR is this?
/kind improvement
/area core
/milestone 2.20.x
#### What this PR does / why we need it:
This PR removes application startup steps buffer to reduce memory usage.
#### Does this PR introduce a user-facing change?
```release-note
None
```
#### What type of PR is this?
/kind improvement
/area core
/milestone 2.20.x
#### What this PR does / why we need it:
This PR disables CSRF check for PAT authentication because the authentication won't pass any cookies to server.
#### Does this PR introduce a user-facing change?
```release-note
None
```
#### What type of PR is this?
/kind feature
/area core
/milestone 2.20.x
#### What this PR does / why we need it:
This PR adds support for impersonating other users for super admin.
1. Login as super admin
2. Request `POST /login/impersonate?username=xxx` and the current user should be xxx
3. Request `POST /logout/impersonate` and the current user should be super admin
#### Does this PR introduce a user-facing change?
```release-note
None
```
#### What type of PR is this?
/kind feature
/milestone 2.20.x
#### What this PR does / why we need it:
文章访问路径支持设置 `/categories/{categorySlug}/{postSlug}` 的形式
#### Which issue(s) this PR fixes:
Fixes#7330
#### Does this PR introduce a user-facing change?
```release-note
文章访问路径支持设置 `/categories/{categorySlug}/{postSlug}` 的形式
```
#### What type of PR is this?
/kind bug
#### What this PR does / why we need it:
修复 postFinder.list() 传参 categoryName 查询不到子类文章
#### Which issue(s) this PR fixes:
Fixes#7296
#### Does this PR introduce a user-facing change?
```release-note
修复 postFinder.list() 的 categoryName 参数无效的问题
```
#### What type of PR is this?
/kind improvement
/area core
/milestone 2.20.x
#### What this PR does / why we need it:
This PR refactors UserScopedPatHandlerImpl with PAT service to make PAT operations flexible.
#### Does this PR introduce a user-facing change?
```release-note
None
```
#### What type of PR is this?
/kind improvement
/area core
/area theme
/milestone 2.20.x
#### What this PR does / why we need it:
This PR adds support for sec:authorize attribute of Thymeleaf which is not supported yet. See https://github.com/halo-dev/halo/issues/7316 for more.
#### Which issue(s) this PR fixes:
Fixes https://github.com/halo-dev/halo/issues/7316
#### Does this PR introduce a user-facing change?
```release-note
完善主题模板判断用户角色等功能
```
#### What type of PR is this?
/kind bug
/area core
/milestone 2.20.x
#### What this PR does / why we need it:
This PR fixes the NPE while post content is null. See https://github.com/halo-dev/halo/issues/7320 for more.
#### Which issue(s) this PR fixes:
Fixes https://github.com/halo-dev/halo/issues/7320
#### Does this PR introduce a user-facing change?
```release-note
修复通过接口创建文章可能导致无法发布和删除的问题
```
#### What type of PR is this?
/kind feature
/area core
/milestone 2.20.x
#### What this PR does / why we need it:
This PR allows users to upload local attachment always with a random filename to simply prevent resource leak.
Please see the configuration and the uploaded result below:

```json
{
"spec": {
"displayName": "halo.run-ykfswxmokpjopvkqwybghazloxeovgae.cer",
"policyName": "attachment-policy-XVdDK",
"ownerName": "admin",
"mediaType": "application/pkix-cert",
"size": 1803
},
"status": {
"permalink": "/upload/random/halo.run-ykfswxmokpjopvkqwybghazloxeovgae.cer"
},
"apiVersion": "storage.halo.run/v1alpha1",
"kind": "Attachment",
"metadata": {
"finalizers": [
"attachment-manager"
],
"name": "44b4c8de-0d3b-4bbb-acc2-4af50175a2b5",
"annotations": {
"storage.halo.run/local-relative-path": "upload/random/halo.run-ykfswxmokpjopvkqwybghazloxeovgae.cer",
"storage.halo.run/uri": "/upload/random/halo.run-ykfswxmokpjopvkqwybghazloxeovgae.cer"
},
"version": 2,
"creationTimestamp": "2025-03-18T15:53:11.817541483Z"
}
}
```
#### Does this PR introduce a user-facing change?
```release-note
支持上传附件至本地时总是随机命名文件名
```
#### What type of PR is this?
/kind bug
/area core
/milestone 2.20.x
#### What this PR does / why we need it:
This PR adds timeout for blocking Extension client to prevent system from blocking without any error.
#### Which issue(s) this PR fixes:
Recently, we have received several issues about getting stuck in creating menu items. Please refer to the key threaddump detail:

#### Does this PR introduce a user-facing change?
```release-note
None
```
#### What type of PR is this?
/kind cleanup
#### What this PR does / why we need it:
撤回对插件类加载顺序的改动这可能导致破坏性更新
同时,不在考虑修改加载顺序问题,由于社区版和专业版引入的依赖不同插件无法以社区版为依赖基准保证功能在专业版也可用,举个例子:
1. 插件引入了 okhttp4 作为依赖,这可能是插件引入的依赖所附带的
2. 在社区版没有问题,插件开发者也是这么测试的
3. 但是在专业版中引入了 okhttp3 作为依赖,此时插件在专业版就不可用了因为插件依赖了 okhttp4 的功能
通过上述问题就导致了不可预知的问题
#### Does this PR introduce a user-facing change?
```release-note
撤回对插件类加载顺序的改动这可能导致破坏性更新
```
#### What type of PR is this?
/area core
/kind improvement
/milestone 2.20.x
#### What this PR does / why we need it:
Add favicon to login page
#### Which issue(s) this PR fixes:
Fixes#7287
#### Special notes for your reviewer:
#### Does this PR introduce a user-facing change?
```release-note
为登录相关的页面添加 Favicon
```
#### What type of PR is this?
/kind feature
/area core
/milestone 2.20.x
#### What this PR does / why we need it:
支持禁用主题预览功能,但拥有主题管理权限的用户不受此功能影响
#### Which issue(s) this PR fixes:
Fixes#7204
#### Does this PR introduce a user-facing change?
```release-note
支持禁用主题预览功能,但拥有主题管理权限的用户不受此功能影响
```
#### What type of PR is this?
/kind bug
/area core
/milestone 2.20.x
#### What this PR does / why we need it:
This PR turns off the logging of TemplateEngine to prevent too many annoying and useless logs.
Please note that the TemplateExceptions won't be eat up because we have a global error handler to log them.
#### Which issue(s) this PR fixes:
Fixes https://github.com/halo-dev/halo/issues/4468
#### Special notes for your reviewer:
Steps to verify:
- Start Halo instance
- Execute command `ab -c 100 -n 10000 -H 'Accept: text/html' -H 'Cache-Control: no-cache' http://localhost:8090/` and then press `Ctrl + C` to stop the ab process.
- See the logs of Halo instance.
#### Does this PR introduce a user-facing change?
```release-note
解决日志中出现大量 InterruptedException 异常的问题
```