Copy disabled (too large)
Download .txt
Showing preview only (11,599K chars total). Download the full file to get everything.
Repository: halo-dev/halo
Branch: main
Commit: 4af3e75a2b05
Files: 2670
Total size: 10.5 MB
Directory structure:
gitextract_qe2hhq1p/
├── .dockerignore
├── .editorconfig
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.en.yml
│ │ ├── bug_report.zh.yml
│ │ ├── config.yml
│ │ ├── feature_request.en.yml
│ │ └── feature_request.zh.yml
│ ├── actions/
│ │ ├── docker-buildx-push/
│ │ │ └── action.yaml
│ │ └── setup-env/
│ │ └── action.yaml
│ ├── pull_request_template.md
│ └── workflows/
│ ├── halo.yaml
│ ├── openapi-check.yaml
│ ├── packages-preview-release.yaml
│ ├── release-ui-packages.yaml
│ └── stale-issues.yaml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── OWNERS
├── README.md
├── SECURITY.md
├── api/
│ ├── build.gradle
│ └── src/
│ ├── main/
│ │ └── java/
│ │ └── run/
│ │ └── halo/
│ │ └── app/
│ │ ├── content/
│ │ │ ├── ContentWrapper.java
│ │ │ ├── ExcerptGenerator.java
│ │ │ ├── PatchUtils.java
│ │ │ ├── PostContentService.java
│ │ │ └── comment/
│ │ │ └── CommentSubject.java
│ │ ├── core/
│ │ │ ├── attachment/
│ │ │ │ ├── ThumbnailProvider.java
│ │ │ │ └── ThumbnailSize.java
│ │ │ ├── endpoint/
│ │ │ │ └── WebSocketEndpoint.java
│ │ │ ├── extension/
│ │ │ │ ├── AnnotationSetting.java
│ │ │ │ ├── AuthProvider.java
│ │ │ │ ├── Counter.java
│ │ │ │ ├── Device.java
│ │ │ │ ├── Menu.java
│ │ │ │ ├── MenuItem.java
│ │ │ │ ├── Plugin.java
│ │ │ │ ├── RememberMeToken.java
│ │ │ │ ├── ReverseProxy.java
│ │ │ │ ├── Role.java
│ │ │ │ ├── RoleBinding.java
│ │ │ │ ├── Setting.java
│ │ │ │ ├── Theme.java
│ │ │ │ ├── User.java
│ │ │ │ ├── UserConnection.java
│ │ │ │ ├── attachment/
│ │ │ │ │ ├── Attachment.java
│ │ │ │ │ ├── Constant.java
│ │ │ │ │ ├── Group.java
│ │ │ │ │ ├── Policy.java
│ │ │ │ │ ├── PolicyTemplate.java
│ │ │ │ │ └── endpoint/
│ │ │ │ │ ├── AttachmentHandler.java
│ │ │ │ │ ├── DeleteOption.java
│ │ │ │ │ ├── SimpleFilePart.java
│ │ │ │ │ └── UploadOption.java
│ │ │ │ ├── content/
│ │ │ │ │ ├── Category.java
│ │ │ │ │ ├── Comment.java
│ │ │ │ │ ├── Constant.java
│ │ │ │ │ ├── Post.java
│ │ │ │ │ ├── Reply.java
│ │ │ │ │ ├── SinglePage.java
│ │ │ │ │ ├── Snapshot.java
│ │ │ │ │ └── Tag.java
│ │ │ │ ├── endpoint/
│ │ │ │ │ ├── CustomEndpoint.java
│ │ │ │ │ └── SortResolver.java
│ │ │ │ ├── notification/
│ │ │ │ │ ├── Notification.java
│ │ │ │ │ ├── NotificationTemplate.java
│ │ │ │ │ ├── NotifierDescriptor.java
│ │ │ │ │ ├── Reason.java
│ │ │ │ │ ├── ReasonType.java
│ │ │ │ │ └── Subscription.java
│ │ │ │ └── service/
│ │ │ │ └── AttachmentService.java
│ │ │ └── user/
│ │ │ └── service/
│ │ │ ├── RoleService.java
│ │ │ ├── SignUpData.java
│ │ │ ├── UserPostCreatingHandler.java
│ │ │ ├── UserPreCreatingHandler.java
│ │ │ └── UserService.java
│ │ ├── event/
│ │ │ ├── post/
│ │ │ │ ├── PostDeletedEvent.java
│ │ │ │ ├── PostEvent.java
│ │ │ │ ├── PostPublishedEvent.java
│ │ │ │ ├── PostUnpublishedEvent.java
│ │ │ │ ├── PostUpdatedEvent.java
│ │ │ │ └── PostVisibleChangedEvent.java
│ │ │ └── user/
│ │ │ ├── UserConnectionDisconnectedEvent.java
│ │ │ ├── UserLoginEvent.java
│ │ │ └── UserLogoutEvent.java
│ │ ├── extension/
│ │ │ ├── AbstractExtension.java
│ │ │ ├── Comparators.java
│ │ │ ├── ConfigMap.java
│ │ │ ├── DefaultExtensionMatcher.java
│ │ │ ├── Extension.java
│ │ │ ├── ExtensionClient.java
│ │ │ ├── ExtensionMatcher.java
│ │ │ ├── ExtensionOperator.java
│ │ │ ├── ExtensionUtil.java
│ │ │ ├── GVK.java
│ │ │ ├── GroupKind.java
│ │ │ ├── GroupVersion.java
│ │ │ ├── GroupVersionKind.java
│ │ │ ├── JsonExtension.java
│ │ │ ├── ListOptions.java
│ │ │ ├── ListResult.java
│ │ │ ├── Metadata.java
│ │ │ ├── MetadataOperator.java
│ │ │ ├── MetadataUtil.java
│ │ │ ├── PageRequest.java
│ │ │ ├── PageRequestImpl.java
│ │ │ ├── ReactiveExtensionClient.java
│ │ │ ├── Ref.java
│ │ │ ├── Scheme.java
│ │ │ ├── SchemeManager.java
│ │ │ ├── Secret.java
│ │ │ ├── Unstructured.java
│ │ │ ├── Watcher.java
│ │ │ ├── WatcherExtensionMatchers.java
│ │ │ ├── WatcherPredicates.java
│ │ │ ├── controller/
│ │ │ │ ├── Controller.java
│ │ │ │ ├── ControllerBuilder.java
│ │ │ │ ├── DefaultController.java
│ │ │ │ ├── DefaultQueue.java
│ │ │ │ ├── ExtensionWatcher.java
│ │ │ │ ├── Reconciler.java
│ │ │ │ ├── RequestQueue.java
│ │ │ │ ├── RequestSynchronizer.java
│ │ │ │ ├── RequeueException.java
│ │ │ │ └── Synchronizer.java
│ │ │ ├── exception/
│ │ │ │ ├── ExtensionException.java
│ │ │ │ ├── NotImplementedException.java
│ │ │ │ └── SchemeNotFoundException.java
│ │ │ ├── index/
│ │ │ │ ├── AbstractValueIndexSpecBuilder.java
│ │ │ │ ├── DefaultIndexAttribute.java
│ │ │ │ ├── IndexAttribute.java
│ │ │ │ ├── IndexAttributeFactory.java
│ │ │ │ ├── IndexSpec.java
│ │ │ │ ├── IndexSpecBuilder.java
│ │ │ │ ├── IndexSpecs.java
│ │ │ │ ├── IndexedQueryEngine.java
│ │ │ │ ├── KeyComparator.java
│ │ │ │ ├── MultiValueBuilder.java
│ │ │ │ ├── MultiValueIndexSpec.java
│ │ │ │ ├── MultiValueIndexSpecBuilder.java
│ │ │ │ ├── SingleValueBuilder.java
│ │ │ │ ├── SingleValueIndexSpec.java
│ │ │ │ ├── SingleValueIndexSpecBuilder.java
│ │ │ │ ├── UnknownKey.java
│ │ │ │ ├── ValueIndexSpec.java
│ │ │ │ └── query/
│ │ │ │ ├── AllCondition.java
│ │ │ │ ├── And.java
│ │ │ │ ├── AndCondition.java
│ │ │ │ ├── BetweenCondition.java
│ │ │ │ ├── Condition.java
│ │ │ │ ├── EmptyCondition.java
│ │ │ │ ├── EqualCondition.java
│ │ │ │ ├── GreaterThanCondition.java
│ │ │ │ ├── InCondition.java
│ │ │ │ ├── IndexCondition.java
│ │ │ │ ├── IsNotNullCondition.java
│ │ │ │ ├── IsNullCondition.java
│ │ │ │ ├── LabelCondition.java
│ │ │ │ ├── LabelEqualsCondition.java
│ │ │ │ ├── LabelExistsCondition.java
│ │ │ │ ├── LabelInCondition.java
│ │ │ │ ├── LabelNotEqualsCondition.java
│ │ │ │ ├── LabelNotExistsCondition.java
│ │ │ │ ├── LabelNotInCondition.java
│ │ │ │ ├── LessThanCondition.java
│ │ │ │ ├── NoneCondition.java
│ │ │ │ ├── NotBetweenCondition.java
│ │ │ │ ├── NotCondition.java
│ │ │ │ ├── NotEqualCondition.java
│ │ │ │ ├── NotInCondition.java
│ │ │ │ ├── OrCondition.java
│ │ │ │ ├── Queries.java
│ │ │ │ ├── Query.java
│ │ │ │ ├── QueryFactory.java
│ │ │ │ ├── StringContainsCondition.java
│ │ │ │ ├── StringEndsWithCondition.java
│ │ │ │ ├── StringNotContainsCondition.java
│ │ │ │ ├── StringNotEndsWithCondition.java
│ │ │ │ ├── StringNotStartsWithCondition.java
│ │ │ │ └── StringStartsWithCondition.java
│ │ │ └── router/
│ │ │ ├── IListRequest.java
│ │ │ ├── QueryParamBuildUtil.java
│ │ │ ├── SortableRequest.java
│ │ │ └── selector/
│ │ │ ├── FieldSelector.java
│ │ │ ├── FieldSelectorConverter.java
│ │ │ ├── LabelSelector.java
│ │ │ ├── LabelSelectorConverter.java
│ │ │ ├── Operator.java
│ │ │ ├── SelectorConverter.java
│ │ │ ├── SelectorCriteria.java
│ │ │ └── SelectorUtil.java
│ │ ├── infra/
│ │ │ ├── AnonymousUserConst.java
│ │ │ ├── BackupRootGetter.java
│ │ │ ├── Condition.java
│ │ │ ├── ConditionList.java
│ │ │ ├── ConditionStatus.java
│ │ │ ├── ExternalLinkProcessor.java
│ │ │ ├── ExternalUrlSupplier.java
│ │ │ ├── FileCategoryMatcher.java
│ │ │ ├── SystemInfo.java
│ │ │ ├── SystemInfoGetter.java
│ │ │ ├── SystemSetting.java
│ │ │ ├── SystemVersionSupplier.java
│ │ │ ├── ValidationUtils.java
│ │ │ ├── model/
│ │ │ │ └── License.java
│ │ │ └── utils/
│ │ │ ├── FileTypeDetectUtils.java
│ │ │ ├── GenericClassUtils.java
│ │ │ ├── JsonParseException.java
│ │ │ ├── JsonUtils.java
│ │ │ └── PathUtils.java
│ │ ├── migration/
│ │ │ ├── Backup.java
│ │ │ └── Constant.java
│ │ ├── notification/
│ │ │ ├── NotificationCenter.java
│ │ │ ├── NotificationContext.java
│ │ │ ├── NotificationReasonEmitter.java
│ │ │ ├── ReactiveNotifier.java
│ │ │ ├── ReasonAttributes.java
│ │ │ ├── ReasonPayload.java
│ │ │ └── UserIdentity.java
│ │ ├── plugin/
│ │ │ ├── ApiVersion.java
│ │ │ ├── BasePlugin.java
│ │ │ ├── PluginConfigUpdatedEvent.java
│ │ │ ├── PluginContext.java
│ │ │ ├── PluginsRootGetter.java
│ │ │ ├── ReactiveSettingFetcher.java
│ │ │ ├── SettingFetcher.java
│ │ │ ├── SharedEvent.java
│ │ │ ├── event/
│ │ │ │ └── PluginStartedEvent.java
│ │ │ └── extensionpoint/
│ │ │ └── ExtensionGetter.java
│ │ ├── search/
│ │ │ ├── HaloDocument.java
│ │ │ ├── HaloDocumentsProvider.java
│ │ │ ├── SearchEngine.java
│ │ │ ├── SearchOption.java
│ │ │ ├── SearchResult.java
│ │ │ ├── SearchService.java
│ │ │ └── event/
│ │ │ ├── HaloDocumentAddRequestEvent.java
│ │ │ ├── HaloDocumentDeleteRequestEvent.java
│ │ │ └── HaloDocumentRebuildRequestEvent.java
│ │ ├── security/
│ │ │ ├── AdditionalWebFilter.java
│ │ │ ├── AfterSecurityWebFilter.java
│ │ │ ├── AnonymousAuthenticationSecurityWebFilter.java
│ │ │ ├── AuthenticationSecurityWebFilter.java
│ │ │ ├── BeforeSecurityWebFilter.java
│ │ │ ├── FormLoginSecurityWebFilter.java
│ │ │ ├── HttpBasicSecurityWebFilter.java
│ │ │ ├── LoginHandlerEnhancer.java
│ │ │ ├── OAuth2AuthorizationCodeSecurityWebFilter.java
│ │ │ ├── PersonalAccessToken.java
│ │ │ ├── authentication/
│ │ │ │ ├── CryptoService.java
│ │ │ │ ├── login/
│ │ │ │ │ └── UsernamePasswordAuthenticationManager.java
│ │ │ │ └── oauth2/
│ │ │ │ └── HaloOAuth2AuthenticationToken.java
│ │ │ └── device/
│ │ │ └── DeviceService.java
│ │ └── theme/
│ │ ├── Constant.java
│ │ ├── ReactivePostContentHandler.java
│ │ ├── ReactiveSinglePageContentHandler.java
│ │ ├── TemplateNameResolver.java
│ │ ├── dialect/
│ │ │ ├── CommentWidget.java
│ │ │ ├── ElementTagPostProcessor.java
│ │ │ ├── TemplateFooterProcessor.java
│ │ │ └── TemplateHeadProcessor.java
│ │ ├── finders/
│ │ │ ├── Finder.java
│ │ │ └── vo/
│ │ │ └── ExtensionVoOperator.java
│ │ └── router/
│ │ ├── ModelConst.java
│ │ ├── PageUrlUtils.java
│ │ └── UrlContextListResult.java
│ └── test/
│ └── java/
│ └── run/
│ └── halo/
│ └── app/
│ ├── core/
│ │ └── extension/
│ │ ├── content/
│ │ │ └── PostTest.java
│ │ └── notification/
│ │ └── SubscriptionTest.java
│ ├── extension/
│ │ ├── ExtensionUtilTest.java
│ │ ├── FakeExtension.java
│ │ ├── ListOptionsTest.java
│ │ ├── PageRequestImplTest.java
│ │ ├── SecretTest.java
│ │ ├── controller/
│ │ │ ├── ControllerBuilderTest.java
│ │ │ ├── DefaultControllerTest.java
│ │ │ ├── DefaultDelayQueueTest.java
│ │ │ ├── DelayedEntryTest.java
│ │ │ ├── ExtensionWatcherTest.java
│ │ │ └── RequestSynchronizerTest.java
│ │ ├── index/
│ │ │ ├── IndexAttributeFactoryTest.java
│ │ │ ├── IndexSpecTest.java
│ │ │ ├── KeyComparatorTest.java
│ │ │ ├── MultiValueBuilderTest.java
│ │ │ ├── SingleValueBuilderTest.java
│ │ │ ├── UnknownKeyTest.java
│ │ │ └── query/
│ │ │ └── QueriesTest.java
│ │ ├── indexer/
│ │ │ ├── DefaultIndexEngineTest.java
│ │ │ └── LabelIndexImplTest.java
│ │ └── router/
│ │ └── selector/
│ │ ├── LabelSelectorTest.java
│ │ ├── OperatorTest.java
│ │ └── SelectorConverterTest.java
│ └── infra/
│ └── utils/
│ ├── GenericClassUtilsTest.java
│ ├── JsonUtilsTest.java
│ └── PathUtilsTest.java
├── api-docs/
│ └── openapi/
│ └── v3_0/
│ ├── aggregated.json
│ ├── apis_console.api_v1alpha1.json
│ ├── apis_extension.api_v1alpha1.json
│ ├── apis_public.api_v1alpha1.json
│ └── apis_uc.api_v1alpha1.json
├── application/
│ ├── build.gradle
│ ├── libs/
│ │ ├── thymeleaf-3.1.3.RELEASE.jar
│ │ └── thymeleaf-spring6-3.1.3.RELEASE.jar
│ └── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── run/
│ │ │ └── halo/
│ │ │ └── app/
│ │ │ ├── Application.java
│ │ │ ├── content/
│ │ │ │ ├── AbstractContentService.java
│ │ │ │ ├── AbstractEventReconciler.java
│ │ │ │ ├── CategoryPostCountUpdater.java
│ │ │ │ ├── CategoryService.java
│ │ │ │ ├── Content.java
│ │ │ │ ├── ContentRequest.java
│ │ │ │ ├── ContentUpdateParam.java
│ │ │ │ ├── Contributor.java
│ │ │ │ ├── ListedPost.java
│ │ │ │ ├── ListedSinglePage.java
│ │ │ │ ├── ListedSnapshotDto.java
│ │ │ │ ├── NotificationReasonConst.java
│ │ │ │ ├── PostContentServiceImpl.java
│ │ │ │ ├── PostHideFromListStateUpdater.java
│ │ │ │ ├── PostQuery.java
│ │ │ │ ├── PostRequest.java
│ │ │ │ ├── PostService.java
│ │ │ │ ├── PostSorter.java
│ │ │ │ ├── SinglePageQuery.java
│ │ │ │ ├── SinglePageRequest.java
│ │ │ │ ├── SinglePageService.java
│ │ │ │ ├── SnapshotService.java
│ │ │ │ ├── Stats.java
│ │ │ │ ├── comment/
│ │ │ │ │ ├── AbstractCommentService.java
│ │ │ │ │ ├── CommentEmailOwner.java
│ │ │ │ │ ├── CommentNotificationReasonPublisher.java
│ │ │ │ │ ├── CommentQuery.java
│ │ │ │ │ ├── CommentRequest.java
│ │ │ │ │ ├── CommentService.java
│ │ │ │ │ ├── CommentServiceImpl.java
│ │ │ │ │ ├── CommentStats.java
│ │ │ │ │ ├── ListedComment.java
│ │ │ │ │ ├── ListedReply.java
│ │ │ │ │ ├── OwnerInfo.java
│ │ │ │ │ ├── PostCommentSubject.java
│ │ │ │ │ ├── ReplyNotificationSubscriptionHelper.java
│ │ │ │ │ ├── ReplyQuery.java
│ │ │ │ │ ├── ReplyRequest.java
│ │ │ │ │ ├── ReplyService.java
│ │ │ │ │ ├── ReplyServiceImpl.java
│ │ │ │ │ └── SinglePageCommentSubject.java
│ │ │ │ ├── impl/
│ │ │ │ │ ├── CategoryServiceImpl.java
│ │ │ │ │ ├── PostServiceImpl.java
│ │ │ │ │ ├── SinglePageServiceImpl.java
│ │ │ │ │ └── SnapshotServiceImpl.java
│ │ │ │ ├── permalinks/
│ │ │ │ │ ├── CategoryPermalinkPolicy.java
│ │ │ │ │ ├── ExtensionLocator.java
│ │ │ │ │ ├── PermalinkPolicy.java
│ │ │ │ │ ├── PostPermalinkPolicy.java
│ │ │ │ │ └── TagPermalinkPolicy.java
│ │ │ │ └── stats/
│ │ │ │ ├── PostStatsUpdater.java
│ │ │ │ ├── ReplyEventReconciler.java
│ │ │ │ ├── TagPostCountUpdater.java
│ │ │ │ ├── VisitedEventReconciler.java
│ │ │ │ └── VotedEventReconciler.java
│ │ │ ├── core/
│ │ │ │ ├── attachment/
│ │ │ │ │ ├── AttachmentChangedEvent.java
│ │ │ │ │ ├── AttachmentLister.java
│ │ │ │ │ ├── AttachmentRootGetter.java
│ │ │ │ │ ├── PolicyConfigChangeDetector.java
│ │ │ │ │ ├── SearchRequest.java
│ │ │ │ │ ├── endpoint/
│ │ │ │ │ │ ├── AttachmentEndpoint.java
│ │ │ │ │ │ ├── LocalAttachmentUploadHandler.java
│ │ │ │ │ │ └── PolicyEndpoint.java
│ │ │ │ │ ├── extension/
│ │ │ │ │ │ ├── LocalThumbnail.java
│ │ │ │ │ │ └── Thumbnail.java
│ │ │ │ │ ├── impl/
│ │ │ │ │ │ ├── AttachmentListerImpl.java
│ │ │ │ │ │ └── AttachmentRootGetterImpl.java
│ │ │ │ │ ├── reconciler/
│ │ │ │ │ │ ├── AttachmentReconciler.java
│ │ │ │ │ │ ├── LocalThumbnailsReconciler.java
│ │ │ │ │ │ ├── PolicyReconciler.java
│ │ │ │ │ │ └── ThumbnailReconciler.java
│ │ │ │ │ └── thumbnail/
│ │ │ │ │ ├── DefaultLocalThumbnailService.java
│ │ │ │ │ ├── DefaultThumbnailService.java
│ │ │ │ │ ├── LocalThumbnailService.java
│ │ │ │ │ ├── ThumbnailImgTagPostProcessor.java
│ │ │ │ │ ├── ThumbnailResourceTransformer.java
│ │ │ │ │ ├── ThumbnailService.java
│ │ │ │ │ └── ThumbnailUtils.java
│ │ │ │ ├── counter/
│ │ │ │ │ ├── CounterService.java
│ │ │ │ │ ├── CounterServiceImpl.java
│ │ │ │ │ └── MeterUtils.java
│ │ │ │ ├── endpoint/
│ │ │ │ │ ├── AttachmentHandler.java
│ │ │ │ │ ├── WebSocketEndpointManager.java
│ │ │ │ │ ├── WebSocketHandlerMapping.java
│ │ │ │ │ ├── console/
│ │ │ │ │ │ ├── AttachmentConsoleEndpoint.java
│ │ │ │ │ │ ├── AuthProviderEndpoint.java
│ │ │ │ │ │ ├── CommentEndpoint.java
│ │ │ │ │ │ ├── ConsoleUserEndpoint.java
│ │ │ │ │ │ ├── CustomEndpointsBuilder.java
│ │ │ │ │ │ ├── PluginEndpoint.java
│ │ │ │ │ │ ├── PostEndpoint.java
│ │ │ │ │ │ ├── ReplyEndpoint.java
│ │ │ │ │ │ ├── SinglePageEndpoint.java
│ │ │ │ │ │ ├── StatsEndpoint.java
│ │ │ │ │ │ ├── SystemConfigEndpoint.java
│ │ │ │ │ │ ├── TagEndpoint.java
│ │ │ │ │ │ ├── TrackerEndpoint.java
│ │ │ │ │ │ └── UserEndpoint.java
│ │ │ │ │ ├── theme/
│ │ │ │ │ │ ├── CategoryQueryEndpoint.java
│ │ │ │ │ │ ├── CommentFinderEndpoint.java
│ │ │ │ │ │ ├── MenuQueryEndpoint.java
│ │ │ │ │ │ ├── PluginQueryEndpoint.java
│ │ │ │ │ │ ├── PostPublicQuery.java
│ │ │ │ │ │ ├── PostQueryEndpoint.java
│ │ │ │ │ │ ├── PublicApiUtils.java
│ │ │ │ │ │ ├── SinglePageQueryEndpoint.java
│ │ │ │ │ │ ├── SiteStatsQueryEndpoint.java
│ │ │ │ │ │ ├── TagQueryEndpoint.java
│ │ │ │ │ │ └── ThumbnailEndpoint.java
│ │ │ │ │ └── uc/
│ │ │ │ │ ├── AnnotationSettingEndpoint.java
│ │ │ │ │ ├── AttachmentUcEndpoint.java
│ │ │ │ │ ├── UcPostEndpoint.java
│ │ │ │ │ ├── UcSnapshotEndpoint.java
│ │ │ │ │ ├── UcUserPreferenceEndpoint.java
│ │ │ │ │ └── UserConnectionEndpoint.java
│ │ │ │ ├── reconciler/
│ │ │ │ │ ├── AnnotationSettingReconciler.java
│ │ │ │ │ ├── AuthProviderReconciler.java
│ │ │ │ │ ├── CategoryReconciler.java
│ │ │ │ │ ├── CommentReconciler.java
│ │ │ │ │ ├── MenuItemReconciler.java
│ │ │ │ │ ├── PluginReconciler.java
│ │ │ │ │ ├── PostCounterReconciler.java
│ │ │ │ │ ├── PostReconciler.java
│ │ │ │ │ ├── ReplyReconciler.java
│ │ │ │ │ ├── ReverseProxyReconciler.java
│ │ │ │ │ ├── RoleReconciler.java
│ │ │ │ │ ├── SinglePageReconciler.java
│ │ │ │ │ ├── SystemConfigReconciler.java
│ │ │ │ │ ├── TagReconciler.java
│ │ │ │ │ ├── ThemeReconciler.java
│ │ │ │ │ └── UserReconciler.java
│ │ │ │ └── user/
│ │ │ │ └── service/
│ │ │ │ ├── DefaultRoleService.java
│ │ │ │ ├── EmailPasswordRecoveryService.java
│ │ │ │ ├── EmailVerificationService.java
│ │ │ │ ├── InMemoryResetTokenRepository.java
│ │ │ │ ├── InvalidResetTokenException.java
│ │ │ │ ├── PatService.java
│ │ │ │ ├── ResetToken.java
│ │ │ │ ├── ResetTokenRepository.java
│ │ │ │ ├── SettingConfigService.java
│ │ │ │ ├── UserConnectionService.java
│ │ │ │ ├── UserLoginOrLogoutProcessing.java
│ │ │ │ └── impl/
│ │ │ │ ├── DefaultAttachmentService.java
│ │ │ │ ├── EmailPasswordRecoveryServiceImpl.java
│ │ │ │ ├── EmailVerificationServiceImpl.java
│ │ │ │ ├── PatServiceImpl.java
│ │ │ │ ├── SettingConfigServiceImpl.java
│ │ │ │ ├── UserConnectionServiceImpl.java
│ │ │ │ └── UserServiceImpl.java
│ │ │ ├── event/
│ │ │ │ ├── post/
│ │ │ │ │ ├── CategoryHiddenStateChangeEvent.java
│ │ │ │ │ ├── CommentCreatedEvent.java
│ │ │ │ │ ├── CommentUnreadReplyCountChangedEvent.java
│ │ │ │ │ ├── DownvotedEvent.java
│ │ │ │ │ ├── PostStatsChangedEvent.java
│ │ │ │ │ ├── ReplyChangedEvent.java
│ │ │ │ │ ├── ReplyCreatedEvent.java
│ │ │ │ │ ├── ReplyDeletedEvent.java
│ │ │ │ │ ├── ReplyEvent.java
│ │ │ │ │ ├── UpvotedEvent.java
│ │ │ │ │ ├── VisitedEvent.java
│ │ │ │ │ └── VotedEvent.java
│ │ │ │ └── user/
│ │ │ │ └── PasswordChangedEvent.java
│ │ │ ├── extension/
│ │ │ │ ├── DefaultSchemeManager.java
│ │ │ │ ├── DelegateExtensionClient.java
│ │ │ │ ├── ExtensionConverter.java
│ │ │ │ ├── ExtensionStoreUtil.java
│ │ │ │ ├── JSONExtensionConverter.java
│ │ │ │ ├── ReactiveExtensionClientImpl.java
│ │ │ │ ├── availability/
│ │ │ │ │ └── IndexBuildState.java
│ │ │ │ ├── controller/
│ │ │ │ │ └── DefaultControllerManager.java
│ │ │ │ ├── event/
│ │ │ │ │ ├── IndexerBuiltEvent.java
│ │ │ │ │ ├── SchemeAddedEvent.java
│ │ │ │ │ └── SchemeRemovedEvent.java
│ │ │ │ ├── exception/
│ │ │ │ │ ├── ExtensionConvertException.java
│ │ │ │ │ ├── ExtensionNotFoundException.java
│ │ │ │ │ └── SchemaViolationException.java
│ │ │ │ ├── gc/
│ │ │ │ │ ├── GcControllerInitializer.java
│ │ │ │ │ ├── GcReconciler.java
│ │ │ │ │ ├── GcRequest.java
│ │ │ │ │ ├── GcSynchronizer.java
│ │ │ │ │ └── GcWatcher.java
│ │ │ │ ├── index/
│ │ │ │ │ ├── DefaultIndexEngine.java
│ │ │ │ │ ├── DefaultIndices.java
│ │ │ │ │ ├── DefaultIndicesManager.java
│ │ │ │ │ ├── Index.java
│ │ │ │ │ ├── IndexEngine.java
│ │ │ │ │ ├── Indices.java
│ │ │ │ │ ├── IndicesInitializer.java
│ │ │ │ │ ├── IndicesManager.java
│ │ │ │ │ ├── LabelIndex.java
│ │ │ │ │ ├── LabelIndexQuery.java
│ │ │ │ │ ├── MultiValueIndex.java
│ │ │ │ │ ├── SingleValueIndex.java
│ │ │ │ │ ├── StringUnknownKeyConverter.java
│ │ │ │ │ ├── TransactionalOperation.java
│ │ │ │ │ ├── ValueIndexQuery.java
│ │ │ │ │ └── query/
│ │ │ │ │ └── QueryVisitor.java
│ │ │ │ ├── indexer/
│ │ │ │ │ └── DefaultIndicesInitializer.java
│ │ │ │ ├── router/
│ │ │ │ │ ├── ExtensionCompositeRouterFunction.java
│ │ │ │ │ ├── ExtensionCreateHandler.java
│ │ │ │ │ ├── ExtensionDeleteHandler.java
│ │ │ │ │ ├── ExtensionGetHandler.java
│ │ │ │ │ ├── ExtensionListHandler.java
│ │ │ │ │ ├── ExtensionPatchHandler.java
│ │ │ │ │ ├── ExtensionRouterFunctionFactory.java
│ │ │ │ │ ├── ExtensionUpdateHandler.java
│ │ │ │ │ └── JsonPatch.java
│ │ │ │ └── store/
│ │ │ │ ├── ExtensionStore.java
│ │ │ │ ├── ExtensionStoreClient.java
│ │ │ │ ├── ExtensionStoreClientJPAImpl.java
│ │ │ │ ├── ExtensionStoreRepository.java
│ │ │ │ ├── ReactiveExtensionStoreClient.java
│ │ │ │ └── ReactiveExtensionStoreClientImpl.java
│ │ │ ├── infra/
│ │ │ │ ├── DefaultBackupRootGetter.java
│ │ │ │ ├── DefaultExternalLinkProcessor.java
│ │ │ │ ├── DefaultInitializationStateGetter.java
│ │ │ │ ├── DefaultReactiveUrlDataBufferFetcher.java
│ │ │ │ ├── DefaultSystemConfigFetcher.java
│ │ │ │ ├── DefaultSystemVersionSupplier.java
│ │ │ │ ├── DefaultThemeRootGetter.java
│ │ │ │ ├── ExtensionInitializedEvent.java
│ │ │ │ ├── ExtensionResourceInitializer.java
│ │ │ │ ├── ExternalUrlChangedEvent.java
│ │ │ │ ├── InitializationPhase.java
│ │ │ │ ├── InitializationStateGetter.java
│ │ │ │ ├── ReactiveExtensionPaginatedOperator.java
│ │ │ │ ├── ReactiveExtensionPaginatedOperatorImpl.java
│ │ │ │ ├── ReactiveUrlDataBufferFetcher.java
│ │ │ │ ├── SchemeInitializer.java
│ │ │ │ ├── SecureRequestMappingHandlerAdapter.java
│ │ │ │ ├── SecureServerRequest.java
│ │ │ │ ├── SecureServerWebExchange.java
│ │ │ │ ├── SystemConfigChangedEvent.java
│ │ │ │ ├── SystemConfigFetcher.java
│ │ │ │ ├── SystemConfigFirstExternalUrlSupplier.java
│ │ │ │ ├── SystemConfigInitializer.java
│ │ │ │ ├── SystemInfoGetterImpl.java
│ │ │ │ ├── SystemState.java
│ │ │ │ ├── ThemeRootGetter.java
│ │ │ │ ├── actuator/
│ │ │ │ │ ├── DatabaseInfoContributor.java
│ │ │ │ │ ├── GlobalInfo.java
│ │ │ │ │ ├── GlobalInfoEndpoint.java
│ │ │ │ │ ├── GlobalInfoService.java
│ │ │ │ │ ├── GlobalInfoServiceImpl.java
│ │ │ │ │ └── RestartEndpoint.java
│ │ │ │ ├── config/
│ │ │ │ │ ├── ExtensionConfiguration.java
│ │ │ │ │ ├── HaloConfiguration.java
│ │ │ │ │ ├── JacksonAdapterModule.java
│ │ │ │ │ ├── R2dbcConfiguration.java
│ │ │ │ │ ├── SessionConfiguration.java
│ │ │ │ │ ├── SwaggerConfig.java
│ │ │ │ │ ├── WebFluxConfig.java
│ │ │ │ │ └── WebServerSecurityConfig.java
│ │ │ │ ├── exception/
│ │ │ │ │ ├── AccessDeniedException.java
│ │ │ │ │ ├── AttachmentAlreadyExistsException.java
│ │ │ │ │ ├── DuplicateNameException.java
│ │ │ │ │ ├── EmailAlreadyTakenException.java
│ │ │ │ │ ├── EmailVerificationFailed.java
│ │ │ │ │ ├── Exceptions.java
│ │ │ │ │ ├── FileSizeExceededException.java
│ │ │ │ │ ├── FileTypeNotAllowedException.java
│ │ │ │ │ ├── NotFoundException.java
│ │ │ │ │ ├── OAuth2UserAlreadyBoundException.java
│ │ │ │ │ ├── PluginAlreadyExistsException.java
│ │ │ │ │ ├── PluginDependenciesNotEnabledException.java
│ │ │ │ │ ├── PluginDependencyException.java
│ │ │ │ │ ├── PluginDependentsNotDisabledException.java
│ │ │ │ │ ├── PluginInstallationException.java
│ │ │ │ │ ├── PluginRuntimeIncompatibleException.java
│ │ │ │ │ ├── RateLimitExceededException.java
│ │ │ │ │ ├── RequestBodyValidationException.java
│ │ │ │ │ ├── RequestRestrictedException.java
│ │ │ │ │ ├── RestrictedNameException.java
│ │ │ │ │ ├── ThemeAlreadyExistsException.java
│ │ │ │ │ ├── ThemeInstallationException.java
│ │ │ │ │ ├── ThemeUninstallException.java
│ │ │ │ │ ├── ThemeUpgradeException.java
│ │ │ │ │ ├── UnsatisfiedAttributeValueException.java
│ │ │ │ │ ├── UserNotFoundException.java
│ │ │ │ │ └── handlers/
│ │ │ │ │ ├── HaloErrorConfiguration.java
│ │ │ │ │ ├── HaloErrorWebExceptionHandler.java
│ │ │ │ │ └── ProblemDetailErrorAttributes.java
│ │ │ │ ├── properties/
│ │ │ │ │ ├── AttachmentProperties.java
│ │ │ │ │ ├── CacheProperties.java
│ │ │ │ │ ├── ExtensionProperties.java
│ │ │ │ │ ├── HaloProperties.java
│ │ │ │ │ ├── JwtProperties.java
│ │ │ │ │ ├── ProxyProperties.java
│ │ │ │ │ ├── SecurityProperties.java
│ │ │ │ │ ├── ThemeProperties.java
│ │ │ │ │ └── UiProperties.java
│ │ │ │ ├── ui/
│ │ │ │ │ ├── ProxyFilter.java
│ │ │ │ │ ├── WebSocketRequestPredicate.java
│ │ │ │ │ ├── WebSocketServerWebExchangeMatcher.java
│ │ │ │ │ └── WebSocketUtils.java
│ │ │ │ ├── utils/
│ │ │ │ │ ├── Base62Utils.java
│ │ │ │ │ ├── FileNameUtils.java
│ │ │ │ │ ├── FileUtils.java
│ │ │ │ │ ├── HaloUtils.java
│ │ │ │ │ ├── IpAddressUtils.java
│ │ │ │ │ ├── ReactiveUtils.java
│ │ │ │ │ ├── SettingUtils.java
│ │ │ │ │ ├── SortUtils.java
│ │ │ │ │ ├── SystemConfigUtils.java
│ │ │ │ │ ├── VersionUtils.java
│ │ │ │ │ └── YamlUnstructuredLoader.java
│ │ │ │ └── webfilter/
│ │ │ │ ├── AdditionalWebFilterChainProxy.java
│ │ │ │ └── LocaleChangeWebFilter.java
│ │ │ ├── migration/
│ │ │ │ ├── BackupFile.java
│ │ │ │ ├── BackupReconciler.java
│ │ │ │ ├── MigrationEndpoint.java
│ │ │ │ ├── MigrationService.java
│ │ │ │ └── impl/
│ │ │ │ └── MigrationServiceImpl.java
│ │ │ ├── notification/
│ │ │ │ ├── DefaultNotificationCenter.java
│ │ │ │ ├── DefaultNotificationReasonEmitter.java
│ │ │ │ ├── DefaultNotificationSender.java
│ │ │ │ ├── DefaultNotificationService.java
│ │ │ │ ├── DefaultNotificationTemplateRender.java
│ │ │ │ ├── DefaultNotifierConfigStore.java
│ │ │ │ ├── DefaultSubscriberEmailResolver.java
│ │ │ │ ├── EmailNotifier.java
│ │ │ │ ├── EmailSenderHelper.java
│ │ │ │ ├── EmailSenderHelperImpl.java
│ │ │ │ ├── LanguageUtils.java
│ │ │ │ ├── NotificationSender.java
│ │ │ │ ├── NotificationTemplateRender.java
│ │ │ │ ├── NotificationTrigger.java
│ │ │ │ ├── NotifierConfigStore.java
│ │ │ │ ├── ReasonNotificationTemplateSelector.java
│ │ │ │ ├── ReasonNotificationTemplateSelectorImpl.java
│ │ │ │ ├── RecipientResolver.java
│ │ │ │ ├── RecipientResolverImpl.java
│ │ │ │ ├── Subscriber.java
│ │ │ │ ├── SubscriberEmailResolver.java
│ │ │ │ ├── SubscriptionService.java
│ │ │ │ ├── SubscriptionServiceImpl.java
│ │ │ │ ├── UserNotificationPreference.java
│ │ │ │ ├── UserNotificationPreferenceService.java
│ │ │ │ ├── UserNotificationPreferenceServiceImpl.java
│ │ │ │ ├── UserNotificationQuery.java
│ │ │ │ ├── UserNotificationService.java
│ │ │ │ └── endpoint/
│ │ │ │ ├── ConsoleNotifierEndpoint.java
│ │ │ │ ├── EmailConfigValidationEndpoint.java
│ │ │ │ ├── SubscriptionRouter.java
│ │ │ │ ├── UserNotificationEndpoint.java
│ │ │ │ ├── UserNotificationPreferencesEndpoint.java
│ │ │ │ └── UserNotifierEndpoint.java
│ │ │ ├── plugin/
│ │ │ │ ├── AggregatedRouterFunction.java
│ │ │ │ ├── BuiltInPluginsInitializer.java
│ │ │ │ ├── DefaultDevelopmentPluginRepository.java
│ │ │ │ ├── DefaultPluginApplicationContextFactory.java
│ │ │ │ ├── DefaultPluginGetter.java
│ │ │ │ ├── DefaultPluginRouterFunctionRegistry.java
│ │ │ │ ├── DefaultReactiveSettingFetcher.java
│ │ │ │ ├── DefaultSettingFetcher.java
│ │ │ │ ├── DefaultSpringPlugin.java
│ │ │ │ ├── DevPluginLoader.java
│ │ │ │ ├── HaloPluginManager.java
│ │ │ │ ├── HaloSharedEventDelegator.java
│ │ │ │ ├── OptionalDependentResolver.java
│ │ │ │ ├── PluginApplicationContext.java
│ │ │ │ ├── PluginApplicationContextFactory.java
│ │ │ │ ├── PluginAutoConfiguration.java
│ │ │ │ ├── PluginBeforeStopSyncListener.java
│ │ │ │ ├── PluginConst.java
│ │ │ │ ├── PluginControllerManager.java
│ │ │ │ ├── PluginDevelopmentInitializer.java
│ │ │ │ ├── PluginExtensionLoaderUtils.java
│ │ │ │ ├── PluginFinder.java
│ │ │ │ ├── PluginGetter.java
│ │ │ │ ├── PluginNotFoundException.java
│ │ │ │ ├── PluginProperties.java
│ │ │ │ ├── PluginRequestMappingHandlerMapping.java
│ │ │ │ ├── PluginRouterFunctionRegistry.java
│ │ │ │ ├── PluginService.java
│ │ │ │ ├── PluginServiceImpl.java
│ │ │ │ ├── PluginSharedEventDelegator.java
│ │ │ │ ├── PluginStartedListener.java
│ │ │ │ ├── PluginUtils.java
│ │ │ │ ├── PluginsRootGetterImpl.java
│ │ │ │ ├── PropertyPluginStatusProvider.java
│ │ │ │ ├── SharedApplicationContextFactory.java
│ │ │ │ ├── SharedEventDispatcher.java
│ │ │ │ ├── SpringComponentsFinder.java
│ │ │ │ ├── SpringExtensionFactory.java
│ │ │ │ ├── SpringPlugin.java
│ │ │ │ ├── SpringPluginFactory.java
│ │ │ │ ├── SpringPluginManager.java
│ │ │ │ ├── YamlPluginDescriptorFinder.java
│ │ │ │ ├── YamlPluginFinder.java
│ │ │ │ ├── event/
│ │ │ │ │ ├── HaloPluginBeforeStopEvent.java
│ │ │ │ │ ├── HaloPluginStartedEvent.java
│ │ │ │ │ ├── HaloPluginStoppedEvent.java
│ │ │ │ │ ├── SpringPluginStartedEvent.java
│ │ │ │ │ ├── SpringPluginStartingEvent.java
│ │ │ │ │ ├── SpringPluginStoppedEvent.java
│ │ │ │ │ └── SpringPluginStoppingEvent.java
│ │ │ │ ├── extensionpoint/
│ │ │ │ │ ├── AbstractDefinitionGetter.java
│ │ │ │ │ ├── DefaultExtensionGetter.java
│ │ │ │ │ ├── ExtensionDefinition.java
│ │ │ │ │ ├── ExtensionDefinitionGetter.java
│ │ │ │ │ ├── ExtensionDefinitionGetterImpl.java
│ │ │ │ │ ├── ExtensionPointDefinition.java
│ │ │ │ │ ├── ExtensionPointDefinitionGetter.java
│ │ │ │ │ └── ExtensionPointDefinitionGetterImpl.java
│ │ │ │ └── resources/
│ │ │ │ ├── BundleResourceUtils.java
│ │ │ │ ├── ReverseProxyRouterFunctionFactory.java
│ │ │ │ └── ReverseProxyRouterFunctionRegistry.java
│ │ │ ├── search/
│ │ │ │ ├── HaloDocumentEventsListener.java
│ │ │ │ ├── IndexEndpoint.java
│ │ │ │ ├── IndicesEndpoint.java
│ │ │ │ ├── SearchEngineUnavailableException.java
│ │ │ │ ├── SearchServiceImpl.java
│ │ │ │ ├── lucene/
│ │ │ │ │ └── LuceneSearchEngine.java
│ │ │ │ └── post/
│ │ │ │ ├── PostEventsListener.java
│ │ │ │ └── PostHaloDocumentsProvider.java
│ │ │ ├── security/
│ │ │ │ ├── AuthProviderService.java
│ │ │ │ ├── AuthProviderServiceImpl.java
│ │ │ │ ├── CorsConfigurer.java
│ │ │ │ ├── CsrfConfigurer.java
│ │ │ │ ├── DefaultServerAuthenticationEntryPoint.java
│ │ │ │ ├── DefaultSuperAdminInitializer.java
│ │ │ │ ├── DefaultUserDetailService.java
│ │ │ │ ├── ExceptionSecurityConfigurer.java
│ │ │ │ ├── HaloRedirectAuthenticationSuccessHandler.java
│ │ │ │ ├── HaloServerRequestCache.java
│ │ │ │ ├── HaloUserDetails.java
│ │ │ │ ├── InitializeRedirectionWebFilter.java
│ │ │ │ ├── ListedAuthProvider.java
│ │ │ │ ├── LoginHandlerEnhancerImpl.java
│ │ │ │ ├── LogoutSecurityConfigurer.java
│ │ │ │ ├── RedirectAccessDeniedHandler.java
│ │ │ │ ├── SecurityWebFiltersConfigurer.java
│ │ │ │ ├── SuperAdminInitializer.java
│ │ │ │ ├── authentication/
│ │ │ │ │ ├── SecurityConfigurer.java
│ │ │ │ │ ├── WebExchangeMatchers.java
│ │ │ │ │ ├── exception/
│ │ │ │ │ │ ├── TooManyRequestsException.java
│ │ │ │ │ │ └── TwoFactorAuthException.java
│ │ │ │ │ ├── impl/
│ │ │ │ │ │ └── RsaKeyService.java
│ │ │ │ │ ├── login/
│ │ │ │ │ │ ├── HaloUser.java
│ │ │ │ │ │ ├── InvalidEncryptedMessageException.java
│ │ │ │ │ │ ├── LoginAuthenticationConverter.java
│ │ │ │ │ │ ├── LoginSecurityConfigurer.java
│ │ │ │ │ │ ├── PublicKeyRouteBuilder.java
│ │ │ │ │ │ ├── UsernamePasswordDelegatingAuthenticationManager.java
│ │ │ │ │ │ └── UsernamePasswordHandler.java
│ │ │ │ │ ├── oauth2/
│ │ │ │ │ │ ├── DefaultOAuth2LoginHandlerEnhancer.java
│ │ │ │ │ │ ├── MapOAuth2AuthenticationFilter.java
│ │ │ │ │ │ ├── OAuth2AuthenticationTokenCache.java
│ │ │ │ │ │ ├── OAuth2LoginHandlerEnhancer.java
│ │ │ │ │ │ ├── OAuth2SecurityConfigurer.java
│ │ │ │ │ │ └── WebSessionOAuth2AuthenticationTokenCache.java
│ │ │ │ │ ├── pat/
│ │ │ │ │ │ ├── PatAuthenticationConverter.java
│ │ │ │ │ │ ├── PatAuthenticationManager.java
│ │ │ │ │ │ ├── PatEndpoint.java
│ │ │ │ │ │ ├── PatSecurityConfigurer.java
│ │ │ │ │ │ ├── UserScopedPatHandler.java
│ │ │ │ │ │ └── UserScopedPatHandlerImpl.java
│ │ │ │ │ ├── rememberme/
│ │ │ │ │ │ ├── CookieSignatureKeyResolver.java
│ │ │ │ │ │ ├── DefaultCookieSignatureKeyResolver.java
│ │ │ │ │ │ ├── PersistentRememberMeTokenRepository.java
│ │ │ │ │ │ ├── PersistentRememberMeTokenRepositoryImpl.java
│ │ │ │ │ │ ├── PersistentTokenBasedRememberMeServices.java
│ │ │ │ │ │ ├── RememberMeAuthenticationManager.java
│ │ │ │ │ │ ├── RememberMeConfigurer.java
│ │ │ │ │ │ ├── RememberMeCookieResolver.java
│ │ │ │ │ │ ├── RememberMeCookieResolverImpl.java
│ │ │ │ │ │ ├── RememberMeRequestCache.java
│ │ │ │ │ │ ├── RememberMeServices.java
│ │ │ │ │ │ ├── RememberMeTokenRevoker.java
│ │ │ │ │ │ ├── RememberTokenCleaner.java
│ │ │ │ │ │ ├── TokenBasedRememberMeServices.java
│ │ │ │ │ │ └── WebSessionRememberMeRequestCache.java
│ │ │ │ │ └── twofactor/
│ │ │ │ │ ├── TotpAuthenticationSuccessHandler.java
│ │ │ │ │ ├── TwoFactorAuthEndpoint.java
│ │ │ │ │ ├── TwoFactorAuthRequiredException.java
│ │ │ │ │ ├── TwoFactorAuthSecurityConfigurer.java
│ │ │ │ │ ├── TwoFactorAuthSettings.java
│ │ │ │ │ ├── TwoFactorAuthentication.java
│ │ │ │ │ ├── TwoFactorAuthenticationEntryPoint.java
│ │ │ │ │ ├── TwoFactorUtils.java
│ │ │ │ │ └── totp/
│ │ │ │ │ ├── DefaultTotpAuthService.java
│ │ │ │ │ ├── TotpAuthService.java
│ │ │ │ │ ├── TotpAuthenticationManager.java
│ │ │ │ │ ├── TotpAuthenticationToken.java
│ │ │ │ │ └── TotpCodeAuthenticationConverter.java
│ │ │ │ ├── authorization/
│ │ │ │ │ ├── Attributes.java
│ │ │ │ │ ├── AttributesRecord.java
│ │ │ │ │ ├── AuthorityUtils.java
│ │ │ │ │ ├── AuthorizationExchangeConfigurers.java
│ │ │ │ │ ├── AuthorizationRuleResolver.java
│ │ │ │ │ ├── AuthorizingVisitor.java
│ │ │ │ │ ├── DefaultRuleResolver.java
│ │ │ │ │ ├── PolicyRuleList.java
│ │ │ │ │ ├── RbacRequestEvaluation.java
│ │ │ │ │ ├── RequestInfo.java
│ │ │ │ │ ├── RequestInfoAuthorizationManager.java
│ │ │ │ │ ├── RequestInfoFactory.java
│ │ │ │ │ └── RuleAccumulator.java
│ │ │ │ ├── device/
│ │ │ │ │ ├── DeviceCookieResolver.java
│ │ │ │ │ ├── DeviceCookieResolverImpl.java
│ │ │ │ │ ├── DeviceEndpoint.java
│ │ │ │ │ ├── DeviceReconciler.java
│ │ │ │ │ ├── DeviceSecurityConfigurer.java
│ │ │ │ │ ├── DeviceServiceImpl.java
│ │ │ │ │ ├── DeviceSessionFilter.java
│ │ │ │ │ ├── NewDeviceLoginEvent.java
│ │ │ │ │ └── NewDeviceLoginListener.java
│ │ │ │ ├── jackson2/
│ │ │ │ │ ├── HaloOAuth2AuthenticationTokenMixin.java
│ │ │ │ │ ├── HaloSecurityJackson2Module.java
│ │ │ │ │ ├── HaloUserMixin.java
│ │ │ │ │ ├── SwitchUserGrantedAuthorityMixIn.java
│ │ │ │ │ └── TwoFactorAuthenticationMixin.java
│ │ │ │ ├── preauth/
│ │ │ │ │ ├── DefaultPasswordResetAvailabilityProviders.java
│ │ │ │ │ ├── EmailPasswordResetAvailabilityProvider.java
│ │ │ │ │ ├── PasswordResetAvailabilityProvider.java
│ │ │ │ │ ├── PasswordResetAvailabilityProviders.java
│ │ │ │ │ ├── PreAuthEmailPasswordResetEndpoint.java
│ │ │ │ │ ├── PreAuthLoginEndpoint.java
│ │ │ │ │ ├── PreAuthSignUpEndpoint.java
│ │ │ │ │ ├── PreAuthTwoFactorEndpoint.java
│ │ │ │ │ └── SystemSetupEndpoint.java
│ │ │ │ ├── session/
│ │ │ │ │ ├── InMemoryReactiveIndexedSessionRepository.java
│ │ │ │ │ ├── ReactiveIndexedSessionRepository.java
│ │ │ │ │ └── SessionInvalidationListener.java
│ │ │ │ └── switchuser/
│ │ │ │ └── SwitchUserConfigurer.java
│ │ │ └── theme/
│ │ │ ├── CompositeTemplateResolver.java
│ │ │ ├── DefaultTemplateEnum.java
│ │ │ ├── DefaultTemplateNameResolver.java
│ │ │ ├── DefaultViewNameResolver.java
│ │ │ ├── HaloViewResolver.java
│ │ │ ├── ReactiveSpelVariableExpressionEvaluator.java
│ │ │ ├── SiteSettingVariablesAcquirer.java
│ │ │ ├── TemplateEngineManager.java
│ │ │ ├── ThemeContext.java
│ │ │ ├── ThemeContextBasedVariablesAcquirer.java
│ │ │ ├── ThemeLinkBuilder.java
│ │ │ ├── ThemeLocaleContextResolver.java
│ │ │ ├── ThemeResolver.java
│ │ │ ├── UserLocaleRequestAttributeWriteFilter.java
│ │ │ ├── ViewContextBasedVariablesAcquirer.java
│ │ │ ├── ViewNameResolver.java
│ │ │ ├── config/
│ │ │ │ ├── ThemeConfiguration.java
│ │ │ │ └── ThemeWebFluxConfigurer.java
│ │ │ ├── dialect/
│ │ │ │ ├── CommentElementTagProcessor.java
│ │ │ │ ├── CommentEnabledVariableProcessor.java
│ │ │ │ ├── ContentTemplateHeadProcessor.java
│ │ │ │ ├── DefaultFaviconHeadProcessor.java
│ │ │ │ ├── DefaultLinkExpressionFactory.java
│ │ │ │ ├── DuplicateMetaTagProcessor.java
│ │ │ │ ├── EvaluationContextEnhancer.java
│ │ │ │ ├── GeneratorMetaProcessor.java
│ │ │ │ ├── GlobalHeadInjectionProcessor.java
│ │ │ │ ├── GlobalSeoProcessor.java
│ │ │ │ ├── HaloExpressionObjectFactory.java
│ │ │ │ ├── HaloPostTemplateHandler.java
│ │ │ │ ├── HaloProcessorDialect.java
│ │ │ │ ├── HaloSpringSecurityDialect.java
│ │ │ │ ├── HaloTrackerProcessor.java
│ │ │ │ ├── IndexSeoProcessor.java
│ │ │ │ ├── InjectionExcluderProcessor.java
│ │ │ │ ├── LinkExpressionObjectDialect.java
│ │ │ │ ├── SecureTemplateContext.java
│ │ │ │ ├── SecureTemplateContextWrapper.java
│ │ │ │ ├── SecureTemplateWebContext.java
│ │ │ │ ├── TemplateFooterElementTagProcessor.java
│ │ │ │ ├── TemplateGlobalHeadProcessor.java
│ │ │ │ └── expression/
│ │ │ │ └── Annotations.java
│ │ │ ├── endpoint/
│ │ │ │ └── ThemeEndpoint.java
│ │ │ ├── engine/
│ │ │ │ ├── DefaultThemeTemplateAvailabilityProvider.java
│ │ │ │ ├── HaloTemplateEngine.java
│ │ │ │ ├── PluginClassloaderTemplateResolver.java
│ │ │ │ └── ThemeTemplateAvailabilityProvider.java
│ │ │ ├── finders/
│ │ │ │ ├── CategoryFinder.java
│ │ │ │ ├── CommentFinder.java
│ │ │ │ ├── CommentPublicQueryService.java
│ │ │ │ ├── ContributorFinder.java
│ │ │ │ ├── DefaultFinderRegistry.java
│ │ │ │ ├── FinderRegistry.java
│ │ │ │ ├── MenuFinder.java
│ │ │ │ ├── PluginFinder.java
│ │ │ │ ├── PostFinder.java
│ │ │ │ ├── PostPublicQueryService.java
│ │ │ │ ├── SinglePageConversionService.java
│ │ │ │ ├── SinglePageFinder.java
│ │ │ │ ├── SiteStatsFinder.java
│ │ │ │ ├── TagFinder.java
│ │ │ │ ├── ThemeFinder.java
│ │ │ │ ├── ThumbnailFinder.java
│ │ │ │ ├── impl/
│ │ │ │ │ ├── CategoryFinderImpl.java
│ │ │ │ │ ├── CommentFinderImpl.java
│ │ │ │ │ ├── CommentPublicQueryServiceImpl.java
│ │ │ │ │ ├── ContributorFinderImpl.java
│ │ │ │ │ ├── MenuFinderImpl.java
│ │ │ │ │ ├── PluginFinderImpl.java
│ │ │ │ │ ├── PostFinderImpl.java
│ │ │ │ │ ├── PostPublicQueryServiceImpl.java
│ │ │ │ │ ├── SinglePageConversionServiceImpl.java
│ │ │ │ │ ├── SinglePageFinderImpl.java
│ │ │ │ │ ├── SiteStatsFinderImpl.java
│ │ │ │ │ ├── TagFinderImpl.java
│ │ │ │ │ ├── ThemeFinderImpl.java
│ │ │ │ │ └── ThumbnailFinderImpl.java
│ │ │ │ └── vo/
│ │ │ │ ├── CategoryTreeVo.java
│ │ │ │ ├── CategoryVo.java
│ │ │ │ ├── CommentStatsVo.java
│ │ │ │ ├── CommentVo.java
│ │ │ │ ├── CommentWithReplyVo.java
│ │ │ │ ├── ContentVo.java
│ │ │ │ ├── ContributorVo.java
│ │ │ │ ├── ListedPostVo.java
│ │ │ │ ├── ListedSinglePageVo.java
│ │ │ │ ├── MenuItemVo.java
│ │ │ │ ├── MenuVo.java
│ │ │ │ ├── NavigationPostVo.java
│ │ │ │ ├── PostArchiveVo.java
│ │ │ │ ├── PostArchiveYearMonthVo.java
│ │ │ │ ├── PostVo.java
│ │ │ │ ├── ReplyVo.java
│ │ │ │ ├── SinglePageVo.java
│ │ │ │ ├── SiteSettingVo.java
│ │ │ │ ├── SiteStatsVo.java
│ │ │ │ ├── StatsVo.java
│ │ │ │ ├── TagVo.java
│ │ │ │ ├── ThemeVo.java
│ │ │ │ ├── UserVo.java
│ │ │ │ └── VisualizableTreeNode.java
│ │ │ ├── message/
│ │ │ │ ├── ThemeMessageResolutionUtils.java
│ │ │ │ └── ThemeMessageResolver.java
│ │ │ ├── router/
│ │ │ │ ├── DefaultQueryPostPredicateResolver.java
│ │ │ │ ├── ExtensionPermalinkPatternUpdater.java
│ │ │ │ ├── ModelMapUtils.java
│ │ │ │ ├── PermalinkRuleChangedEvent.java
│ │ │ │ ├── PreviewRouterFunction.java
│ │ │ │ ├── ReactiveQueryPostPredicateResolver.java
│ │ │ │ ├── SinglePageRoute.java
│ │ │ │ ├── ThemeCompositeRouterFunction.java
│ │ │ │ ├── TitleVisibilityIdentifyCalculator.java
│ │ │ │ └── factories/
│ │ │ │ ├── ArchiveRouteFactory.java
│ │ │ │ ├── AuthorPostsRouteFactory.java
│ │ │ │ ├── CategoriesRouteFactory.java
│ │ │ │ ├── CategoryPostRouteFactory.java
│ │ │ │ ├── IndexRouteFactory.java
│ │ │ │ ├── PostRouteFactory.java
│ │ │ │ ├── RouteFactory.java
│ │ │ │ ├── TagPostRouteFactory.java
│ │ │ │ └── TagsRouteFactory.java
│ │ │ ├── service/
│ │ │ │ ├── ThemeService.java
│ │ │ │ ├── ThemeServiceImpl.java
│ │ │ │ └── ThemeUtils.java
│ │ │ └── utils/
│ │ │ └── PatternUtils.java
│ │ └── resources/
│ │ ├── META-INF/
│ │ │ └── spring-devtools.properties
│ │ ├── application-dev.yaml
│ │ ├── application-doc.yaml
│ │ ├── application-mariadb.yaml
│ │ ├── application-mysql.yaml
│ │ ├── application-postgresql.yaml
│ │ ├── application-win.yaml
│ │ ├── application.yaml
│ │ ├── banner.txt
│ │ ├── config/
│ │ │ └── i18n/
│ │ │ ├── messages.properties
│ │ │ ├── messages_es.properties
│ │ │ └── messages_zh.properties
│ │ ├── db/
│ │ │ └── migration/
│ │ │ ├── h2/
│ │ │ │ └── .gitkeep
│ │ │ ├── mariadb/
│ │ │ │ └── .gitkeep
│ │ │ ├── mysql/
│ │ │ │ └── .gitkeep
│ │ │ └── postgresql/
│ │ │ └── .gitkeep
│ │ ├── extensions/
│ │ │ ├── attachment-local-policy.yaml
│ │ │ ├── authproviders.yaml
│ │ │ ├── extension-definitions.yaml
│ │ │ ├── extensionpoint-definitions.yaml
│ │ │ ├── notification-templates.yaml
│ │ │ ├── notification.yaml
│ │ │ ├── role-template-actuator.yaml
│ │ │ ├── role-template-anonymous.yaml
│ │ │ ├── role-template-attachment.yaml
│ │ │ ├── role-template-authenticated.yaml
│ │ │ ├── role-template-cache.yaml
│ │ │ ├── role-template-category.yaml
│ │ │ ├── role-template-comment.yaml
│ │ │ ├── role-template-configmap.yaml
│ │ │ ├── role-template-menu.yaml
│ │ │ ├── role-template-migration.yaml
│ │ │ ├── role-template-notification.yaml
│ │ │ ├── role-template-permissions.yaml
│ │ │ ├── role-template-plugin.yaml
│ │ │ ├── role-template-post.yaml
│ │ │ ├── role-template-role.yaml
│ │ │ ├── role-template-setting.yaml
│ │ │ ├── role-template-singlepage.yaml
│ │ │ ├── role-template-snapshot.yaml
│ │ │ ├── role-template-tag.yaml
│ │ │ ├── role-template-theme.yaml
│ │ │ ├── role-template-uc-attachment.yaml
│ │ │ ├── role-template-uc-content.yaml
│ │ │ ├── role-template-user.yaml
│ │ │ ├── system-configurable-configmap.yaml
│ │ │ ├── system-default-role.yaml
│ │ │ ├── system-setting.yaml
│ │ │ └── user.yaml
│ │ ├── initial-data.yaml
│ │ ├── schema-h2.sql
│ │ ├── schema-mariadb.sql
│ │ ├── schema-mysql.sql
│ │ ├── schema-postgresql.sql
│ │ ├── static/
│ │ │ ├── halo-tracker.js
│ │ │ ├── js/
│ │ │ │ └── main.js
│ │ │ └── styles/
│ │ │ └── main.css
│ │ ├── templates/
│ │ │ ├── challenges/
│ │ │ │ └── two-factor/
│ │ │ │ ├── totp.html
│ │ │ │ ├── totp.properties
│ │ │ │ ├── totp_en.properties
│ │ │ │ ├── totp_es.properties
│ │ │ │ └── totp_zh_TW.properties
│ │ │ ├── error/
│ │ │ │ └── error.html
│ │ │ ├── gateway_fragments/
│ │ │ │ ├── common.html
│ │ │ │ ├── common.properties
│ │ │ │ ├── common_en.properties
│ │ │ │ ├── common_es.properties
│ │ │ │ ├── common_zh_TW.properties
│ │ │ │ ├── input.html
│ │ │ │ ├── layout.html
│ │ │ │ ├── login.html
│ │ │ │ ├── login.properties
│ │ │ │ ├── login_en.properties
│ │ │ │ ├── login_es.properties
│ │ │ │ ├── login_zh_TW.properties
│ │ │ │ ├── logout.html
│ │ │ │ ├── logout.properties
│ │ │ │ ├── logout_en.properties
│ │ │ │ ├── logout_es.properties
│ │ │ │ ├── logout_zh_TW.properties
│ │ │ │ ├── password_reset_email_reset.html
│ │ │ │ ├── password_reset_email_reset.properties
│ │ │ │ ├── password_reset_email_reset_en.properties
│ │ │ │ ├── password_reset_email_reset_es.properties
│ │ │ │ ├── password_reset_email_reset_zh_TW.properties
│ │ │ │ ├── password_reset_email_send.html
│ │ │ │ ├── password_reset_email_send.properties
│ │ │ │ ├── password_reset_email_send_en.properties
│ │ │ │ ├── password_reset_email_send_es.properties
│ │ │ │ ├── password_reset_email_send_zh_TW.properties
│ │ │ │ ├── signup.html
│ │ │ │ ├── signup.properties
│ │ │ │ ├── signup_en.properties
│ │ │ │ ├── signup_es.properties
│ │ │ │ ├── signup_zh_TW.properties
│ │ │ │ ├── totp.html
│ │ │ │ ├── totp.properties
│ │ │ │ ├── totp_en.properties
│ │ │ │ ├── totp_es.properties
│ │ │ │ └── totp_zh_TW.properties
│ │ │ ├── login.html
│ │ │ ├── login.properties
│ │ │ ├── login_en.properties
│ │ │ ├── login_es.properties
│ │ │ ├── login_local.html
│ │ │ ├── login_local.properties
│ │ │ ├── login_local_en.properties
│ │ │ ├── login_local_es.properties
│ │ │ ├── login_local_zh_TW.properties
│ │ │ ├── login_zh_TW.properties
│ │ │ ├── logout.html
│ │ │ ├── logout.properties
│ │ │ ├── logout_en.properties
│ │ │ ├── logout_es.properties
│ │ │ ├── logout_zh_TW.properties
│ │ │ ├── password-reset/
│ │ │ │ └── email/
│ │ │ │ ├── reset.html
│ │ │ │ ├── reset.properties
│ │ │ │ ├── reset_en.properties
│ │ │ │ ├── reset_es.properties
│ │ │ │ ├── reset_zh_TW.properties
│ │ │ │ ├── send.html
│ │ │ │ ├── send.properties
│ │ │ │ ├── send_en.properties
│ │ │ │ ├── send_es.properties
│ │ │ │ └── send_zh_TW.properties
│ │ │ ├── setup.html
│ │ │ ├── setup.properties
│ │ │ ├── setup_en.properties
│ │ │ ├── setup_es.properties
│ │ │ ├── setup_zh_TW.properties
│ │ │ ├── signup.html
│ │ │ ├── signup.properties
│ │ │ ├── signup_en.properties
│ │ │ ├── signup_es.properties
│ │ │ └── signup_zh_TW.properties
│ │ └── thumbnailator.properties
│ └── test/
│ ├── java/
│ │ └── run/
│ │ └── halo/
│ │ └── app/
│ │ ├── ApplicationTests.java
│ │ ├── PathPrefixPredicateTest.java
│ │ ├── XForwardHeaderTest.java
│ │ ├── config/
│ │ │ ├── CorsTest.java
│ │ │ ├── ExtensionConfigurationTest.java
│ │ │ ├── HaloConfigurationTest.java
│ │ │ ├── SecurityConfigTest.java
│ │ │ ├── ServerCodecTest.java
│ │ │ └── WebFluxConfigTest.java
│ │ ├── content/
│ │ │ ├── CategoryPostCountUpdaterTest.java
│ │ │ ├── ContentRequestTest.java
│ │ │ ├── PostIntegrationTests.java
│ │ │ ├── TestPost.java
│ │ │ ├── comment/
│ │ │ │ ├── CommentEmailOwnerTest.java
│ │ │ │ ├── CommentNotificationReasonPublisherTest.java
│ │ │ │ ├── CommentRequestTest.java
│ │ │ │ ├── CommentServiceImplIntegrationTest.java
│ │ │ │ ├── CommentServiceImplTest.java
│ │ │ │ ├── PostCommentSubjectTest.java
│ │ │ │ ├── ReplyNotificationSubscriptionHelperTest.java
│ │ │ │ ├── ReplyServiceImplIntegrationTest.java
│ │ │ │ └── SinglePageCommentSubjectTest.java
│ │ │ └── permalinks/
│ │ │ ├── CategoryPermalinkPolicyTest.java
│ │ │ ├── PostPermalinkPolicyTest.java
│ │ │ └── TagPermalinkPolicyTest.java
│ │ ├── core/
│ │ │ ├── attachment/
│ │ │ │ ├── PolicyConfigChangeDetectorTest.java
│ │ │ │ ├── endpoint/
│ │ │ │ │ ├── LocalAttachmentUploadHandlerTest.java
│ │ │ │ │ └── PolicyEndpointTest.java
│ │ │ │ ├── impl/
│ │ │ │ │ └── AttachmentRootGetterImplTest.java
│ │ │ │ └── thumbnail/
│ │ │ │ ├── DefaultLocalThumbnailServiceTest.java
│ │ │ │ ├── DefaultThumbnailServiceTest.java
│ │ │ │ ├── ThumbnailImgTagPostProcessorTest.java
│ │ │ │ ├── ThumbnailResourceTransformerTest.java
│ │ │ │ └── ThumbnailUtilsTest.java
│ │ │ ├── counter/
│ │ │ │ └── MeterUtilsTest.java
│ │ │ ├── endpoint/
│ │ │ │ ├── WebSocketHandlerMappingTest.java
│ │ │ │ ├── console/
│ │ │ │ │ ├── EmailVerificationCodeTest.java
│ │ │ │ │ ├── PluginEndpointTest.java
│ │ │ │ │ ├── PostEndpointTest.java
│ │ │ │ │ ├── SinglePageEndpointTest.java
│ │ │ │ │ ├── TagEndpointTest.java
│ │ │ │ │ ├── UserEndpointIntegrationTest.java
│ │ │ │ │ └── UserEndpointTest.java
│ │ │ │ ├── theme/
│ │ │ │ │ ├── CategoryQueryEndpointTest.java
│ │ │ │ │ ├── CommentFinderEndpointTest.java
│ │ │ │ │ ├── MenuQueryEndpointTest.java
│ │ │ │ │ ├── PluginQueryEndpointTest.java
│ │ │ │ │ ├── PostQueryEndpointTest.java
│ │ │ │ │ ├── PublicApiUtilsTest.java
│ │ │ │ │ ├── SinglePageQueryEndpointTest.java
│ │ │ │ │ └── ThumbnailEndpointTest.java
│ │ │ │ └── uc/
│ │ │ │ ├── AnnotationSettingEndpointTest.java
│ │ │ │ └── UcUserPreferenceEndpointTest.java
│ │ │ ├── extension/
│ │ │ │ ├── PostTest.java
│ │ │ │ ├── RoleBindingTest.java
│ │ │ │ ├── SettingTest.java
│ │ │ │ ├── TestRole.java
│ │ │ │ ├── ThemeTest.java
│ │ │ │ └── attachment/
│ │ │ │ └── endpoint/
│ │ │ │ └── AttachmentEndpointTest.java
│ │ │ ├── reconciler/
│ │ │ │ ├── CommentReconcilerTest.java
│ │ │ │ ├── MenuItemReconcilerTest.java
│ │ │ │ ├── PluginReconcilerTest.java
│ │ │ │ ├── PostReconcilerTest.java
│ │ │ │ ├── ReverseProxyReconcilerTest.java
│ │ │ │ ├── SinglePageReconcilerTest.java
│ │ │ │ ├── SystemConfigReconcilerTest.java
│ │ │ │ ├── TagReconcilerTest.java
│ │ │ │ ├── ThemeReconcilerTest.java
│ │ │ │ └── UserReconcilerTest.java
│ │ │ └── user/
│ │ │ └── service/
│ │ │ ├── DefaultRoleServiceTest.java
│ │ │ └── impl/
│ │ │ ├── EmailPasswordRecoveryServiceImplTest.java
│ │ │ ├── EmailVerificationServiceImplTest.java
│ │ │ └── UserServiceImplTest.java
│ │ ├── extension/
│ │ │ ├── AbstractExtensionTest.java
│ │ │ ├── ComparatorsTest.java
│ │ │ ├── ConfigMapTest.java
│ │ │ ├── DefaultSchemeManagerTest.java
│ │ │ ├── ExtensionOperatorTest.java
│ │ │ ├── ExtensionStoreUtilTest.java
│ │ │ ├── FakeExtension.java
│ │ │ ├── GroupVersionKindTest.java
│ │ │ ├── GroupVersionTest.java
│ │ │ ├── JsonExtensionConverterTest.java
│ │ │ ├── JsonExtensionTest.java
│ │ │ ├── ListResultTest.java
│ │ │ ├── MetadataOperatorTest.java
│ │ │ ├── ReactiveExtensionClientTest.java
│ │ │ ├── RefTest.java
│ │ │ ├── SchemeTest.java
│ │ │ ├── UnstructuredTest.java
│ │ │ ├── gc/
│ │ │ │ ├── GcReconcilerTest.java
│ │ │ │ ├── GcSynchronizerTest.java
│ │ │ │ └── GcWatcherTest.java
│ │ │ ├── index/
│ │ │ │ ├── DefaultIndexEngineTest.java
│ │ │ │ ├── DefaultIndicesManagerTest.java
│ │ │ │ ├── DefaultIndicesTest.java
│ │ │ │ ├── Fake.java
│ │ │ │ ├── LabelIndexTest.java
│ │ │ │ ├── MultiValueIndexTest.java
│ │ │ │ ├── SingleValueIndexTest.java
│ │ │ │ └── query/
│ │ │ │ └── QueryVisitorTest.java
│ │ │ ├── router/
│ │ │ │ ├── ExtensionCompositeRouterFunctionTest.java
│ │ │ │ ├── ExtensionCreateHandlerTest.java
│ │ │ │ ├── ExtensionDeleteHandlerTest.java
│ │ │ │ ├── ExtensionGetHandlerTest.java
│ │ │ │ ├── ExtensionListHandlerTest.java
│ │ │ │ ├── ExtensionRouterFunctionFactoryTest.java
│ │ │ │ ├── ExtensionUpdateHandlerTest.java
│ │ │ │ └── PathPatternGeneratorTest.java
│ │ │ └── store/
│ │ │ └── ReactiveExtensionStoreClientImplTest.java
│ │ ├── infra/
│ │ │ ├── ConditionListTest.java
│ │ │ ├── DefaultBackupRootGetterTest.java
│ │ │ ├── DefaultExternalLinkProcessorTest.java
│ │ │ ├── DefaultSystemConfigFetcherTest.java
│ │ │ ├── DefaultSystemVersionSupplierTest.java
│ │ │ ├── ExtensionResourceInitializerTest.java
│ │ │ ├── InitializationStateGetterTest.java
│ │ │ ├── ReactiveExtensionPaginatedOperatorImplTest.java
│ │ │ ├── SystemConfigFirstExternalUrlSupplierTest.java
│ │ │ ├── SystemSettingTest.java
│ │ │ ├── SystemStateTest.java
│ │ │ ├── ValidationUtilsTest.java
│ │ │ ├── config/
│ │ │ │ └── SessionConfigurationTest.java
│ │ │ ├── exception/
│ │ │ │ └── handlers/
│ │ │ │ └── I18nExceptionTest.java
│ │ │ ├── properties/
│ │ │ │ └── HaloPropertiesTest.java
│ │ │ └── utils/
│ │ │ ├── Base62UtilsTest.java
│ │ │ ├── FileNameUtilsTest.java
│ │ │ ├── FileTypeDetectUtilsTest.java
│ │ │ ├── FileUtilsTest.java
│ │ │ ├── HaloUtilsTest.java
│ │ │ ├── IpAddressUtilsTest.java
│ │ │ ├── SettingUtilsTest.java
│ │ │ ├── SortUtilsTest.java
│ │ │ ├── SystemConfigUtilsTest.java
│ │ │ ├── VersionUtilsTest.java
│ │ │ └── YamlUnstructuredLoaderTest.java
│ │ ├── migration/
│ │ │ ├── BackupReconcilerTest.java
│ │ │ └── impl/
│ │ │ └── MigrationServiceImplTest.java
│ │ ├── notification/
│ │ │ ├── DefaultNotificationCenterTest.java
│ │ │ ├── DefaultNotificationReasonEmitterTest.java
│ │ │ ├── DefaultNotificationSenderTest.java
│ │ │ ├── DefaultNotificationTemplateRenderTest.java
│ │ │ ├── DefaultNotifierConfigStoreTest.java
│ │ │ ├── DefaultSubscriberEmailResolverTest.java
│ │ │ ├── LanguageUtilsTest.java
│ │ │ ├── NotificationContextTest.java
│ │ │ ├── NotificationTriggerTest.java
│ │ │ ├── ReasonNotificationTemplateSelectorImplTest.java
│ │ │ ├── ReasonPayloadTest.java
│ │ │ ├── RecipientResolverImplTest.java
│ │ │ ├── SubscriptionServiceImplTest.java
│ │ │ ├── UserIdentityTest.java
│ │ │ ├── UserNotificationPreferenceServiceImplTest.java
│ │ │ ├── UserNotificationPreferenceTest.java
│ │ │ └── endpoint/
│ │ │ ├── SubscriptionRouterTest.java
│ │ │ └── UserNotificationPreferencesEndpointTest.java
│ │ ├── plugin/
│ │ │ ├── BuiltInPluginsInitializerTest.java
│ │ │ ├── DefaultDevelopmentPluginRepositoryTest.java
│ │ │ ├── DefaultPluginApplicationContextFactoryTest.java
│ │ │ ├── DefaultPluginRouterFunctionRegistryTest.java
│ │ │ ├── DefaultSettingFetcherTest.java
│ │ │ ├── HaloPluginManagerTest.java
│ │ │ ├── OptionalDependentResolverTest.java
│ │ │ ├── PluginExtensionLoaderUtilsTest.java
│ │ │ ├── PluginRequestMappingHandlerMappingTest.java
│ │ │ ├── PluginServiceImplTest.java
│ │ │ ├── PluginsRootGetterImplTest.java
│ │ │ ├── SharedApplicationContextFactoryTest.java
│ │ │ ├── SharedEventDispatcherTest.java
│ │ │ ├── SpringComponentsFinderTest.java
│ │ │ ├── YamlPluginDescriptorFinderTest.java
│ │ │ ├── YamlPluginFinderTest.java
│ │ │ ├── extensionpoint/
│ │ │ │ └── DefaultExtensionGetterTest.java
│ │ │ └── resources/
│ │ │ ├── BundleResourceUtilsTest.java
│ │ │ ├── ReverseProxyRouterFunctionFactoryTest.java
│ │ │ └── ReverseProxyRouterFunctionRegistryTest.java
│ │ ├── search/
│ │ │ ├── HaloDocumentEventsListenerTest.java
│ │ │ ├── IndexEndpointTest.java
│ │ │ ├── IndicesEndpointTest.java
│ │ │ ├── SearchServiceImplTest.java
│ │ │ ├── lucene/
│ │ │ │ ├── LuceneSearchEngineIntegrationTest.java
│ │ │ │ └── LuceneSearchEngineTest.java
│ │ │ └── post/
│ │ │ ├── PostEventsListenerTest.java
│ │ │ └── PostHaloDocumentsProviderTest.java
│ │ ├── security/
│ │ │ ├── AuthProviderServiceImplTest.java
│ │ │ ├── CsrfSecurityTest.java
│ │ │ ├── DefaultServerAuthenticationEntryPointTest.java
│ │ │ ├── DefaultSuperAdminInitializerTest.java
│ │ │ ├── DefaultUserDetailServiceTest.java
│ │ │ ├── HaloServerRequestCacheTest.java
│ │ │ ├── InitializeRedirectionWebFilterTest.java
│ │ │ ├── ResponseMap.java
│ │ │ ├── authentication/
│ │ │ │ ├── WebExchangeMatchersTest.java
│ │ │ │ ├── impl/
│ │ │ │ │ └── RsaKeyServiceTest.java
│ │ │ │ ├── login/
│ │ │ │ │ ├── LoginAuthenticationConverterTest.java
│ │ │ │ │ └── PublicKeyRouteBuilderTest.java
│ │ │ │ ├── pat/
│ │ │ │ │ └── PatTest.java
│ │ │ │ ├── rememberme/
│ │ │ │ │ ├── PersistentTokenBasedRememberMeServicesTest.java
│ │ │ │ │ ├── RememberTokenCleanerTest.java
│ │ │ │ │ └── TokenBasedRememberMeServicesTest.java
│ │ │ │ └── twofactor/
│ │ │ │ └── TwoFactorAuthSettingsTest.java
│ │ │ ├── authorization/
│ │ │ │ ├── AuthorityUtilsTest.java
│ │ │ │ ├── AuthorizationTest.java
│ │ │ │ ├── DefaultRuleResolverTest.java
│ │ │ │ ├── PolicyRuleTest.java
│ │ │ │ ├── RbacRequestEvaluationTest.java
│ │ │ │ └── RequestInfoResolverTest.java
│ │ │ ├── device/
│ │ │ │ └── DeviceServiceImplTest.java
│ │ │ ├── jackson2/
│ │ │ │ └── HaloSecurityJacksonModuleTest.java
│ │ │ ├── preauth/
│ │ │ │ └── SystemSetupEndpointTest.java
│ │ │ ├── session/
│ │ │ │ └── InMemoryReactiveIndexedSessionRepositoryTest.java
│ │ │ └── switchuser/
│ │ │ ├── SwitchUserConfigurerTest.java
│ │ │ ├── SwitchUserSecurityContextFactory.java
│ │ │ └── WithSwitchUser.java
│ │ ├── theme/
│ │ │ ├── CompositeTemplateResolverTest.java
│ │ │ ├── ReactiveFinderExpressionParserTests.java
│ │ │ ├── SiteSettingVariablesAcquirerTest.java
│ │ │ ├── ThemeContextTest.java
│ │ │ ├── ThemeIntegrationTest.java
│ │ │ ├── ThemeLinkBuilderTest.java
│ │ │ ├── ThemeLocaleContextResolverTest.java
│ │ │ ├── ViewNameResolverTest.java
│ │ │ ├── dialect/
│ │ │ │ ├── CommentElementTagProcessorTest.java
│ │ │ │ ├── CommentEnabledVariableProcessorTest.java
│ │ │ │ ├── ContentTemplateHeadProcessorIntegrationTest.java
│ │ │ │ ├── ContentTemplateHeadProcessorTest.java
│ │ │ │ ├── DuplicateMetaTagProcessorTest.java
│ │ │ │ ├── GeneratorMetaProcessorTest.java
│ │ │ │ ├── HaloPostTemplateHandlerTest.java
│ │ │ │ ├── HaloProcessorDialectTest.java
│ │ │ │ ├── HaloSpringSecurityDialectTest.java
│ │ │ │ ├── InjectionExcluderProcessorTest.java
│ │ │ │ ├── LinkExpressionObjectDialectTest.java
│ │ │ │ └── TemplateFooterElementTagProcessorTest.java
│ │ │ ├── endpoint/
│ │ │ │ └── ThemeEndpointTest.java
│ │ │ ├── engine/
│ │ │ │ ├── DefaultThemeTemplateAvailabilityProviderTest.java
│ │ │ │ └── PluginClassloaderTemplateResolverTest.java
│ │ │ ├── finders/
│ │ │ │ ├── FinderRegistryTest.java
│ │ │ │ ├── impl/
│ │ │ │ │ ├── CategoryFinderImplTest.java
│ │ │ │ │ ├── CommentPublicQueryServiceImplTest.java
│ │ │ │ │ ├── CommentPublicQueryServiceIntegrationTest.java
│ │ │ │ │ ├── MenuFinderImplTest.java
│ │ │ │ │ ├── PluginFinderImplTest.java
│ │ │ │ │ ├── PostFinderImplIntegrationTest.java
│ │ │ │ │ ├── PostFinderImplTest.java
│ │ │ │ │ ├── PostPublicQueryServiceImplTest.java
│ │ │ │ │ ├── SinglePageConversionServiceImplTest.java
│ │ │ │ │ ├── SinglePageFinderImplTest.java
│ │ │ │ │ ├── TagFinderImplTest.java
│ │ │ │ │ └── ThumbnailFinderImplTest.java
│ │ │ │ └── vo/
│ │ │ │ └── UserVoTest.java
│ │ │ ├── message/
│ │ │ │ ├── ThemeMessageResolutionUtilsTest.java
│ │ │ │ └── ThemeMessageResolverIntegrationTest.java
│ │ │ ├── router/
│ │ │ │ ├── EmptyView.java
│ │ │ │ ├── PageUrlUtilsTest.java
│ │ │ │ ├── PreviewRouterFunctionTest.java
│ │ │ │ ├── ReactiveQueryPostPredicateResolverTest.java
│ │ │ │ ├── SinglePageRouteTest.java
│ │ │ │ └── factories/
│ │ │ │ ├── ArchiveRouteFactoryTest.java
│ │ │ │ ├── AuthorPostsRouteFactoryTest.java
│ │ │ │ ├── CategoriesRouteFactoryTest.java
│ │ │ │ ├── IndexRouteFactoryTest.java
│ │ │ │ ├── PostRouteFactoryTest.java
│ │ │ │ ├── RouteFactoryTest.java
│ │ │ │ ├── RouteFactoryTestSuite.java
│ │ │ │ └── TagPostRouteFactoryTest.java
│ │ │ ├── service/
│ │ │ │ └── ThemeServiceImplTest.java
│ │ │ └── utils/
│ │ │ └── PatternUtilsTest.java
│ │ ├── ui/
│ │ │ ├── WebSocketServerWebExchangeMatcherTest.java
│ │ │ └── WebSocketUtilsTest.java
│ │ └── webfilter/
│ │ └── LocaleChangeWebFilterTest.java
│ └── resources/
│ ├── apiToken.salt
│ ├── app.key
│ ├── app.pub
│ ├── application.yaml
│ ├── backups/
│ │ └── backup-for-restoration/
│ │ ├── extensions.data
│ │ └── workdir/
│ │ └── fake-file
│ ├── categories/
│ │ └── independent-post-count.json
│ ├── config/
│ │ └── i18n/
│ │ ├── messages.properties
│ │ └── messages_zh.properties
│ ├── console/
│ │ ├── assets/
│ │ │ └── fake.txt
│ │ └── index.html
│ ├── file-type-detect/
│ │ ├── index.html
│ │ ├── index.js
│ │ ├── other.xlsx
│ │ ├── test.docx
│ │ └── test.json
│ ├── folder-to-zip/
│ │ └── examplefile
│ ├── plugin/
│ │ ├── plugin-0.0.1/
│ │ │ ├── extensions/
│ │ │ │ ├── reverseProxy.yaml
│ │ │ │ ├── roles.yaml
│ │ │ │ ├── setting.yaml
│ │ │ │ └── test.yml
│ │ │ └── plugin.yaml
│ │ ├── plugin-0.0.2/
│ │ │ └── plugin.yaml
│ │ ├── plugin-for-finder/
│ │ │ └── META-INF/
│ │ │ └── plugin-components.idx
│ │ ├── plugin-for-reverseproxy/
│ │ │ └── static/
│ │ │ └── test.txt
│ │ └── plugin.yaml
│ ├── presets/
│ │ └── plugins/
│ │ └── fake-plugin.jar
│ ├── themes/
│ │ ├── default/
│ │ │ ├── i18n/
│ │ │ │ ├── default.properties
│ │ │ │ ├── en.properties
│ │ │ │ └── zh.properties
│ │ │ ├── templates/
│ │ │ │ ├── index.html
│ │ │ │ ├── index.properties
│ │ │ │ ├── index_zh.properties
│ │ │ │ └── timezone.html
│ │ │ └── theme.yaml
│ │ ├── invalid-missing-manifest/
│ │ │ ├── i18n/
│ │ │ │ ├── default.properties
│ │ │ │ └── en.properties
│ │ │ └── templates/
│ │ │ ├── index.html
│ │ │ └── timezone.html
│ │ └── other/
│ │ ├── i18n/
│ │ │ ├── default.properties
│ │ │ └── en.properties
│ │ ├── templates/
│ │ │ └── index.html
│ │ └── theme.yaml
│ └── ui/
│ ├── console.html
│ ├── uc.html
│ └── ui-assets/
│ └── fake.txt
├── buildSrc/
│ ├── build.gradle
│ └── src/
│ └── main/
│ └── groovy/
│ ├── UploadBundleTask.groovy
│ └── halo.publish.gradle
├── config/
│ └── checkstyle/
│ └── checkstyle.xml
├── docs/
│ ├── authentication/
│ │ └── README.md
│ ├── backup-and-restore.md
│ ├── cache/
│ │ └── page.md
│ ├── developer-guide/
│ │ ├── custom-endpoint.md
│ │ └── plugin-configuration-properties.md
│ ├── email-verification/
│ │ └── README.md
│ ├── extension-points/
│ │ ├── authentication.md
│ │ ├── content.md
│ │ └── search-engine.md
│ ├── full-text-search/
│ │ └── README.md
│ ├── index/
│ │ └── README.md
│ ├── notification/
│ │ └── README.md
│ └── plugin/
│ ├── shared-event.md
│ └── websocket.md
├── e2e/
│ ├── Dockerfile
│ ├── Makefile
│ ├── README.md
│ ├── compose-mysql.yaml
│ ├── compose-postgres.yaml
│ ├── compose.yaml
│ ├── start.sh
│ └── testsuite.yaml
├── gradle/
│ ├── libs.versions.toml
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── hack/
│ └── cherry_pick_pull.sh
├── platform/
│ ├── application/
│ │ └── build.gradle
│ └── plugin/
│ └── build.gradle
├── settings.gradle
└── ui/
├── .editorconfig
├── .husky/
│ └── pre-commit
├── .npmrc
├── .oxfmtrc.json
├── Makefile
├── build.gradle
├── console-src/
│ ├── App.vue
│ ├── components/
│ │ └── snapshots/
│ │ ├── BaseSnapshots.vue
│ │ ├── SnapshotContent.vue
│ │ ├── SnapshotDiffContent.vue
│ │ ├── SnapshotListItem.vue
│ │ └── query-keys.ts
│ ├── composables/
│ │ ├── use-content-snapshot.ts
│ │ ├── use-dashboard-stats.ts
│ │ ├── use-entity-extension-points.ts
│ │ ├── use-operation-extension-points.ts
│ │ ├── use-save-keybinding.ts
│ │ └── use-slugify.ts
│ ├── layouts/
│ │ ├── BasicLayout.vue
│ │ └── BlankLayout.vue
│ ├── main.ts
│ ├── modules/
│ │ ├── contents/
│ │ │ ├── attachments/
│ │ │ │ ├── AttachmentList.vue
│ │ │ │ ├── components/
│ │ │ │ │ ├── AttachmentDetailModal.vue
│ │ │ │ │ ├── AttachmentError.vue
│ │ │ │ │ ├── AttachmentGroupBadge.vue
│ │ │ │ │ ├── AttachmentGroupEditingModal.vue
│ │ │ │ │ ├── AttachmentGroupList.vue
│ │ │ │ │ ├── AttachmentListItem.vue
│ │ │ │ │ ├── AttachmentLoading.vue
│ │ │ │ │ ├── AttachmentPoliciesListItem.vue
│ │ │ │ │ ├── AttachmentPoliciesModal.vue
│ │ │ │ │ ├── AttachmentPolicyBadge.vue
│ │ │ │ │ ├── AttachmentPolicyEditingModal.vue
│ │ │ │ │ ├── AttachmentSelectorModal.vue
│ │ │ │ │ ├── AttachmentUploadArea.vue
│ │ │ │ │ ├── AttachmentUploadModal.vue
│ │ │ │ │ ├── DisplayNameEditForm.vue
│ │ │ │ │ ├── UploadFromUrl.vue
│ │ │ │ │ └── selector-providers/
│ │ │ │ │ ├── CoreSelectorProvider.vue
│ │ │ │ │ └── components/
│ │ │ │ │ ├── AttachmentSelectorListItem.vue
│ │ │ │ │ ├── GroupFilter.vue
│ │ │ │ │ └── PolicyFilter.vue
│ │ │ │ ├── composables/
│ │ │ │ │ ├── use-attachment-group.ts
│ │ │ │ │ ├── use-attachment-policy.ts
│ │ │ │ │ └── use-attachment.ts
│ │ │ │ └── module.ts
│ │ │ ├── comments/
│ │ │ │ ├── CommentList.vue
│ │ │ │ ├── components/
│ │ │ │ │ ├── CommentDetailModal.vue
│ │ │ │ │ ├── CommentEditor.vue
│ │ │ │ │ ├── CommentListItem.vue
│ │ │ │ │ ├── DefaultCommentContent.vue
│ │ │ │ │ ├── DefaultCommentEditor.vue
│ │ │ │ │ ├── OwnerButton.vue
│ │ │ │ │ ├── ReplyCreationModal.vue
│ │ │ │ │ ├── ReplyDetailModal.vue
│ │ │ │ │ ├── ReplyListItem.vue
│ │ │ │ │ ├── SubjectQueryCommentList.vue
│ │ │ │ │ └── SubjectQueryCommentListModal.vue
│ │ │ │ ├── composables/
│ │ │ │ │ ├── use-comment-last-readtime-mutate.ts
│ │ │ │ │ ├── use-comments-fetch.ts
│ │ │ │ │ ├── use-content-provider-extension-point.ts
│ │ │ │ │ └── use-subject-ref.ts
│ │ │ │ └── module.ts
│ │ │ ├── pages/
│ │ │ │ ├── DeletedSinglePageList.vue
│ │ │ │ ├── SinglePageEditor.vue
│ │ │ │ ├── SinglePageList.vue
│ │ │ │ ├── SinglePageSnapshots.vue
│ │ │ │ ├── components/
│ │ │ │ │ ├── SinglePageListItem.vue
│ │ │ │ │ ├── SinglePageSettingModal.vue
│ │ │ │ │ └── entity-fields/
│ │ │ │ │ ├── ContributorsField.vue
│ │ │ │ │ ├── CoverField.vue
│ │ │ │ │ ├── PublishStatusField.vue
│ │ │ │ │ ├── PublishTimeField.vue
│ │ │ │ │ ├── TitleField.vue
│ │ │ │ │ └── VisibleField.vue
│ │ │ │ ├── composables/
│ │ │ │ │ └── use-page-update-mutate.ts
│ │ │ │ └── module.ts
│ │ │ └── posts/
│ │ │ ├── DeletedPostList.vue
│ │ │ ├── PostEditor.vue
│ │ │ ├── PostList.vue
│ │ │ ├── PostSnapshots.vue
│ │ │ ├── categories/
│ │ │ │ ├── CategoryList.vue
│ │ │ │ ├── components/
│ │ │ │ │ ├── CategoryEditingModal.vue
│ │ │ │ │ ├── CategoryListItem.vue
│ │ │ │ │ └── __tests__/
│ │ │ │ │ └── CategoryEditingModal.spec.ts
│ │ │ │ ├── composables/
│ │ │ │ │ └── use-post-category.ts
│ │ │ │ └── utils/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.ts
│ │ │ │ └── index.ts
│ │ │ ├── components/
│ │ │ │ ├── PostBatchSettingModal.vue
│ │ │ │ ├── PostListItem.vue
│ │ │ │ ├── PostSettingModal.vue
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── PostSettingModal.spec.ts
│ │ │ │ └── entity-fields/
│ │ │ │ ├── ContributorsField.vue
│ │ │ │ ├── CoverField.vue
│ │ │ │ ├── PublishStatusField.vue
│ │ │ │ ├── PublishTimeField.vue
│ │ │ │ ├── TitleField.vue
│ │ │ │ └── VisibleField.vue
│ │ │ ├── composables/
│ │ │ │ └── use-post-update-mutate.ts
│ │ │ ├── module.ts
│ │ │ └── tags/
│ │ │ ├── TagList.vue
│ │ │ ├── components/
│ │ │ │ ├── PostTag.vue
│ │ │ │ ├── TagEditingModal.vue
│ │ │ │ └── TagListItem.vue
│ │ │ └── composables/
│ │ │ └── use-post-tag.ts
│ │ ├── dashboard/
│ │ │ ├── Dashboard.vue
│ │ │ ├── DashboardDesigner.vue
│ │ │ ├── components/
│ │ │ │ ├── ActionButton.vue
│ │ │ │ ├── WidgetCard.vue
│ │ │ │ ├── WidgetConfigFormModal.vue
│ │ │ │ ├── WidgetEditableItem.vue
│ │ │ │ ├── WidgetHubModal.vue
│ │ │ │ └── WidgetViewItem.vue
│ │ │ ├── composables/
│ │ │ │ ├── use-dashboard-extension-point.ts
│ │ │ │ └── use-dashboard-widgets-fetch.ts
│ │ │ ├── module.ts
│ │ │ ├── styles/
│ │ │ │ └── dashboard.css
│ │ │ └── widgets/
│ │ │ ├── defaults.ts
│ │ │ ├── index.ts
│ │ │ └── presets/
│ │ │ ├── comments/
│ │ │ │ ├── CommentItem.vue
│ │ │ │ ├── CommentStatsWidget.vue
│ │ │ │ └── PendingCommentsWidget.vue
│ │ │ ├── core/
│ │ │ │ ├── iframe/
│ │ │ │ │ └── IframeWidget.vue
│ │ │ │ ├── quick-action/
│ │ │ │ │ ├── QuickActionItem.vue
│ │ │ │ │ ├── QuickActionWidget.vue
│ │ │ │ │ ├── ThemePreviewItem.vue
│ │ │ │ │ └── composables/
│ │ │ │ │ └── use-dashboard-extension-point.ts
│ │ │ │ ├── stack/
│ │ │ │ │ ├── StackWidget.vue
│ │ │ │ │ ├── StackWidgetConfigModal.vue
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── IndexIndicator.vue
│ │ │ │ │ │ ├── WidgetEditableItem.vue
│ │ │ │ │ │ └── WidgetViewItem.vue
│ │ │ │ │ └── types.ts
│ │ │ │ ├── upvotes-stats/
│ │ │ │ │ └── UpvotesStatsWidget.vue
│ │ │ │ └── view-stats/
│ │ │ │ └── ViewsStatsWidget.vue
│ │ │ ├── posts/
│ │ │ │ ├── PostStatsWidget.vue
│ │ │ │ ├── RecentPublishedWidget.vue
│ │ │ │ └── components/
│ │ │ │ └── PostListItem.vue
│ │ │ ├── single-pages/
│ │ │ │ └── SinglePageStatsWidget.vue
│ │ │ └── users/
│ │ │ ├── NotificationWidget.vue
│ │ │ └── UserStatsWidget.vue
│ │ ├── index.ts
│ │ ├── interface/
│ │ │ ├── menus/
│ │ │ │ ├── Menus.vue
│ │ │ │ ├── components/
│ │ │ │ │ ├── MenuEditingModal.vue
│ │ │ │ │ ├── MenuItemEditingModal.vue
│ │ │ │ │ └── MenuList.vue
│ │ │ │ ├── module.ts
│ │ │ │ └── utils/
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── index.spec.ts.snap
│ │ │ │ │ └── index.spec.ts
│ │ │ │ └── index.ts
│ │ │ └── themes/
│ │ │ ├── ThemeDetail.vue
│ │ │ ├── ThemeSetting.vue
│ │ │ ├── components/
│ │ │ │ ├── ThemeListItem.vue
│ │ │ │ ├── ThemeListModal.vue
│ │ │ │ ├── list-tabs/
│ │ │ │ │ ├── InstalledThemes.vue
│ │ │ │ │ ├── LocalUpload.vue
│ │ │ │ │ ├── NotInstalledThemes.vue
│ │ │ │ │ └── RemoteDownload.vue
│ │ │ │ ├── operation/
│ │ │ │ │ ├── MoreOperationItem.vue
│ │ │ │ │ └── UninstallOperationItem.vue
│ │ │ │ └── preview/
│ │ │ │ ├── ThemePreviewListItem.vue
│ │ │ │ └── ThemePreviewModal.vue
│ │ │ ├── composables/
│ │ │ │ └── use-theme.ts
│ │ │ ├── constants/
│ │ │ │ └── index.ts
│ │ │ ├── layouts/
│ │ │ │ └── ThemeLayout.vue
│ │ │ ├── module.ts
│ │ │ └── types/
│ │ │ └── index.ts
│ │ └── system/
│ │ ├── auth-providers/
│ │ │ ├── AuthProviderDetail.vue
│ │ │ ├── AuthProviders.vue
│ │ │ ├── components/
│ │ │ │ ├── AuthProviderListItem.vue
│ │ │ │ └── AuthProvidersSection.vue
│ │ │ └── module.ts
│ │ ├── backup/
│ │ │ ├── Backups.vue
│ │ │ ├── components/
│ │ │ │ └── BackupListItem.vue
│ │ │ ├── composables/
│ │ │ │ └── use-backup.ts
│ │ │ ├── module.ts
│ │ │ └── tabs/
│ │ │ ├── List.vue
│ │ │ └── Restore.vue
│ │ ├── overview/
│ │ │ ├── Overview.vue
│ │ │ ├── components/
│ │ │ │ ├── ExternalUrlForm.vue
│ │ │ │ └── ExternalUrlItem.vue
│ │ │ └── module.ts
│ │ ├── plugins/
│ │ │ ├── PluginDetail.vue
│ │ │ ├── PluginExtensionPointSettings.vue
│ │ │ ├── PluginList.vue
│ │ │ ├── components/
│ │ │ │ ├── PluginConditionsModal.vue
│ │ │ │ ├── PluginDetailModal.vue
│ │ │ │ ├── PluginInstallationModal.vue
│ │ │ │ ├── PluginListItem.vue
│ │ │ │ ├── entity-fields/
│ │ │ │ │ ├── AuthorField.vue
│ │ │ │ │ ├── LogoField.vue
│ │ │ │ │ ├── ReloadField.vue
│ │ │ │ │ ├── SwitchField.vue
│ │ │ │ │ └── TitleField.vue
│ │ │ │ ├── extension-points/
│ │ │ │ │ ├── ExtensionDefinitionListItem.vue
│ │ │ │ │ ├── ExtensionDefinitionMultiInstanceView.vue
│ │ │ │ │ └── ExtensionDefinitionSingletonView.vue
│ │ │ │ ├── installation-tabs/
│ │ │ │ │ ├── LocalUpload.vue
│ │ │ │ │ └── RemoteDownload.vue
│ │ │ │ └── tabs/
│ │ │ │ ├── Detail.vue
│ │ │ │ └── Setting.vue
│ │ │ ├── composables/
│ │ │ │ ├── use-extension-definition-fetch.ts
│ │ │ │ └── use-plugin.ts
│ │ │ ├── constants/
│ │ │ │ └── index.ts
│ │ │ ├── module.ts
│ │ │ └── types/
│ │ │ └── index.ts
│ │ ├── roles/
│ │ │ ├── RoleDetail.vue
│ │ │ ├── RoleList.vue
│ │ │ ├── components/
│ │ │ │ └── RoleEditingModal.vue
│ │ │ └── module.ts
│ │ ├── settings/
│ │ │ ├── SystemSettings.vue
│ │ │ ├── module.ts
│ │ │ └── tabs/
│ │ │ ├── NotificationSetting.vue
│ │ │ ├── Notifications.vue
│ │ │ └── Setting.vue
│ │ ├── tools/
│ │ │ ├── Tools.vue
│ │ │ └── module.ts
│ │ └── users/
│ │ ├── UserDetail.vue
│ │ ├── UserList.vue
│ │ ├── components/
│ │ │ ├── GrantPermissionModal.vue
│ │ │ ├── RolesView.vue
│ │ │ ├── UserCreationModal.vue
│ │ │ ├── UserEditingModal.vue
│ │ │ ├── UserListItem.vue
│ │ │ └── UserPasswordChangeModal.vue
│ │ ├── composables/
│ │ │ ├── use-role.ts
│ │ │ └── use-user.ts
│ │ ├── module.ts
│ │ └── tabs/
│ │ └── Detail.vue
│ ├── router/
│ │ ├── constant.ts
│ │ ├── guards/
│ │ │ ├── auth-check.ts
│ │ │ └── permission.ts
│ │ ├── index.ts
│ │ └── routes.config.ts
│ └── stores/
│ └── theme.ts
├── console.html
├── docs/
│ ├── components/
│ │ └── README.md
│ ├── custom-formkit-input/
│ │ └── README.md
│ ├── extension-points/
│ │ ├── backup.md
│ │ ├── comment-content.md
│ │ ├── comment-editor.md
│ │ ├── comment-subject-ref.md
│ │ ├── dashboard.md
│ │ ├── default-editor–extension.md
│ │ ├── editor.md
│ │ ├── entity-listitem-field.md
│ │ ├── entity-listitem-operation.md
│ │ ├── plugin-installation-tabs.md
│ │ ├── plugin-self-tabs.md
│ │ └── theme-list-tabs.md
│ ├── project-structure/
│ │ └── README.md
│ └── routes-generation/
│ └── README.md
├── env.d.ts
├── eslint.config.ts
├── package.json
├── packages/
│ ├── api-client/
│ │ ├── .openapi_config.yaml
│ │ ├── README.md
│ │ ├── entry/
│ │ │ ├── api-client.ts
│ │ │ ├── index.ts
│ │ │ └── utils/
│ │ │ ├── index.ts
│ │ │ └── paginate.ts
│ │ ├── openapitools.json
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── .gitignore
│ │ │ ├── .npmignore
│ │ │ ├── .openapi-generator/
│ │ │ │ ├── FILES
│ │ │ │ └── VERSION
│ │ │ ├── .openapi-generator-ignore
│ │ │ ├── api/
│ │ │ │ ├── annotation-setting-v1-alpha-uc-api.ts
│ │ │ │ ├── annotation-setting-v1alpha1-api.ts
│ │ │ │ ├── attachment-v1alpha1-api.ts
│ │ │ │ ├── attachment-v1alpha1-console-api.ts
│ │ │ │ ├── attachment-v1alpha1-uc-api.ts
│ │ │ │ ├── auth-provider-v1alpha1-api.ts
│ │ │ │ ├── auth-provider-v1alpha1-console-api.ts
│ │ │ │ ├── backup-v1alpha1-api.ts
│ │ │ │ ├── category-v1alpha1-api.ts
│ │ │ │ ├── category-v1alpha1-public-api.ts
│ │ │ │ ├── comment-v1alpha1-api.ts
│ │ │ │ ├── comment-v1alpha1-console-api.ts
│ │ │ │ ├── comment-v1alpha1-public-api.ts
│ │ │ │ ├── config-map-v1alpha1-api.ts
│ │ │ │ ├── counter-v1alpha1-api.ts
│ │ │ │ ├── device-v1alpha1-api.ts
│ │ │ │ ├── device-v1alpha1-uc-api.ts
│ │ │ │ ├── extension-definition-v1alpha1-api.ts
│ │ │ │ ├── extension-point-definition-v1alpha1-api.ts
│ │ │ │ ├── group-v1alpha1-api.ts
│ │ │ │ ├── index-v1alpha1-public-api.ts
│ │ │ │ ├── indices-v1alpha1-console-api.ts
│ │ │ │ ├── local-thumbnail-v1alpha1-api.ts
│ │ │ │ ├── menu-item-v1alpha1-api.ts
│ │ │ │ ├── menu-v1alpha1-api.ts
│ │ │ │ ├── menu-v1alpha1-public-api.ts
│ │ │ │ ├── metrics-v1alpha1-public-api.ts
│ │ │ │ ├── migration-v1alpha1-console-api.ts
│ │ │ │ ├── notification-template-v1alpha1-api.ts
│ │ │ │ ├── notification-v1alpha1-api.ts
│ │ │ │ ├── notification-v1alpha1-public-api.ts
│ │ │ │ ├── notification-v1alpha1-uc-api.ts
│ │ │ │ ├── notifier-descriptor-v1alpha1-api.ts
│ │ │ │ ├── notifier-v1alpha1-console-api.ts
│ │ │ │ ├── notifier-v1alpha1-uc-api.ts
│ │ │ │ ├── personal-access-token-v1alpha1-api.ts
│ │ │ │ ├── personal-access-token-v1alpha1-uc-api.ts
│ │ │ │ ├── plugin-v1alpha1-api.ts
│ │ │ │ ├── plugin-v1alpha1-console-api.ts
│ │ │ │ ├── plugin-v1alpha1-public-api.ts
│ │ │ │ ├── policy-alpha1-console-api.ts
│ │ │ │ ├── policy-template-v1alpha1-api.ts
│ │ │ │ ├── policy-v1alpha1-api.ts
│ │ │ │ ├── post-v1alpha1-api.ts
│ │ │ │ ├── post-v1alpha1-console-api.ts
│ │ │ │ ├── post-v1alpha1-public-api.ts
│ │ │ │ ├── post-v1alpha1-uc-api.ts
│ │ │ │ ├── reason-type-v1alpha1-api.ts
│ │ │ │ ├── reason-v1alpha1-api.ts
│ │ │ │ ├── remember-me-token-v1alpha1-api.ts
│ │ │ │ ├── reply-v1alpha1-api.ts
│ │ │ │ ├── reply-v1alpha1-console-api.ts
│ │ │ │ ├── reverse-proxy-v1alpha1-api.ts
│ │ │ │ ├── role-binding-v1alpha1-api.ts
│ │ │ │ ├── role-v1alpha1-api.ts
│ │ │ │ ├── secret-v1alpha1-api.ts
│ │ │ │ ├── setting-v1alpha1-api.ts
│ │ │ │ ├── single-page-v1alpha1-api.ts
│ │ │ │ ├── single-page-v1alpha1-console-api.ts
│ │ │ │ ├── single-page-v1alpha1-public-api.ts
│ │ │ │ ├── snapshot-v1alpha1-api.ts
│ │ │ │ ├── snapshot-v1alpha1-uc-api.ts
│ │ │ │ ├── subscription-v1alpha1-api.ts
│ │ │ │ ├── system-config-v1alpha1-console-api.ts
│ │ │ │ ├── system-v1alpha1-console-api.ts
│ │ │ │ ├── system-v1alpha1-public-api.ts
│ │ │ │ ├── tag-v1alpha1-api.ts
│ │ │ │ ├── tag-v1alpha1-console-api.ts
│ │ │ │ ├── tag-v1alpha1-public-api.ts
│ │ │ │ ├── theme-v1alpha1-api.ts
│ │ │ │ ├── theme-v1alpha1-console-api.ts
│ │ │ │ ├── thumbnail-v1alpha1-api.ts
│ │ │ │ ├── thumbnail-v1alpha1-public-api.ts
│ │ │ │ ├── two-factor-auth-v1alpha1-uc-api.ts
│ │ │ │ ├── user-connection-v1alpha1-api.ts
│ │ │ │ ├── user-connection-v1alpha1-uc-api.ts
│ │ │ │ ├── user-preference-v1alpha1-uc-api.ts
│ │ │ │ ├── user-v1alpha1-api.ts
│ │ │ │ └── user-v1alpha1-console-api.ts
│ │ │ ├── api.ts
│ │ │ ├── base.ts
│ │ │ ├── common.ts
│ │ │ ├── configuration.ts
│ │ │ ├── git_push.sh
│ │ │ ├── index.ts
│ │ │ └── models/
│ │ │ ├── add-operation.ts
│ │ │ ├── annotation-setting-list.ts
│ │ │ ├── annotation-setting-spec.ts
│ │ │ ├── annotation-setting.ts
│ │ │ ├── attachment-list.ts
│ │ │ ├── attachment-spec.ts
│ │ │ ├── attachment-status.ts
│ │ │ ├── attachment.ts
│ │ │ ├── auth-provider-list.ts
│ │ │ ├── auth-provider-spec.ts
│ │ │ ├── auth-provider.ts
│ │ │ ├── author.ts
│ │ │ ├── backup-file.ts
│ │ │ ├── backup-list.ts
│ │ │ ├── backup-spec.ts
│ │ │ ├── backup-status.ts
│ │ │ ├── backup.ts
│ │ │ ├── category-list.ts
│ │ │ ├── category-spec.ts
│ │ │ ├── category-status.ts
│ │ │ ├── category-vo-list.ts
│ │ │ ├── category-vo.ts
│ │ │ ├── category.ts
│ │ │ ├── change-own-password-request.ts
│ │ │ ├── change-password-request.ts
│ │ │ ├── comment-email-owner.ts
│ │ │ ├── comment-list.ts
│ │ │ ├── comment-owner.ts
│ │ │ ├── comment-request.ts
│ │ │ ├── comment-spec.ts
│ │ │ ├── comment-stats-vo.ts
│ │ │ ├── comment-stats.ts
│ │ │ ├── comment-status.ts
│ │ │ ├── comment-vo-list.ts
│ │ │ ├── comment-vo.ts
│ │ │ ├── comment-with-reply-vo-list.ts
│ │ │ ├── comment-with-reply-vo.ts
│ │ │ ├── comment.ts
│ │ │ ├── condition.ts
│ │ │ ├── config-map-list.ts
│ │ │ ├── config-map-ref.ts
│ │ │ ├── config-map.ts
│ │ │ ├── content-update-param.ts
│ │ │ ├── content-vo.ts
│ │ │ ├── content-wrapper.ts
│ │ │ ├── content.ts
│ │ │ ├── contributor-vo.ts
│ │ │ ├── contributor.ts
│ │ │ ├── copy-operation.ts
│ │ │ ├── counter-list.ts
│ │ │ ├── counter-request.ts
│ │ │ ├── counter.ts
│ │ │ ├── create-user-request.ts
│ │ │ ├── custom-templates.ts
│ │ │ ├── dashboard-stats.ts
│ │ │ ├── detailed-user.ts
│ │ │ ├── device-list.ts
│ │ │ ├── device-spec.ts
│ │ │ ├── device-status.ts
│ │ │ ├── device.ts
│ │ │ ├── email-config-validation-request.ts
│ │ │ ├── email-verify-request.ts
│ │ │ ├── excerpt.ts
│ │ │ ├── extension-definition-list.ts
│ │ │ ├── extension-definition.ts
│ │ │ ├── extension-point-definition-list.ts
│ │ │ ├── extension-point-definition.ts
│ │ │ ├── extension-point-spec.ts
│ │ │ ├── extension-spec.ts
│ │ │ ├── extension.ts
│ │ │ ├── file-reverse-proxy-provider.ts
│ │ │ ├── grant-request.ts
│ │ │ ├── group-kind.ts
│ │ │ ├── group-list.ts
│ │ │ ├── group-spec.ts
│ │ │ ├── group-status.ts
│ │ │ ├── group.ts
│ │ │ ├── halo-document.ts
│ │ │ ├── index.ts
│ │ │ ├── install-from-uri-request.ts
│ │ │ ├── interest-reason-subject.ts
│ │ │ ├── interest-reason.ts
│ │ │ ├── json-patch-inner.ts
│ │ │ ├── license.ts
│ │ │ ├── list-result-reply-vo.ts
│ │ │ ├── listed-auth-provider.ts
│ │ │ ├── listed-comment-list.ts
│ │ │ ├── listed-comment.ts
│ │ │ ├── listed-post-list.ts
│ │ │ ├── listed-post-vo-list.ts
│ │ │ ├── listed-post-vo.ts
│ │ │ ├── listed-post.ts
│ │ │ ├── listed-reply-list.ts
│ │ │ ├── listed-reply.ts
│ │ │ ├── listed-single-page-list.ts
│ │ │ ├── listed-single-page-vo-list.ts
│ │ │ ├── listed-single-page-vo.ts
│ │ │ ├── listed-single-page.ts
│ │ │ ├── listed-snapshot-dto.ts
│ │ │ ├── listed-snapshot-spec.ts
│ │ │ ├── listed-user.ts
│ │ │ ├── local-thumbnail-list.ts
│ │ │ ├── local-thumbnail-spec.ts
│ │ │ ├── local-thumbnail-status.ts
│ │ │ ├── local-thumbnail.ts
│ │ │ ├── mark-specified-request.ts
│ │ │ ├── menu-item-list.ts
│ │ │ ├── menu-item-spec.ts
│ │ │ ├── menu-item-status.ts
│ │ │ ├── menu-item-vo.ts
│ │ │ ├── menu-item.ts
│ │ │ ├── menu-list.ts
│ │ │ ├── menu-spec.ts
│ │ │ ├── menu-vo.ts
│ │ │ ├── menu.ts
│ │ │ ├── metadata.ts
│ │ │ ├── move-operation.ts
│ │ │ ├── navigation-post-vo.ts
│ │ │ ├── notification-list.ts
│ │ │ ├── notification-spec.ts
│ │ │ ├── notification-template-list.ts
│ │ │ ├── notification-template-spec.ts
│ │ │ ├── notification-template.ts
│ │ │ ├── notification.ts
│ │ │ ├── notifier-descriptor-list.ts
│ │ │ ├── notifier-descriptor-spec.ts
│ │ │ ├── notifier-descriptor.ts
│ │ │ ├── notifier-info.ts
│ │ │ ├── notifier-setting-ref.ts
│ │ │ ├── owner-info.ts
│ │ │ ├── password-request.ts
│ │ │ ├── pat-spec.ts
│ │ │ ├── personal-access-token-list.ts
│ │ │ ├── personal-access-token.ts
│ │ │ ├── plugin-author.ts
│ │ │ ├── plugin-list.ts
│ │ │ ├── plugin-running-state-request.ts
│ │ │ ├── plugin-spec.ts
│ │ │ ├── plugin-status.ts
│ │ │ ├── plugin.ts
│ │ │ ├── policy-list.ts
│ │ │ ├── policy-rule.ts
│ │ │ ├── policy-spec.ts
│ │ │ ├── policy-template-list.ts
│ │ │ ├── policy-template-spec.ts
│ │ │ ├── policy-template.ts
│ │ │ ├── policy.ts
│ │ │ ├── post-list.ts
│ │ │ ├── post-request.ts
│ │ │ ├── post-spec.ts
│ │ │ ├── post-status.ts
│ │ │ ├── post-vo.ts
│ │ │ ├── post.ts
│ │ │ ├── reason-attributes.ts
│ │ │ ├── reason-list.ts
│ │ │ ├── reason-property.ts
│ │ │ ├── reason-selector.ts
│ │ │ ├── reason-spec.ts
│ │ │ ├── reason-subject.ts
│ │ │ ├── reason-type-info.ts
│ │ │ ├── reason-type-list.ts
│ │ │ ├── reason-type-notifier-collection-request.ts
│ │ │ ├── reason-type-notifier-matrix.ts
│ │ │ ├── reason-type-notifier-request.ts
│ │ │ ├── reason-type-spec.ts
│ │ │ ├── reason-type.ts
│ │ │ ├── reason.ts
│ │ │ ├── ref.ts
│ │ │ ├── remember-me-token-list.ts
│ │ │ ├── remember-me-token-spec.ts
│ │ │ ├── remember-me-token.ts
│ │ │ ├── remove-operation.ts
│ │ │ ├── replace-operation.ts
│ │ │ ├── reply-list.ts
│ │ │ ├── reply-request.ts
│ │ │ ├── reply-spec.ts
│ │ │ ├── reply-status.ts
│ │ │ ├── reply-vo-list.ts
│ │ │ ├── reply-vo.ts
│ │ │ ├── reply.ts
│ │ │ ├── reverse-proxy-list.ts
│ │ │ ├── reverse-proxy-rule.ts
│ │ │ ├── reverse-proxy.ts
│ │ │ ├── revert-snapshot-for-post-param.ts
│ │ │ ├── revert-snapshot-for-single-param.ts
│ │ │ ├── role-binding-list.ts
│ │ │ ├── role-binding.ts
│ │ │ ├── role-list.ts
│ │ │ ├── role-ref.ts
│ │ │ ├── role.ts
│ │ │ ├── search-option.ts
│ │ │ ├── search-result.ts
│ │ │ ├── secret-list.ts
│ │ │ ├── secret.ts
│ │ │ ├── setting-form.ts
│ │ │ ├── setting-list.ts
│ │ │ ├── setting-ref.ts
│ │ │ ├── setting-spec.ts
│ │ │ ├── setting.ts
│ │ │ ├── setup-request.ts
│ │ │ ├── single-page-list.ts
│ │ │ ├── single-page-request.ts
│ │ │ ├── single-page-spec.ts
│ │ │ ├── single-page-status.ts
│ │ │ ├── single-page-vo.ts
│ │ │ ├── single-page.ts
│ │ │ ├── site-stats-vo.ts
│ │ │ ├── snap-shot-spec.ts
│ │ │ ├── snapshot-list.ts
│ │ │ ├── snapshot.ts
│ │ │ ├── stats-vo.ts
│ │ │ ├── stats.ts
│ │ │ ├── subject.ts
│ │ │ ├── subscription-list.ts
│ │ │ ├── subscription-spec.ts
│ │ │ ├── subscription-subscriber.ts
│ │ │ ├── subscription.ts
│ │ │ ├── tag-list.ts
│ │ │ ├── tag-spec.ts
│ │ │ ├── tag-status.ts
│ │ │ ├── tag-vo-list.ts
│ │ │ ├── tag-vo.ts
│ │ │ ├── tag.ts
│ │ │ ├── template-content.ts
│ │ │ ├── template-descriptor.ts
│ │ │ ├── test-operation.ts
│ │ │ ├── theme-list.ts
│ │ │ ├── theme-spec.ts
│ │ │ ├── theme-status.ts
│ │ │ ├── theme.ts
│ │ │ ├── thumbnail-list.ts
│ │ │ ├── thumbnail-spec.ts
│ │ │ ├── thumbnail.ts
│ │ │ ├── totp-auth-link-response.ts
│ │ │ ├── totp-request.ts
│ │ │ ├── two-factor-auth-settings.ts
│ │ │ ├── uc-upload-from-url-request.ts
│ │ │ ├── upgrade-from-uri-request.ts
│ │ │ ├── upload-from-url-request.ts
│ │ │ ├── user-connection-list.ts
│ │ │ ├── user-connection-spec.ts
│ │ │ ├── user-connection.ts
│ │ │ ├── user-device.ts
│ │ │ ├── user-endpoint-listed-user-list.ts
│ │ │ ├── user-list.ts
│ │ │ ├── user-permission.ts
│ │ │ ├── user-spec.ts
│ │ │ ├── user-status.ts
│ │ │ ├── user.ts
│ │ │ ├── verify-code-request.ts
│ │ │ └── vote-request.ts
│ │ ├── tsconfig.json
│ │ └── tsdown.config.ts
│ ├── components/
│ │ ├── .storybook/
│ │ │ ├── main.ts
│ │ │ └── preview.ts
│ │ ├── env.d.ts
│ │ ├── package.json
│ │ ├── postcss.config.cjs
│ │ ├── src/
│ │ │ ├── components/
│ │ │ │ ├── alert/
│ │ │ │ │ ├── Alert.stories.ts
│ │ │ │ │ ├── Alert.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── Alert.spec.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── avatar/
│ │ │ │ │ ├── Avatar.stories.ts
│ │ │ │ │ ├── Avatar.vue
│ │ │ │ │ ├── AvatarGroup.stories.ts
│ │ │ │ │ ├── AvatarGroup.vue
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── button/
│ │ │ │ │ ├── Button.stories.ts
│ │ │ │ │ ├── Button.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── Button.spec.ts
│ │ │ │ │ │ └── __snapshots__/
│ │ │ │ │ │ └── Button.spec.ts.snap
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── card/
│ │ │ │ │ ├── Card.stories.ts
│ │ │ │ │ ├── Card.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── Card.spec.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── description/
│ │ │ │ │ ├── Description.vue
│ │ │ │ │ ├── DescriptionItem.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── dialog/
│ │ │ │ │ ├── Dialog.stories.ts
│ │ │ │ │ ├── Dialog.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── Dialog.spec.ts
│ │ │ │ │ ├── dialog-manager.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── dropdown/
│ │ │ │ │ ├── Draopdown.stories.ts
│ │ │ │ │ ├── DropdownDivider.vue
│ │ │ │ │ ├── DropdownItem.vue
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── style.scss
│ │ │ │ ├── empty/
│ │ │ │ │ ├── Empty.stories.ts
│ │ │ │ │ ├── Empty.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── Empty.spec.ts
│ │ │ │ │ │ └── __snapshots__/
│ │ │ │ │ │ └── Empty.spec.ts.snap
│ │ │ │ │ └── index.ts
│ │ │ │ ├── entity/
│ │ │ │ │ ├── Entity.vue
│ │ │ │ │ ├── EntityContainer.vue
│ │ │ │ │ ├── EntityField.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── Entity.spec.ts
│ │ │ │ │ │ └── EntityField.spec.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── header/
│ │ │ │ │ ├── PageHeader.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── loading/
│ │ │ │ │ ├── Loading.stories.ts
│ │ │ │ │ ├── Loading.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── menu/
│ │ │ │ │ ├── Menu.stories.ts
│ │ │ │ │ ├── Menu.vue
│ │ │ │ │ ├── MenuItem.vue
│ │ │ │ │ ├── MenuLabel.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── Menu.spec.tsx
│ │ │ │ │ │ ├── MenuLabel.spec.ts
│ │ │ │ │ │ └── __snapshots__/
│ │ │ │ │ │ ├── Menu.spec.tsx.snap
│ │ │ │ │ │ └── MenuLabel.spec.ts.snap
│ │ │ │ │ └── index.ts
│ │ │ │ ├── modal/
│ │ │ │ │ ├── Modal.stories.ts
│ │ │ │ │ ├── Modal.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── Modal.spec.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── pagination/
│ │ │ │ │ ├── Pagination.stories.ts
│ │ │ │ │ ├── Pagination.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── Pagination.spec.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── space/
│ │ │ │ │ ├── Space.stories.ts
│ │ │ │ │ ├── Space.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── Space.spec.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── status/
│ │ │ │ │ ├── StatusDot.stories.ts
│ │ │ │ │ ├── StatusDot.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── StatusDot.spec.ts
│ │ │ │ │ │ └── __snapshots__/
│ │ │ │ │ │ └── StatusDot.spec.ts.snap
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── switch/
│ │ │ │ │ ├── Switch.stories.ts
│ │ │ │ │ ├── Switch.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── Switch.spec.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── tabs/
│ │ │ │ │ ├── TabItem.vue
│ │ │ │ │ ├── Tabbar.stories.ts
│ │ │ │ │ ├── Tabbar.vue
│ │ │ │ │ ├── Tabs.stories.ts
│ │ │ │ │ ├── Tabs.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── TabItem.spec.ts
│ │ │ │ │ │ ├── Tabbar.spec.ts
│ │ │ │ │ │ └── Tabs.spec.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── tag/
│ │ │ │ │ ├── Tag.stories.ts
│ │ │ │ │ ├── Tag.story.vue
│ │ │ │ │ ├── Tag.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── Tag.spec.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── toast/
│ │ │ │ │ ├── Toast.story.vue
│ │ │ │ │ ├── Toast.vue
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── toast-manager.ts
│ │ │ │ │ └── types.ts
│ │ │ │ └── tooltip/
│ │ │ │ ├── index.ts
│ │ │ │ └── style.css
│ │ │ ├── components.ts
│ │ │ ├── icons/
│ │ │ │ └── icons.ts
│ │ │ ├── index.ts
│ │ │ ├── stories/
│ │ │ │ └── Introduction.mdx
│ │ │ └── styles/
│ │ │ └── tailwind.css
│ │ ├── tailwind.config.ts
│ │ ├── tsconfig.app.json
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ ├── tsconfig.vitest.json
│ │ └── vite.config.ts
│ ├── console-shared/
│ │ ├── README.md
│ │ ├── index.js
│ │ └── package.json
│ ├── editor/
│ │ ├── README.md
│ │ ├── docs/
│ │ │ └── extension.md
│ │ ├── env.d.ts
│ │ ├── package.json
│ │ ├── postcss.config.cjs
│ │ ├── src/
│ │ │ ├── components/
│ │ │ │ ├── Editor.vue
│ │ │ │ ├── EditorHeader.vue
│ │ │ │ ├── base/
│ │ │ │ │ ├── DropdownItem.vue
│ │ │ │ │ ├── Input.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── block/
│ │ │ │ │ ├── BlockActionButton.vue
│ │ │ │ │ ├── BlockActionHorizontalSeparator.vue
│ │ │ │ │ ├── BlockActionSeparator.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── bubble/
│ │ │ │ │ ├── BubbleButton.vue
│ │ │ │ │ ├── BubbleItem.vue
│ │ │ │ │ ├── EditorBubbleMenu.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── common/
│ │ │ │ │ └── ColorPickerDropdown.vue
│ │ │ │ ├── drag/
│ │ │ │ │ ├── EditorDragButtonItem.vue
│ │ │ │ │ ├── EditorDragHandle.vue
│ │ │ │ │ ├── EditorDragMenu.vue
│ │ │ │ │ ├── default-drag.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── icon/
│ │ │ │ │ └── MingcuteDelete2Line.vue
│ │ │ │ ├── index.ts
│ │ │ │ ├── toolbar/
│ │ │ │ │ ├── ToolbarItem.vue
│ │ │ │ │ ├── ToolbarSubItem.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── toolbox/
│ │ │ │ │ ├── ToolboxItem.vue
│ │ │ │ │ └── index.ts
│ │ │ │ └── upload/
│ │ │ │ ├── EditorLinkObtain.vue
│ │ │ │ ├── ResourceReplaceButton.vue
│ │ │ │ └── index.ts
│ │ │ ├── composables/
│ │ │ │ └── use-attachment.ts
│ │ │ ├── extensions/
│ │ │ │ ├── align/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── audio/
│ │ │ │ │ ├── AudioView.vue
│ │ │ │ │ ├── BubbleItemAudioLink.vue
│ │ │ │ │ ├── BubbleItemAudioPosition.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── block-position/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── blockquote/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── bold/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── bullet-list/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── character-count/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── clear-format/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── code/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── code-block/
│ │ │ │ │ ├── CodeBlockSelect.vue
│ │ │ │ │ ├── CodeBlockViewRenderer.vue
│ │ │ │ │ ├── code-block.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── color/
│ │ │ │ │ ├── ColorBubbleItem.vue
│ │ │ │ │ ├── ColorToolbarItem.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── columns/
│ │ │ │ │ ├── column.ts
│ │ │ │ │ ├── columns.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── commands-menu/
│ │ │ │ │ ├── CommandsView.vue
│ │ │ │ │ ├── commands.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── details/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── document/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── drop-cursor/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── extensions-kit.ts
│ │ │ │ ├── figure/
│ │ │ │ │ ├── FigureCaptionView.vue
│ │ │ │ │ ├── figure-caption.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── font-size/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── format-brush/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── util.ts
│ │ │ │ ├── gallery/
│ │ │ │ │ ├── BubbleItemAddImage.vue
│ │ │ │ │ ├── BubbleItemGap.vue
│ │ │ │ │ ├── BubbleItemGroupSize.vue
│ │ │ │ │ ├── BubbleItemLayout.vue
│ │ │ │ │ ├── GalleryView.vue
│ │ │ │ │ ├── gallery-bubble.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── useGalleryImages.ts
│ │ │ │ ├── gap-cursor/
│ │ │ │ │ ├── gap-cursor-selection.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── hard-break/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── heading/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── highlight/
│ │ │ │ │ ├── HighlightBubbleItem.vue
│ │ │ │ │ ├── HighlightToolbarItem.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── history/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── horizontal-rule/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── iframe/
│ │ │ │ │ ├── BubbleItemIframeAlign.vue
│ │ │ │ │ ├── BubbleItemIframeLink.vue
│ │ │ │ │ ├── BubbleItemIframeSize.vue
│ │ │ │ │ ├── IframeView.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── image/
│ │ │ │ │ ├── BubbleItemImageAlt.vue
│ │ │ │ │ ├── BubbleItemImageHref.vue
│ │ │ │ │ ├── BubbleItemImageLink.vue
│ │ │ │ │ ├── BubbleItemImagePosition.vue
│ │ │ │ │ ├── BubbleItemImageSize.vue
│ │ │ │ │ ├── ImageView.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── indent/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── italic/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── link/
│ │ │ │ │ ├── LinkBubbleButton.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── list-extra/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── list-keymap/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── node-selected/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── ordered-list/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── paragraph/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── placeholder/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── range-selection/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── range-selection.ts
│ │ │ │ ├── search-and-replace/
│ │ │ │ │ ├── IconButton.vue
│ │ │ │ │ ├── MatchToggleButton.vue
│ │ │ │ │ ├── SearchAndReplace.vue
│ │ │ │ │ ├── SearchAndReplacePlugin.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── smart-scroll/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── strike/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── subscript/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── superscript/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── table/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── table-cell.ts
│ │ │ │ │ ├── table-header.ts
│ │ │ │ │ ├── table-row.ts
│ │ │ │ │ └── util.ts
│ │ │ │ ├── task-list/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── text/
│ │ │ │ │ ├── BubbleItemTextType.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── text-align/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── text-style/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── trailing-node/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── underline/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── upload/
│ │ │ │ │ └── index.ts
│ │ │ │ └── video/
│ │ │ │ ├── BubbleItemVideoLink.vue
│ │ │ │ ├── BubbleItemVideoPosition.vue
│ │ │ │ ├── BubbleItemVideoSize.vue
│ │ │ │ ├── VideoView.vue
│ │ │ │ └── index.ts
│ │ │ ├── index.ts
│ │ │ ├── locales/
│ │ │ │ ├── en.json
│ │ │ │ ├── es.json
│ │ │ │ ├── index.ts
│ │ │ │ └── zh-CN.json
│ │ │ ├── styles/
│ │ │ │ ├── base.scss
│ │ │ │ ├── columns.scss
│ │ │ │ ├── details.scss
│ │ │ │ ├── draggable.scss
│ │ │ │ ├── figure.scss
│ │ │ │ ├── format-brush.scss
│ │ │ │ ├── gap-cursor.scss
│ │ │ │ ├── index.scss
│ │ │ │ ├── node-select.scss
│ │ │ │ ├── range-selection.scss
│ │ │ │ ├── resizer.scss
│ │ │ │ ├── search.scss
│ │ │ │ ├── table.scss
│ │ │ │ └── tailwind.css
│ │ │ ├── tiptap/
│ │ │ │ ├── core/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── pm/
│ │ │ │ │ └── index.ts
│ │ │ │ └── vue-3/
│ │ │ │ └── index.ts
│ │ │ ├── types/
│ │ │ │ └── index.ts
│ │ │ └── utils/
│ │ │ ├── anchor.ts
│ │ │ ├── attachment.ts
│ │ │ ├── clipboard.ts
│ │ │ ├── delete-node.ts
│ │ │ ├── filter-duplicate-extensions.ts
│ │ │ ├── index.ts
│ │ │ ├── is-allowed-uri.ts
│ │ │ ├── is-list-active.ts
│ │ │ ├── is-node-empty.ts
│ │ │ ├── keyboard.ts
│ │ │ └── upload.ts
│ │ ├── tailwind.config.ts
│ │ ├── tsconfig.app.json
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ ├── tsconfig.vitest.json
│ │ └── vite.config.ts
│ ├── shared/
│ │ ├── env.d.ts
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── events/
│ │ │ │ └── index.ts
│ │ │ ├── index.ts
│ │ │ ├── plugin/
│ │ │ │ ├── index.ts
│ │ │ │ └── types/
│ │ │ │ ├── attachment-selector.ts
│ │ │ │ ├── backup.ts
│ │ │ │ ├── comment.ts
│ │ │ │ ├── dashboard-widget.ts
│ │ │ │ ├── editor-provider.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── list-entity-field.ts
│ │ │ │ ├── list-operation.ts
│ │ │ │ ├── plugin-installation-tab.ts
│ │ │ │ ├── plugin-tab.ts
│ │ │ │ ├── theme-list-tab.ts
│ │ │ │ ├── ui-plugin-entry.ts
│ │ │ │ ├── ui-plugin-module.ts
│ │ │ │ └── user-tab.ts
│ │ │ ├── stores/
│ │ │ │ ├── index.ts
│ │ │ │ └── types/
│ │ │ │ ├── actuator.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── slug.ts
│ │ │ ├── types/
│ │ │ │ ├── index.ts
│ │ │ │ └── menus.ts
│ │ │ └── utils/
│ │ │ ├── attachment.ts
│ │ │ ├── date.ts
│ │ │ ├── id.ts
│ │ │ ├── index.ts
│ │ │ └── permission.ts
│ │ ├── tsconfig.app.json
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ └── tsdown.config.ts
│ └── ui-plugin-bundler-kit/
│ ├── README.md
│ ├── package.json
│ ├── src/
│ │ ├── constants/
│ │ │ ├── build.ts
│ │ │ ├── externals.ts
│ │ │ └── halo-plugin.ts
│ │ ├── index.ts
│ │ ├── legacy.ts
│ │ ├── rsbuild.ts
│ │ ├── utils/
│ │ │ └── halo-plugin.ts
│ │ └── vite.ts
│ ├── tsconfig.json
│ └── tsdown.config.ts
├── patches/
│ └── @tiptap__extension-drag-handle@3.17.1.patch
├── pnpm-workspace.yaml
├── postcss.config.cjs
├── scripts/
│ ├── apply_missing_translations.mjs
│ ├── find_missing_translations.mjs
│ └── fix_translations.mjs
├── src/
│ ├── components/
│ │ ├── alerts/
│ │ │ └── H2WarningAlert.vue
│ │ ├── attachment/
│ │ │ ├── AttachmentGridListItem.vue
│ │ │ ├── AttachmentImagePreview.vue
│ │ │ └── AttachmentPermalinkList.vue
│ │ ├── back-to-top/
│ │ │ └── BackToTop.vue
│ │ ├── base-app/
│ │ │ └── BaseApp.vue
│ │ ├── button/
│ │ │ └── SubmitButton.vue
│ │ ├── codemirror/
│ │ │ ├── Codemirror.vue
│ │ │ └── supports.ts
│ │ ├── common/
│ │ │ └── AppDownloadAlert.vue
│ │ ├── dropdown-selector/
│ │ │ └── EditorProviderSelector.vue
│ │ ├── editor/
│ │ │ └── DefaultEditor.vue
│ │ ├── entity/
│ │ │ └── EntityDropdownItems.vue
│ │ ├── entity-fields/
│ │ │ ├── EntityFieldItems.vue
│ │ │ └── StatusDotField.vue
│ │ ├── filter/
│ │ │ ├── CategoryFilterDropdown.vue
│ │ │ ├── FilterCleanButton.vue
│ │ │ ├── FilterDropdown.vue
│ │ │ ├── FilterTag.vue
│ │ │ ├── TagFilterDropdown.vue
│ │ │ └── UserFilterDropdown.vue
│ │ ├── form/
│ │ │ └── AnnotationsForm.vue
│ │ ├── global-search/
│ │ │ └── GlobalSearchModal.vue
│ │ ├── icon/
│ │ │ └── AttachmentFileTypeIcon.vue
│ │ ├── input/
│ │ │ └── SearchInput.vue
│ │ ├── menu/
│ │ │ ├── MenuLoading.vue
│ │ │ └── RoutesMenu.tsx
│ │ ├── permission/
│ │ │ └── HasPermission.vue
│ │ ├── preview/
│ │ │ └── UrlPreviewModal.vue
│ │ ├── sticky-block/
│ │ │ └── StickyBlock.vue
│ │ ├── upload/
│ │ │ └── UppyUpload.vue
│ │ ├── user/
│ │ │ └── PostContributorList.vue
│ │ ├── user-avatar/
│ │ │ ├── UserAvatar.vue
│ │ │ └── UserAvatarCropper.vue
│ │ └── video/
│ │ └── LazyVideo.vue
│ ├── composables/
│ │ ├── use-auto-save-content.ts
│ │ ├── use-content-cache.ts
│ │ ├── use-editor-extension-points.ts
│ │ ├── use-role.ts
│ │ ├── use-route-menu-generator.ts
│ │ ├── use-session-keep-alive.ts
│ │ └── use-title.ts
│ ├── constants/
│ │ ├── annotations.ts
│ │ ├── app.ts
│ │ ├── constants.ts
│ │ ├── error-types.ts
│ │ ├── finalizers.ts
│ │ ├── labels.ts
│ │ └── regex.ts
│ ├── formkit/
│ │ ├── formkit.config.ts
│ │ ├── inputs/
│ │ │ ├── array/
│ │ │ │ ├── ArrayFormModal.vue
│ │ │ │ ├── ArrayInput.vue
│ │ │ │ ├── index.ts
│ │ │ │ ├── labels/
│ │ │ │ │ ├── ColorLabel.vue
│ │ │ │ │ └── IconifyLabel.vue
│ │ │ │ ├── renderers/
│ │ │ │ │ ├── attachment.ts
│ │ │ │ │ ├── category-select.ts
│ │ │ │ │ ├── checkbox.ts
│ │ │ │ │ ├── helpers/
│ │ │ │ │ │ └── findOption.ts
│ │ │ │ │ ├── iconify.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── native-select.ts
│ │ │ │ │ ├── radio.ts
│ │ │ │ │ ├── select.ts
│ │ │ │ │ ├── tag-select.ts
│ │ │ │ │ ├── toggle.ts
│ │ │ │ │ └── types.ts
│ │ │ │ └── sections/
│ │ │ │ └── index.ts
│ │ │ ├── attachment/
│ │ │ │ ├── AttachmentDropdownItem.vue
│ │ │ │ ├── AttachmentInput.vue
│ │ │ │ ├── AttachmentPreview.vue
│ │ │ │ ├── CustomLinkDropdownItem.vue
│ │ │ │ ├── UploadDropdownItem.vue
│ │ │ │ ├── feature.ts
│ │ │ │ └── index.ts
│ │ │ ├── attachment-group-select.ts
│ │ │ ├── attachment-input/
│ │ │ │ ├── AttachmentInput.vue
│ │ │ │ └── index.ts
│ │ │ ├── attachment-policy-select.ts
│ │ │ ├── category-checkbox.ts
│ │ │ ├── category-select/
│ │ │ │ ├── CategorySelect.vue
│ │ │ │ ├── components/
│ │ │ │ │ ├── CategoryListItem.vue
│ │ │ │ │ ├── CategoryTag.vue
│ │ │ │ │ └── SearchResultListItem.vue
│ │ │ │ ├── index.ts
│ │ │ │ └── sections/
│ │ │ │ └── index.ts
│ │ │ ├── code/
│ │ │ │ ├── CodeInput.vue
│ │ │ │ └── index.ts
│ │ │ ├── color/
│ │ │ │ ├── ColorInput.vue
│ │ │ │ ├── index.ts
│ │ │ │ └── types.ts
│ │ │ ├── form.ts
│ │ │ ├── group.ts
│ │ │ ├── iconify/
│ │ │ │ ├── Collections.vue
│ │ │ │ ├── CollectionsView.vue
│ │ │ │ ├── Icon.vue
│ │ │ │ ├── IconConfirmPanel.vue
│ │ │ │ ├── IconifyInput.vue
│ │ │ │ ├── IconifyPicker.vue
│ │ │ │ ├── Icons.vue
│ │ │ │ ├── SearchView.vue
│ │ │ │ ├── api.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── types.ts
│ │ │ ├── list/
│ │ │ │ ├── AddButton.vue
│ │ │ │ ├── features/
│ │ │ │ │ └── lists.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── listSection.ts
│ │ │ │ └── sections/
│ │ │ │ └── index.ts
│ │ │ ├── menu-checkbox.ts
│ │ │ ├── menu-item-select.ts
│ │ │ ├── menu-radio.ts
│ │ │ ├── menu-select.ts
│ │ │ ├── password/
│ │ │ │ ├── RevealButton.vue
│ │ │ │ └── index.ts
│ │ │ ├── post-select.ts
│ │ │ ├── repeater/
│ │ │ │ ├── AddButton.vue
│ │ │ │ ├── features/
│ │ │ │ │ └── repeats.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── repeaterSection.ts
│ │ │ │ └── sections/
│ │ │ │ └── index.ts
│ │ │ ├── role-select.ts
│ │ │ ├── secret/
│ │ │ │ ├── SecretSelect.vue
│ │ │ │ ├── components/
│ │ │ │ │ ├── SecretCreationModal.vue
│ │ │ │ │ ├── SecretEditModal.vue
│ │ │ │ │ ├── SecretForm.vue
│ │ │ │ │ ├── SecretListItem.vue
│ │ │ │ │ └── SecretListModal.vue
│ │ │ │ ├── composables/
│ │ │ │ │ └── use-secrets-fetch.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── sections/
│ │ │ │ │ └── index.ts
│ │ │ │ └── types/
│ │ │ │ └── index.ts
│ │ │ ├── select/
│ │ │ │ ├── MultipleOverflow.vue
│ │ │ │ ├── MultipleOverflowItem.vue
│ │ │ │ ├── MultipleSelect.vue
│ │ │ │ ├── MultipleSelectItem.vue
│ │ │ │ ├── MultipleSelectSearchInput.vue
│ │ │ │ ├── MultipleSelectSelector.vue
│ │ │ │ ├── SelectContainer.vue
│ │ │ │ ├── SelectDropdownContainer.vue
│ │ │ │ ├── SelectMain.vue
│ │ │ │ ├── SelectOption.vue
│ │ │ │ ├── SelectOptionItem.vue
│ │ │ │ ├── SelectSearchInput.vue
│ │ │ │ ├── SelectSelector.vue
│ │ │ │ ├── index.ts
│ │ │ │ ├── isFalse.ts
│ │ │ │ └── sections/
│ │ │ │ └── index.ts
│ │ │ ├── singlePage-select.ts
│ │ │ ├── switch/
│ │ │ │ ├── SwitchInput.vue
│ │ │ │ ├── feature.ts
│ │ │ │ └── index.ts
│ │ │ ├── tag-checkbox.ts
│ │ │ ├── tag-select/
│ │ │ │ ├── TagSelect.vue
│ │ │ │ ├── index.ts
│ │ │ │ └── sections/
│ │ │ │ └── index.ts
│ │ │ ├── toggle/
│ │ │ │ ├── ToggleInput.vue
│ │ │ │ ├── feature.ts
│ │ │ │ └── index.ts
│ │ │ ├── user-select.ts
│ │ │ └── verify-form/
│ │ │ ├── VerificationButton.vue
│ │ │ ├── features/
│ │ │ │ └── index.ts
│ │ │ └── index.ts
│ │ ├── plugins/
│ │ │ ├── auto-scroll-to-errors.ts
│ │ │ ├── password-prevent-autocomplete.ts
│ │ │ ├── radio-alt.ts
│ │ │ ├── required-asterisk.ts
│ │ │ └── stop-implicit-submission.ts
│ │ ├── theme.ts
│ │ └── utils/
│ │ └── focus.ts
│ ├── layouts/
│ │ ├── MobileMenu.vue
│ │ └── UserProfileBanner.vue
│ ├── locales/
│ │ ├── en.json
│ │ ├── es.json
│ │ ├── index.ts
│ │ ├── zh-CN.json
│ │ └── zh-TW.json
│ ├── router/
│ │ └── process-bar.ts
│ ├── setup/
│ │ ├── setupApiClient.ts
│ │ ├── setupComponents.ts
│ │ ├── setupModules.ts
│ │ ├── setupStyles.ts
│ │ ├── setupUserPermissions.ts
│ │ └── setupVueQuery.ts
│ ├── stores/
│ │ ├── plugin.ts
│ │ └── role.ts
│ ├── styles/
│ │ ├── index.css
│ │ └── tailwind.css
│ ├── utils/
│ │ ├── __tests__/
│ │ │ └── media-type.spec.ts
│ │ ├── cookie.ts
│ │ ├── device.ts
│ │ ├── image.ts
│ │ ├── load-style.ts
│ │ ├── media-type.ts
│ │ ├── modal.ts
│ │ └── role.ts
│ ├── views/
│ │ └── exceptions/
│ │ ├── Forbidden.vue
│ │ ├── NotFound.vue
│ │ ├── __tests__/
│ │ │ └── NotFound.spec.ts
│ │ └── components/
│ │ └── Exception.vue
│ └── vite/
│ ├── library-external.ts
│ └── plugin-dev.ts
├── tailwind.config.ts
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.node.json
├── tsconfig.vitest.json
├── uc-src/
│ ├── App.vue
│ ├── layouts/
│ │ └── BasicLayout.vue
│ ├── main.ts
│ ├── modules/
│ │ ├── contents/
│ │ │ ├── attachments/
│ │ │ │ ├── components/
│ │ │ │ │ ├── AttachmentDetailModal.vue
│ │ │ │ │ ├── AttachmentSelectorModal.vue
│ │ │ │ │ └── selector-providers/
│ │ │ │ │ ├── AttachmentUploadModal.vue
│ │ │ │ │ ├── CoreSelectorProvider.vue
│ │ │ │ │ └── components/
│ │ │ │ │ └── AttachmentSelectorListItem.vue
│ │ │ │ └── module.ts
│ │ │ └── posts/
│ │ │ ├── PostEditor.vue
│ │ │ ├── PostList.vue
│ │ │ ├── components/
│ │ │ │ ├── PostCreationModal.vue
│ │ │ │ ├── PostListItem.vue
│ │ │ │ ├── PostSettingEditModal.vue
│ │ │ │ └── PostSettingForm.vue
│ │ │ ├── composables/
│ │ │ │ ├── use-post-publish-mutate.ts
│ │ │ │ └── use-post-update-mutate.ts
│ │ │ ├── module.ts
│ │ │ └── types/
│ │ │ └── index.ts
│ │ ├── index.ts
│ │ ├── notifications/
│ │ │ ├── Notifications.vue
│ │ │ ├── components/
│ │ │ │ ├── NotificationContent.vue
│ │ │ │ └── NotificationListItem.vue
│ │ │ └── module.ts
│ │ └── profile/
│ │ ├── Profile.vue
│ │ ├── components/
│ │ │ ├── EmailVerifyModal.vue
│ │ │ ├── PasswordChangeModal.vue
│ │ │ ├── PersonalAccessTokenCreationModal.vue
│ │ │ ├── PersonalAccessTokenListItem.vue
│ │ │ └── ProfileEditingModal.vue
│ │ ├── module.ts
│ │ └── tabs/
│ │ ├── Authentication.vue
│ │ ├── Detail.vue
│ │ ├── Devices.vue
│ │ ├── NotificationPreferences.vue
│ │ ├── PersonalAccessTokens.vue
│ │ ├── components/
│ │ │ ├── AuthProviders.vue
│ │ │ ├── DeviceDetailModal.vue
│ │ │ ├── DeviceListItem.vue
│ │ │ ├── PasswordValidationForm.vue
│ │ │ ├── TotpConfigureModal.vue
│ │ │ ├── TotpDeletionModal.vue
│ │ │ ├── TwoFactor.vue
│ │ │ ├── TwoFactorDisableModal.vue
│ │ │ └── TwoFactorEnableModal.vue
│ │ └── composables/
│ │ ├── use-user-agent.ts
│ │ └── use-user-device.ts
│ └── router/
│ ├── constant.ts
│ ├── guards/
│ │ ├── auth-check.ts
│ │ └── permission.ts
│ ├── index.ts
│ └── routes.config.ts
├── uc.html
└── vite.config.ts
================================================
FILE CONTENTS
================================================
================================================
FILE: .dockerignore
================================================
ui
.github
.git
================================================
FILE: .editorconfig
================================================
root=true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = false
max_line_length = 120
tab_width = 4
ij_continuation_indent_size = 8
ij_formatter_off_tag = @formatter:off
ij_formatter_on_tag = @formatter:on
ij_formatter_tags_enabled = true
ij_smart_tabs = false
ij_wrap_on_typing = false
[*.java]
max_line_length = 100
ij_continuation_indent_size = 4
ij_java_align_consecutive_assignments = false
ij_java_align_consecutive_variable_declarations = false
ij_java_align_group_field_declarations = false
ij_java_align_multiline_annotation_parameters = false
ij_java_align_multiline_array_initializer_expression = false
ij_java_align_multiline_assignment = false
ij_java_align_multiline_binary_operation = false
ij_java_align_multiline_chained_methods = false
ij_java_align_multiline_extends_list = false
ij_java_align_multiline_for = true
ij_java_align_multiline_method_parentheses = false
ij_java_align_multiline_parameters = false
ij_java_align_multiline_parameters_in_calls = false
ij_java_align_multiline_parenthesized_expression = false
ij_java_align_multiline_records = true
ij_java_align_multiline_resources = true
ij_java_align_multiline_ternary_operation = false
ij_java_align_multiline_text_blocks = false
ij_java_align_multiline_throws_list = false
ij_java_align_subsequent_simple_methods = false
ij_java_align_throws_keyword = false
ij_java_annotation_parameter_wrap = off
ij_java_array_initializer_new_line_after_left_brace = false
ij_java_array_initializer_right_brace_on_new_line = false
ij_java_array_initializer_wrap = normal
ij_java_assert_statement_colon_on_next_line = false
ij_java_assert_statement_wrap = normal
ij_java_assignment_wrap = normal
ij_java_binary_operation_sign_on_next_line = true
ij_java_binary_operation_wrap = normal
ij_java_blank_lines_after_anonymous_class_header = 0
ij_java_blank_lines_after_class_header = 0
ij_java_blank_lines_after_imports = 1
ij_java_blank_lines_after_package = 1
ij_java_blank_lines_around_class = 1
ij_java_blank_lines_around_field = 0
ij_java_blank_lines_around_field_in_interface = 0
ij_java_blank_lines_around_initializer = 1
ij_java_blank_lines_around_method = 1
ij_java_blank_lines_around_method_in_interface = 1
ij_java_blank_lines_before_class_end = 0
ij_java_blank_lines_before_imports = 0
ij_java_blank_lines_before_method_body = 0
ij_java_blank_lines_before_package = 1
ij_java_block_brace_style = end_of_line
ij_java_block_comment_at_first_column = false
ij_java_call_parameters_new_line_after_left_paren = false
ij_java_call_parameters_right_paren_on_new_line = false
ij_java_call_parameters_wrap = normal
ij_java_case_statement_on_separate_line = true
ij_java_catch_on_new_line = false
ij_java_class_annotation_wrap = split_into_lines
ij_java_class_brace_style = end_of_line
ij_java_class_count_to_use_import_on_demand = 999
ij_java_class_names_in_javadoc = 1
ij_java_do_not_indent_top_level_class_members = false
ij_java_do_not_wrap_after_single_annotation = false
ij_java_do_while_brace_force = always
ij_java_doc_add_blank_line_after_description = true
ij_java_doc_add_blank_line_after_param_comments = false
ij_java_doc_add_blank_line_after_return = false
ij_java_doc_add_p_tag_on_empty_lines = true
ij_java_doc_align_exception_comments = true
ij_java_doc_align_param_comments = false
ij_java_doc_do_not_wrap_if_one_line = false
ij_java_doc_enable_formatting = true
ij_java_doc_enable_leading_asterisks = true
ij_java_doc_indent_on_continuation = false
ij_java_doc_keep_empty_lines = true
ij_java_doc_keep_empty_parameter_tag = true
ij_java_doc_keep_empty_return_tag = true
ij_java_doc_keep_empty_throws_tag = true
ij_java_doc_keep_invalid_tags = true
ij_java_doc_param_description_on_new_line = false
ij_java_doc_preserve_line_breaks = false
ij_java_doc_use_throws_not_exception_tag = true
ij_java_else_on_new_line = false
ij_java_enum_constants_wrap = normal
ij_java_extends_keyword_wrap = normal
ij_java_extends_list_wrap = normal
ij_java_field_annotation_wrap = split_into_lines
ij_java_finally_on_new_line = false
ij_java_for_brace_force = always
ij_java_for_statement_new_line_after_left_paren = false
ij_java_for_statement_right_paren_on_new_line = false
ij_java_for_statement_wrap = normal
ij_java_generate_final_locals = false
ij_java_generate_final_parameters = false
ij_java_if_brace_force = always
ij_java_imports_layout = $*, |, *, |, *
ij_java_indent_case_from_switch = true
ij_java_insert_inner_class_imports = false
ij_java_insert_override_annotation = true
ij_java_keep_blank_lines_before_right_brace = 2
ij_java_keep_blank_lines_between_package_declaration_and_header = 2
ij_java_keep_blank_lines_in_code = 2
ij_java_keep_blank_lines_in_declarations = 2
ij_java_keep_control_statement_in_one_line = true
ij_java_keep_first_column_comment = true
ij_java_keep_indents_on_empty_lines = false
ij_java_keep_line_breaks = true
ij_java_keep_multiple_expressions_in_one_line = false
ij_java_keep_simple_blocks_in_one_line = false
ij_java_keep_simple_classes_in_one_line = false
ij_java_keep_simple_lambdas_in_one_line = false
ij_java_keep_simple_methods_in_one_line = false
ij_java_label_indent_absolute = false
ij_java_label_indent_size = 0
ij_java_lambda_brace_style = end_of_line
ij_java_layout_static_imports_separately = true
ij_java_line_comment_add_space = true
ij_java_line_comment_at_first_column = false
ij_java_method_annotation_wrap = split_into_lines
ij_java_method_brace_style = end_of_line
ij_java_method_call_chain_wrap = normal
ij_java_method_parameters_new_line_after_left_paren = false
ij_java_method_parameters_right_paren_on_new_line = false
ij_java_method_parameters_wrap = normal
ij_java_modifier_list_wrap = false
ij_java_names_count_to_use_import_on_demand = 999
ij_java_new_line_after_lparen_in_record_header = false
ij_java_parameter_annotation_wrap = normal
ij_java_parentheses_expression_new_line_after_left_paren = false
ij_java_parentheses_expression_right_paren_on_new_line = false
ij_java_place_assignment_sign_on_next_line = false
ij_java_prefer_longer_names = true
ij_java_prefer_parameters_wrap = false
ij_java_record_components_wrap = normal
ij_java_repeat_synchronized = true
ij_java_replace_instanceof_and_cast = false
ij_java_replace_null_check = true
ij_java_replace_sum_lambda_with_method_ref = true
ij_java_resource_list_new_line_after_left_paren = false
ij_java_resource_list_right_paren_on_new_line = false
ij_java_resource_list_wrap = normal
ij_java_rparen_on_new_line_in_record_header = false
ij_java_space_after_closing_angle_bracket_in_type_argument = false
ij_java_space_after_colon = true
ij_java_space_after_comma = true
ij_java_space_after_comma_in_type_arguments = true
ij_java_space_after_for_semicolon = true
ij_java_space_after_quest = true
ij_java_space_after_type_cast = true
ij_java_space_before_annotation_array_initializer_left_brace = false
ij_java_space_before_annotation_parameter_list = false
ij_java_space_before_array_initializer_left_brace = true
ij_java_space_before_catch_keyword = true
ij_java_space_before_catch_left_brace = true
ij_java_space_before_catch_parentheses = true
ij_java_space_before_class_left_brace = true
ij_java_space_before_colon = true
ij_java_space_before_colon_in_foreach = true
ij_java_space_before_comma = false
ij_java_space_before_do_left_brace = true
ij_java_space_before_else_keyword = true
ij_java_space_before_else_left_brace = true
ij_java_space_before_finally_keyword = true
ij_java_space_before_finally_left_brace = true
ij_java_space_before_for_left_brace = true
ij_java_space_before_for_parentheses = true
ij_java_space_before_for_semicolon = false
ij_java_space_before_if_left_brace = true
ij_java_space_before_if_parentheses = true
ij_java_space_before_method_call_parentheses = false
ij_java_space_before_method_left_brace = true
ij_java_space_before_method_parentheses = false
ij_java_space_before_opening_angle_bracket_in_type_parameter = false
ij_java_space_before_quest = true
ij_java_space_before_switch_left_brace = true
ij_java_space_before_switch_parentheses = true
ij_java_space_before_synchronized_left_brace = true
ij_java_space_before_synchronized_parentheses = true
ij_java_space_before_try_left_brace = true
ij_java_space_before_try_parentheses = true
ij_java_space_before_type_parameter_list = false
ij_java_space_before_while_keyword = true
ij_java_space_before_while_left_brace = true
ij_java_space_before_while_parentheses = true
ij_java_space_inside_one_line_enum_braces = false
ij_java_space_within_empty_array_initializer_braces = false
ij_java_space_within_empty_method_call_parentheses = false
ij_java_space_within_empty_method_parentheses = false
ij_java_spaces_around_additive_operators = true
ij_java_spaces_around_assignment_operators = true
ij_java_spaces_around_bitwise_operators = true
ij_java_spaces_around_equality_operators = true
ij_java_spaces_around_lambda_arrow = true
ij_java_spaces_around_logical_operators = true
ij_java_spaces_around_method_ref_dbl_colon = false
ij_java_spaces_around_multiplicative_operators = true
ij_java_spaces_around_relational_operators = true
ij_java_spaces_around_shift_operators = true
ij_java_spaces_around_type_bounds_in_type_parameters = true
ij_java_spaces_around_unary_operator = false
ij_java_spaces_within_angle_brackets = false
ij_java_spaces_within_annotation_parentheses = false
ij_java_spaces_within_array_initializer_braces = false
ij_java_spaces_within_braces = false
ij_java_spaces_within_brackets = false
ij_java_spaces_within_cast_parentheses = false
ij_java_spaces_within_catch_parentheses = false
ij_java_spaces_within_for_parentheses = false
ij_java_spaces_within_if_parentheses = false
ij_java_spaces_within_method_call_parentheses = false
ij_java_spaces_within_method_parentheses = false
ij_java_spaces_within_parentheses = false
ij_java_spaces_within_switch_parentheses = false
ij_java_spaces_within_synchronized_parentheses = false
ij_java_spaces_within_try_parentheses = false
ij_java_spaces_within_while_parentheses = false
ij_java_special_else_if_treatment = true
ij_java_subclass_name_suffix = Impl
ij_java_ternary_operation_signs_on_next_line = true
ij_java_ternary_operation_wrap = normal
ij_java_test_name_suffix = Test
ij_java_throws_keyword_wrap = normal
ij_java_throws_list_wrap = normal
ij_java_use_external_annotations = false
ij_java_use_fq_class_names = false
ij_java_use_relative_indents = false
ij_java_use_single_class_imports = true
ij_java_variable_annotation_wrap = normal
ij_java_visibility = public
ij_java_while_brace_force = always
ij_java_while_on_new_line = false
ij_java_wrap_comments = false
ij_java_wrap_first_method_in_call_chain = false
ij_java_wrap_long_lines = true
[*.properties]
ij_properties_align_group_field_declarations = false
ij_properties_keep_blank_lines = false
ij_properties_key_value_delimiter = equals
ij_properties_spaces_around_key_value_delimiter = false
[.editorconfig]
ij_editorconfig_align_group_field_declarations = false
ij_editorconfig_space_after_colon = false
ij_editorconfig_space_after_comma = true
ij_editorconfig_space_before_colon = false
ij_editorconfig_space_before_comma = false
ij_editorconfig_spaces_around_assignment_operators = true
[{*.ant, *.fxml, *.jhm, *.jnlp, *.jrxml, *.jspx, *.pom, *.rng, *.tagx, *.tld, *.wsdl, *.xml, *.xsd, *.xsl, *.xslt, *.xul}]
ij_xml_align_attributes = true
ij_xml_align_text = false
ij_xml_attribute_wrap = normal
ij_xml_block_comment_at_first_column = true
ij_xml_keep_blank_lines = 2
ij_xml_keep_indents_on_empty_lines = false
ij_xml_keep_line_breaks = true
ij_xml_keep_line_breaks_in_text = true
ij_xml_keep_whitespaces = false
ij_xml_keep_whitespaces_around_cdata = preserve
ij_xml_keep_whitespaces_inside_cdata = false
ij_xml_line_comment_at_first_column = true
ij_xml_space_after_tag_name = false
ij_xml_space_around_equals_in_attribute = false
ij_xml_space_inside_empty_tag = false
ij_xml_text_wrap = normal
[{*.bash, *.sh, *.zsh}]
indent_size = 2
tab_width = 2
ij_shell_binary_ops_start_line = false
ij_shell_keep_column_alignment_padding = false
ij_shell_minify_program = false
ij_shell_redirect_followed_by_space = false
ij_shell_switch_cases_indented = false
[{*.gant, *.gradle, *.groovy, *.gy}]
ij_groovy_align_group_field_declarations = false
ij_groovy_align_multiline_array_initializer_expression = false
ij_groovy_align_multiline_assignment = false
ij_groovy_align_multiline_binary_operation = false
ij_groovy_align_multiline_chained_methods = false
ij_groovy_align_multiline_extends_list = false
ij_groovy_align_multiline_for = true
ij_groovy_align_multiline_list_or_map = true
ij_groovy_align_multiline_method_parentheses = false
ij_groovy_align_multiline_parameters = true
ij_groovy_align_multiline_parameters_in_calls = false
ij_groovy_align_multiline_resources = true
ij_groovy_align_multiline_ternary_operation = false
ij_groovy_align_multiline_throws_list = false
ij_groovy_align_named_args_in_map = true
ij_groovy_align_throws_keyword = false
ij_groovy_array_initializer_new_line_after_left_brace = false
ij_groovy_array_initializer_right_brace_on_new_line = false
ij_groovy_array_initializer_wrap = off
ij_groovy_assert_statement_wrap = off
ij_groovy_assignment_wrap = off
ij_groovy_binary_operation_wrap = off
ij_groovy_blank_lines_after_class_header = 0
ij_groovy_blank_lines_after_imports = 1
ij_groovy_blank_lines_after_package = 1
ij_groovy_blank_lines_around_class = 1
ij_groovy_blank_lines_around_field = 0
ij_groovy_blank_lines_around_field_in_interface = 0
ij_groovy_blank_lines_around_method = 1
ij_groovy_blank_lines_around_method_in_interface = 1
ij_groovy_blank_lines_before_imports = 1
ij_groovy_blank_lines_before_method_body = 0
ij_groovy_blank_lines_before_package = 0
ij_groovy_block_brace_style = end_of_line
ij_groovy_block_comment_at_first_column = true
ij_groovy_call_parameters_new_line_after_left_paren = false
ij_groovy_call_parameters_right_paren_on_new_line = false
ij_groovy_call_parameters_wrap = off
ij_groovy_catch_on_new_line = false
ij_groovy_class_annotation_wrap = split_into_lines
ij_groovy_class_brace_style = end_of_line
ij_groovy_class_count_to_use_import_on_demand = 5
ij_groovy_do_while_brace_force = never
ij_groovy_else_on_new_line = false
ij_groovy_enum_constants_wrap = off
ij_groovy_extends_keyword_wrap = off
ij_groovy_extends_list_wrap = off
ij_groovy_field_annotation_wrap = split_into_lines
ij_groovy_finally_on_new_line = false
ij_groovy_for_brace_force = never
ij_groovy_for_statement_new_line_after_left_paren = false
ij_groovy_for_statement_right_paren_on_new_line = false
ij_groovy_for_statement_wrap = off
ij_groovy_if_brace_force = never
ij_groovy_import_annotation_wrap = 2
ij_groovy_indent_case_from_switch = true
ij_groovy_indent_label_blocks = true
ij_groovy_insert_inner_class_imports = false
ij_groovy_keep_blank_lines_before_right_brace = 2
ij_groovy_keep_blank_lines_in_code = 2
ij_groovy_keep_blank_lines_in_declarations = 2
ij_groovy_keep_control_statement_in_one_line = true
ij_groovy_keep_first_column_comment = true
ij_groovy_keep_indents_on_empty_lines = false
ij_groovy_keep_line_breaks = true
ij_groovy_keep_multiple_expressions_in_one_line = false
ij_groovy_keep_simple_blocks_in_one_line = false
ij_groovy_keep_simple_classes_in_one_line = true
ij_groovy_keep_simple_lambdas_in_one_line = true
ij_groovy_keep_simple_methods_in_one_line = true
ij_groovy_label_indent_absolute = false
ij_groovy_label_indent_size = 0
ij_groovy_lambda_brace_style = end_of_line
ij_groovy_layout_static_imports_separately = true
ij_groovy_line_comment_add_space = false
ij_groovy_line_comment_at_first_column = true
ij_groovy_method_annotation_wrap = split_into_lines
ij_groovy_method_brace_style = end_of_line
ij_groovy_method_call_chain_wrap = off
ij_groovy_method_parameters_new_line_after_left_paren = false
ij_groovy_method_parameters_right_paren_on_new_line = false
ij_groovy_method_parameters_wrap = off
ij_groovy_modifier_list_wrap = false
ij_groovy_names_count_to_use_import_on_demand = 3
ij_groovy_parameter_annotation_wrap = off
ij_groovy_parentheses_expression_new_line_after_left_paren = false
ij_groovy_parentheses_expression_right_paren_on_new_line = false
ij_groovy_prefer_parameters_wrap = false
ij_groovy_resource_list_new_line_after_left_paren = false
ij_groovy_resource_list_right_paren_on_new_line = false
ij_groovy_resource_list_wrap = off
ij_groovy_space_after_assert_separator = true
ij_groovy_space_after_colon = true
ij_groovy_space_after_comma = true
ij_groovy_space_after_comma_in_type_arguments = true
ij_groovy_space_after_for_semicolon = true
ij_groovy_space_after_quest = true
ij_groovy_space_after_type_cast = true
ij_groovy_space_before_annotation_parameter_list = false
ij_groovy_space_before_array_initializer_left_brace = false
ij_groovy_space_before_assert_separator = false
ij_groovy_space_before_catch_keyword = true
ij_groovy_space_before_catch_left_brace = true
ij_groovy_space_before_catch_parentheses = true
ij_groovy_space_before_class_left_brace = true
ij_groovy_space_before_closure_left_brace = true
ij_groovy_space_before_colon = true
ij_groovy_space_before_comma = false
ij_groovy_space_before_do_left_brace = true
ij_groovy_space_before_else_keyword = true
ij_groovy_space_before_else_left_brace = true
ij_groovy_space_before_finally_keyword = true
ij_groovy_space_before_finally_left_brace = true
ij_groovy_space_before_for_left_brace = true
ij_groovy_space_before_for_parentheses = true
ij_groovy_space_before_for_semicolon = false
ij_groovy_space_before_if_left_brace = true
ij_groovy_space_before_if_parentheses = true
ij_groovy_space_before_method_call_parentheses = false
ij_groovy_space_before_method_left_brace = true
ij_groovy_space_before_method_parentheses = false
ij_groovy_space_before_quest = true
ij_groovy_space_before_switch_left_brace = true
ij_groovy_space_before_switch_parentheses = true
ij_groovy_space_before_synchronized_left_brace = true
ij_groovy_space_before_synchronized_parentheses = true
ij_groovy_space_before_try_left_brace = true
ij_groovy_space_before_try_parentheses = true
ij_groovy_space_before_while_keyword = true
ij_groovy_space_before_while_left_brace = true
ij_groovy_space_before_while_parentheses = true
ij_groovy_space_in_named_argument = true
ij_groovy_space_in_named_argument_before_colon = false
ij_groovy_space_within_empty_array_initializer_braces = false
ij_groovy_space_within_empty_method_call_parentheses = false
ij_groovy_spaces_around_additive_operators = true
ij_groovy_spaces_around_assignment_operators = true
ij_groovy_spaces_around_bitwise_operators = true
ij_groovy_spaces_around_equality_operators = true
ij_groovy_spaces_around_lambda_arrow = true
ij_groovy_spaces_around_logical_operators = true
ij_groovy_spaces_around_multiplicative_operators = true
ij_groovy_spaces_around_regex_operators = true
ij_groovy_spaces_around_relational_operators = true
ij_groovy_spaces_around_shift_operators = true
ij_groovy_spaces_within_annotation_parentheses = false
ij_groovy_spaces_within_array_initializer_braces = false
ij_groovy_spaces_within_braces = true
ij_groovy_spaces_within_brackets = false
ij_groovy_spaces_within_cast_parentheses = false
ij_groovy_spaces_within_catch_parentheses = false
ij_groovy_spaces_within_for_parentheses = false
ij_groovy_spaces_within_gstring_injection_braces = false
ij_groovy_spaces_within_if_parentheses = false
ij_groovy_spaces_within_list_or_map = false
ij_groovy_spaces_within_method_call_parentheses = false
ij_groovy_spaces_within_method_parentheses = false
ij_groovy_spaces_within_parentheses = false
ij_groovy_spaces_within_switch_parentheses = false
ij_groovy_spaces_within_synchronized_parentheses = false
ij_groovy_spaces_within_try_parentheses = false
ij_groovy_spaces_within_tuple_expression = false
ij_groovy_spaces_within_while_parentheses = false
ij_groovy_special_else_if_treatment = true
ij_groovy_ternary_operation_wrap = off
ij_groovy_throws_keyword_wrap = off
ij_groovy_throws_list_wrap = off
ij_groovy_use_flying_geese_braces = false
ij_groovy_use_fq_class_names = false
ij_groovy_use_fq_class_names_in_javadoc = true
ij_groovy_use_relative_indents = false
ij_groovy_use_single_class_imports = true
ij_groovy_variable_annotation_wrap = off
ij_groovy_while_brace_force = never
ij_groovy_while_on_new_line = false
ij_groovy_wrap_long_lines = false
[{*.har, *.json}]
indent_size = 2
ij_json_keep_blank_lines_in_code = 0
ij_json_keep_indents_on_empty_lines = false
ij_json_keep_line_breaks = true
ij_json_space_after_colon = true
ij_json_space_after_comma = true
ij_json_space_before_colon = true
ij_json_space_before_comma = false
ij_json_spaces_within_braces = false
ij_json_spaces_within_brackets = false
ij_json_wrap_long_lines = false
[{*.htm, *.html, *.sht, *.shtm, *.shtml}]
ij_html_add_new_line_before_tags = body, div, p, form, h1, h2, h3
ij_html_align_attributes = true
ij_html_align_text = false
ij_html_attribute_wrap = normal
ij_html_block_comment_at_first_column = true
ij_html_do_not_align_children_of_min_lines = 0
ij_html_do_not_break_if_inline_tags = title, h1, h2, h3, h4, h5, h6, p
ij_html_do_not_indent_children_of_tags = html, body, thead, tbody, tfoot
ij_html_enforce_quotes = false
ij_html_inline_tags = a, abbr, acronym, b, basefont, bdo, big, br, cite, cite, code, dfn, em, font, i, img, input, kbd, label, q, s, samp, select, small, span, strike, strong, sub, sup, textarea, tt, u, var
ij_html_keep_blank_lines = 2
ij_html_keep_indents_on_empty_lines = false
ij_html_keep_line_breaks = true
ij_html_keep_line_breaks_in_text = true
ij_html_keep_whitespaces = false
ij_html_keep_whitespaces_inside = span, pre, textarea
ij_html_line_comment_at_first_column = true
ij_html_new_line_after_last_attribute = never
ij_html_new_line_before_first_attribute = never
ij_html_quote_style = double
ij_html_remove_new_line_before_tags = br
ij_html_space_after_tag_name = false
ij_html_space_around_equality_in_attribute = false
ij_html_space_inside_empty_tag = false
ij_html_text_wrap = normal
[{*.yaml, *.yml}]
indent_size = 2
ij_yaml_keep_indents_on_empty_lines = false
ij_yaml_keep_line_breaks = true
[*.md]
indent_size = 2
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.en.yml
================================================
name: Bug Report
description: File a bug report
labels: [bug]
body:
- type: checkboxes
id: preface
attributes:
label: Prerequisites
description: Thank you for taking the time to fill out this issue report! Before we begin, we highly recommend reading through the [Open Source Guides](https://opensource.guide/), which will greatly improve our mutual efficiency.
options:
- label: I have searched for related issues in the [issues](https://github.com/halo-dev/halo/issues) list.
required: true
- label: "This is an issue with the Halo project itself. If it is not an issue with the project itself(For example: Installation and deployment issues.), it is recommended to submit it in the [Discussions](https://github.com/halo-dev/halo/discussions)."
required: true
- label: I have tried disabling all plugins to rule out plugins as the cause of the problem.
required: true
- label: If it is an issue with plugins and themes, please submit it in the respective plugin and theme repositories.
required: true
- type: markdown
id: environment
attributes:
value: "## Environment"
- type: textarea
id: system-information
attributes:
label: "System information"
description: "Access the actuator page of the Console, click the copy button in the upper right corner, and paste the information here."
placeholder: |
- External url: https://demo.halo.run
- Start time: 2024-07-21 14:50
- Version: 2.x.x
- Build time: 2024-07-15 18:19
- Git Commit: 6d4bedd
- Java: IBM Semeru Runtime Open Edition / ...
- Database: PostgreSQL / 16.3 ...
- Operating system: Linux / 5.15.0-88 ...
- Activated theme: ...
- Enabled plugins:
- ...
validations:
required: true
- type: dropdown
id: operation-method
validations:
required: true
attributes:
label: "What is the project operation method?"
options:
- Docker
- Docker Compose
- Fat Jar
- Source Code
- type: markdown
id: details
attributes:
value: "## Details"
- type: textarea
id: what-happened
attributes:
label: "What happened?"
description: "For ease of management, please do not report multiple unrelated issues under the same issue."
validations:
required: true
- type: textarea
id: reproduce-steps
attributes:
label: "Reproduce Steps"
description: "If it can be consistently reproduced, please provide detailed steps."
placeholder: |
1. Open '...'
2. Click '...'
- type: textarea
id: logs
attributes:
label: "Relevant log output"
description: "Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks."
render: shell
- type: textarea
id: additional-information
attributes:
label: "Additional information"
description: "If you have other information to note, you can fill it in here (screenshots, videos, etc.)."
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.zh.yml
================================================
name: Bug 反馈
description: 提交 Bug 反馈
labels: [bug]
body:
- type: checkboxes
id: preface
attributes:
label: 前置条件
description: 感谢你花时间填写此错误报告!在开始之前,我们非常推荐阅读一遍[《开源软件指南》](https://opensource.guide/zh-hans/),这会在很大程度上提高我们彼此的效率。
options:
- label: 已经在 [issues](https://github.com/halo-dev/halo/issues) 列表中搜索了相关问题。
required: true
- label: 这是 Halo 项目本身存在的问题,如果是非项目本身的问题(如:安装部署问题),建议在 [Discussions](https://github.com/halo-dev/halo/discussions) 提交。
required: true
- label: 已经尝试过停用所有的插件,排除是插件导致的问题。
required: true
- label: 如果是插件和主题的问题,请在对应的插件和主题仓库提交。
required: true
- type: markdown
id: environment
attributes:
value: "## 环境信息"
- type: textarea
id: system-information
attributes:
label: "系统信息"
description: "访问 Console 的概览页面,点击右上角的复制按钮,将信息粘贴到此处。"
placeholder: |
- 外部访问地址: https://demo.halo.run
- 启动时间: 2024-07-21 14:50
- 版本: 2.x.x
- 构建时间: 2024-07-15 18:19
- Git Commit: 6d4bedd
- Java: IBM Semeru Runtime Open Edition / ...
- 数据库: PostgreSQL / 16.3 ...
- 操作系统: Linux / 5.15.0-88 ...
- 已激活主题: ...
- 已启动插件:
- ...
validations:
required: true
- type: dropdown
id: operation-method
validations:
required: true
attributes:
label: "使用的哪种方式运行?"
options:
- Docker
- Docker Compose
- Fat Jar
- Source Code
- type: markdown
id: details
attributes:
value: "## 详细信息"
- type: textarea
id: what-happened
attributes:
label: "发生了什么?"
description: "为了方便我们管理,请不要在同一个 issue 下报告多个不相关的问题。"
validations:
required: true
- type: textarea
id: reproduce-steps
attributes:
label: "复现步骤"
description: "如果可以稳定复现,请提供详细的步骤。"
placeholder: |
1. 打开 '...'
2. 点击 '...'
- type: textarea
id: logs
attributes:
label: "相关日志输出"
description: "请复制并粘贴任何相关的日志输出。这将自动格式化为代码,因此无需反引号。"
render: shell
- type: textarea
id: additional-information
attributes:
label: "附加信息"
description: "如果你还有其他需要提供的信息,可以在这里填写(可以提供截图、视频等)。"
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
- name: 商业产品反馈
url: https://github.com/orgs/lxware-dev/discussions
about: Halo 付费版以及应用市场商业应用的问题,建议优先在这里反馈。
- name: 对 Halo 有其他问题
url: https://bbs.halo.run
about: 如果你对 Halo 有其他想要提问的,欢迎到官方社区进行提问。
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.en.yml
================================================
name: Feature Request
description: File a feature request
body:
- type: checkboxes
id: preface
attributes:
label: Prerequisites
description: Hello! Thank you for submitting a new feature suggestion for Halo. Before we begin, we highly recommend reading through the [Open Source Guides](https://opensource.guide/), which will greatly improve our mutual efficiency.
options:
- label: I have searched for related issues in the [Issues](https://github.com/halo-dev/halo/issues) list.
required: true
- label: This is a feature related to Halo. If it is not an issue with the project itself, it is recommended to submit it in the [Discussions](https://github.com/halo-dev/halo/discussions).
required: true
- label: If it is a feature suggestion for plugins and themes, please submit it in the respective plugin and theme repositories.
required: true
- type: markdown
id: environment
attributes:
value: "## Environment"
- type: input
id: version
attributes:
label: "Your current Halo version"
- type: markdown
id: details
attributes:
value: "## Details"
- type: textarea
id: description
attributes:
label: "Describe this feature"
description: "For ease of management, please do not submit multiple unrelated features under the same issue."
validations:
required: true
- type: textarea
id: additional-information
attributes:
label: "Additional information"
description: "If you have other information to note, you can fill it in here (screenshots, videos, etc.)."
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.zh.yml
================================================
name: 新特性建议
description: 提交新特性建议
body:
- type: checkboxes
id: preface
attributes:
label: 前置条件
description: 你好!感谢你为 Halo 提交新特性建议。在开始之前,我们非常推荐阅读一遍[《开源软件指南》](https://opensource.guide/zh-hans/),这会在很大程度上提高我们彼此的效率。
options:
- label: 已经在 [Issues](https://github.com/halo-dev/halo/issues) 列表中搜索了相关问题。
required: true
- label: 这是和 Halo 相关的特性,如果是非项目本身的问题,建议在 [Discussions](https://github.com/halo-dev/halo/discussions) 提交。
required: true
- label: 如果是插件和主题特性建议,请在对应的插件和主题仓库提交。
required: true
- type: markdown
id: environment
attributes:
value: "## 环境信息"
- type: input
id: version
attributes:
label: "你当前使用的版本"
- type: markdown
id: details
attributes:
value: "## 详细信息"
- type: textarea
id: description
attributes:
label: "描述一下此特性"
description: "为了方便我们管理,请不要在同一个 issue 下提交多个没有相关性的特性。"
validations:
required: true
- type: textarea
id: additional-information
attributes:
label: "附加信息"
description: "如果你还有其他需要提供的信息,可以在这里填写(可以提供截图、视频等)。"
================================================
FILE: .github/actions/docker-buildx-push/action.yaml
================================================
name: "Docker buildx and push"
description: "Buildx and push the Docker image."
inputs:
ghcr-token:
description: Token of current GitHub account in GitHub container registry.
required: false
default: ""
dockerhub-user:
description: "User name for the DockerHub account"
required: false
default: ""
dockerhub-token:
description: Token for the DockerHub account
required: false
default: ""
f2c-registry-user:
description: "User name of Fit2Cloud Docker Registry."
required: false
default: ""
f2c-registry-token:
description: "Token of Fit2Cloud Docker Registry."
required: false
default: ""
push:
description: Should push the docker image or not.
required: false
default: "false"
platforms:
description: Target platforms for building image
required: false
default: "linux/amd64,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x"
image-name:
description: The basic name of docker.
required: false
default: "halo"
runs:
using: "composite"
steps:
- name: Docker meta for Halo
id: meta
uses: docker/metadata-action@v5
with:
images: |
ghcr.io/${{ github.repository_owner }}/${{ inputs.image-name }}
halohub/${{ inputs.image-name }}
registry.fit2cloud.com/halo/${{ inputs.image-name }}
tags: |
type=schedule,pattern=nightly-{{date 'YYYYMMDD'}},enabled=${{ github.event_name == 'schedule' }}
type=ref,event=branch,enabled=${{ github.event_name == 'push' }}
type=ref,event=pr,enabled=${{ github.event_name == 'pull_request' }}
type=semver,pattern={{major}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{ version }}
type=sha,enabled=${{ github.event_name == 'push' }}
flavor: |
latest=false
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GHCR
uses: docker/login-action@v3
if: inputs.ghcr-token != '' && github.event_name != 'pull_request'
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ inputs.ghcr-token }}
- name: Login to DockerHub
if: inputs.dockerhub-token != '' && github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ inputs.dockerhub-user }}
password: ${{ inputs.dockerhub-token }}
- name: Login to Fit2Cloud Docker Registry
if: inputs.f2c-registry-token != '' && github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: registry.fit2cloud.com
username: ${{ inputs.f2c-registry-user }}
password: ${{ inputs.f2c-registry-token }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
platforms: ${{ inputs.platforms }}
labels: ${{ steps.meta.outputs.labels }}
tags: ${{ steps.meta.outputs.tags }}
push: ${{ (inputs.ghcr-token != '' || inputs.dockerhub-token != '') && inputs.push == 'true' }}
================================================
FILE: .github/actions/setup-env/action.yaml
================================================
name: Setup Environment
description: Setup environment to check and build Halo, including console and core projects.
inputs:
node-version:
description: Node.js version.
required: false
default: "24"
pnpm-version:
description: pnpm version.
required: false
default: "10"
java-version:
description: Java version.
required: false
default: "21"
runs:
using: "composite"
steps:
- uses: pnpm/action-setup@v3
name: Setup pnpm
with:
version: ${{ inputs.pnpm-version }}
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
cache: "pnpm"
cache-dependency-path: "ui/pnpm-lock.yaml"
- name: Setup JDK
uses: actions/setup-java@v4
with:
distribution: "temurin"
cache: "gradle"
java-version: ${{ inputs.java-version }}
================================================
FILE: .github/pull_request_template.md
================================================
<!-- Thanks for sending a pull request! Here are some tips for you:
1. 如果这是你的第一次,请阅读我们的贡献指南:<https://github.com/halo-dev/halo/blob/main/CONTRIBUTING.md>。
1. If this is your first time, please read our contributor guidelines: <https://github.com/halo-dev/halo/blob/main/CONTRIBUTING.md>.
2. 请根据你解决问题的类型为 Pull Request 添加合适的标签。
2. Please label this pull request according to what type of issue you are addressing, especially if this is a release targeted pull request.
3. 请确保你已经添加并运行了适当的测试。
3. Ensure you have added or ran the appropriate tests for your PR.
4. 如果你的 PR 使用了 LLM 生成代码,请在 PR 中添加相应的说明,我们不反对使用 LLM 辅助开发,但希望你能够先对生成的代码进行审查。
5. If your PR uses LLM generated code, please add a corresponding description in the PR, we do not oppose using LLM to assist development, but we hope you can review the generated code first.
-->
#### What type of PR is this?
<!--
添加其中一个类别:
Add one of the following kinds:
/kind bug
/kind cleanup
/kind documentation
/kind feature
/kind improvement
适当添加其中一个或多个类别(可选):
Optionally add one or more of the following kinds if applicable:
/kind api-change
/kind deprecation
/kind failing-test
/kind flake
/kind regression
-->
#### What this PR does / why we need it:
#### Which issue(s) this PR fixes:
<!--
PR 合并时自动关闭 issue。
Automatically closes linked issue when PR is merged.
用法:`Fixes #<issue 号>`,或者 `Fixes (粘贴 issue 完整链接)`
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
-->
Fixes #
#### Special notes for your reviewer:
#### Does this PR introduce a user-facing change?
<!--
如果当前 Pull Request 的修改不会造成用户侧的任何变更,在 `release-note` 代码块儿中填写 `NONE`。
否则请填写用户侧能够理解的 Release Note。如果当前 Pull Request 包含破坏性更新(Break Change),
Release Note 需要以 `action required` 开头。
If no, just write "NONE" in the release-note block below.
If yes, a release note is required:
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".
-->
```release-note
```
================================================
FILE: .github/workflows/halo.yaml
================================================
name: Halo Workflow
on:
pull_request:
branches:
- main
- release-*
paths:
- "**"
- "!**.md"
push:
branches:
- main
- release-*
paths:
- "**"
- "!**.md"
release:
types:
- published
concurrency:
group: ${{github.workflow}} - ${{github.ref}}
cancel-in-progress: true
jobs:
test:
if: github.event_name == 'pull_request' || github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Environment
uses: ./.github/actions/setup-env
- name: Check Halo
run: ./gradlew clean check --configuration-cache --configuration-cache-problems=warn
- name: Upload coverage reports to Codecov
if: github.repository == 'halo-dev/halo'
uses: codecov/codecov-action@v4
build:
runs-on: ubuntu-latest
if: always() && (needs.test.result == 'skipped' || needs.test.result == 'success')
needs: test
steps:
- uses: actions/checkout@v4
- name: Setup Environment
uses: ./.github/actions/setup-env
- name: Reset version of Halo
if: github.event_name == 'release'
shell: bash
run: |
# Set the version with tag name when releasing
version=${{ github.event.release.tag_name }}
version=${version#v}
sed -i "s/version=.*-SNAPSHOT$/version=$version/1" gradle.properties
- name: Build Halo
run: ./gradlew clean downloadPluginPresets build -x check --configuration-cache --configuration-cache-problems=warn
- name: Upload Artifacts
if: github.repository == 'halo-dev/halo'
uses: actions/upload-artifact@v4
with:
name: halo-artifacts
path: application/build/libs
retention-days: 1
github-release:
runs-on: ubuntu-latest
if: always() && needs.build.result == 'success' && github.event_name == 'release'
needs: build
steps:
- uses: actions/checkout@v4
- name: Download Artifacts
uses: actions/download-artifact@v4
with:
name: halo-artifacts
path: application/build/libs
- name: Upload Artifacts
if: github.repository == 'halo-dev/halo'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh release upload ${{ github.event.release.tag_name }} application/build/libs/*
build-and-publish-container-image-with-buildpacks:
needs: build
if: always() && needs.build.result == 'success' && (github.event_name == 'push' || github.event_name == 'release')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Environment
uses: ./.github/actions/setup-env
- name: Reset version of Halo
if: github.event_name == 'release'
shell: bash
run: |
# Set the version with tag name when releasing
version=${{ github.event.release.tag_name }}
version=${version#v}
sed -i "s/version=.*-SNAPSHOT$/version=$version/1" gradle.properties
- name: Publish To Container Registries
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }}
F2C_USERNAME: ${{ secrets.F2C_REGISTRY_USER }}
F2C_TOKEN: ${{ secrets.F2C_REGISTRY_TOKEN }}
GHCR_USERNAME: ${{ github.repository_owner }}
GHCR_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run:
./gradlew publishToAllRegistries -Prelease=${{ github.event_name == 'release' && 'true' || 'false' }}
docker-build-and-push:
if: always() && needs.build.result == 'success' && (github.event_name == 'push' || github.event_name == 'release')
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v4
- name: Download Artifacts
uses: actions/download-artifact@v4
with:
name: halo-artifacts
path: application/build/libs
- name: Docker Buildx and Push
uses: ./.github/actions/docker-buildx-push
with:
image-name: ${{ github.event_name == 'release' && 'halo' || 'halo-dev' }}
ghcr-token: ${{ secrets.GITHUB_TOKEN }}
dockerhub-user: ${{ secrets.DOCKER_USERNAME }}
dockerhub-token: ${{ secrets.DOCKER_TOKEN }}
f2c-registry-user: ${{ secrets.F2C_REGISTRY_USER }}
f2c-registry-token: ${{ secrets.F2C_REGISTRY_TOKEN }}
push: true
platforms: linux/amd64,linux/arm64/v8,linux/ppc64le,linux/s390x
e2e-test:
if: always() && needs.build.result == 'success' && (github.event_name == 'pull_request' || github.event_name == 'push')
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v4
- name: Download Artifacts
uses: actions/download-artifact@v4
with:
name: halo-artifacts
path: application/build/libs
- name: Docker Build
uses: docker/build-push-action@v5
with:
tags: ghcr.io/halo-dev/halo-dev:main
push: false
context: .
- name: E2E Testing
continue-on-error: true
run: |
sudo curl -L https://github.com/docker/compose/releases/download/v2.23.0/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
sudo chmod u+x /usr/local/bin/docker-compose
cd e2e && make all
================================================
FILE: .github/workflows/openapi-check.yaml
================================================
name: OpenAPI Check
on:
pull_request:
branches:
- main
- release-*
paths:
- 'application/src/**'
- 'api/src/**'
- 'api-docs/openapi/**'
- 'ui/packages/api-client/**'
push:
branches:
- main
- release-*
paths:
- 'application/src/**'
- 'api/src/**'
- 'api-docs/openapi/**'
- 'ui/packages/api-client/**'
concurrency:
group: ${{github.workflow}} - ${{github.ref}}
cancel-in-progress: true
jobs:
openapi-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Environment
uses: ./.github/actions/setup-env
- name: Install UI dependencies
run: ./gradlew pnpmInstall
- name: Regenerate OpenAPI docs
run: ./gradlew generateOpenApiDocs --no-configuration-cache
- name: Regenerate api-client
run: cd ui && pnpm run api-client:gen
- name: Verify OpenAPI docs and api-client are in sync
run: |
if ! git diff --exit-code -- api-docs/openapi ui/packages/api-client/src; then
echo "::error::OpenAPI docs or api-client generated code is out of sync with the current API. Run './gradlew generateOpenApiDocs --no-configuration-cache' and 'cd ui && pnpm run api-client:gen', then commit the changes under api-docs/openapi and ui/packages/api-client/src."
git diff --stat api-docs/openapi ui/packages/api-client/src
exit 1
fi
================================================
FILE: .github/workflows/packages-preview-release.yaml
================================================
name: "Packages preview release"
on:
push:
paths:
- "ui/packages/**"
branches:
- main
pull_request:
paths:
- "ui/packages/**"
branches:
- main
jobs:
packages-preview-release:
runs-on: ubuntu-latest
if: github.repository == 'halo-dev/halo'
steps:
- uses: actions/checkout@v4
- name: Setup Environment
uses: ./.github/actions/setup-env
- name: Install Dependencies
run: ./gradlew pnpmInstall
- name: Build Packages
run: cd ui && pnpm build:packages
- name: Release
run: cd ui && pnpx pkg-pr-new publish --compact --pnpm './packages/*'
================================================
FILE: .github/workflows/release-ui-packages.yaml
================================================
name: Release UI Packages
on:
release:
types:
- published
permissions:
contents: write
id-token: write
jobs:
release:
runs-on: ubuntu-latest
if: github.repository == 'halo-dev/halo' && github.event.release.prerelease == false
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Environment
uses: ./.github/actions/setup-env
- run: ./gradlew pnpmInstall
- name: Publish to NPM
run: cd ui && pnpm run publish:packages
================================================
FILE: .github/workflows/stale-issues.yaml
================================================
name: Close Stale Issues
on:
schedule:
- cron: "30 1 * * *"
workflow_dispatch:
permissions:
issues: write
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v10
with:
stale-issue-message: |
This issue has been automatically marked as stale because it has not had recent activity.
It will be closed if no further activity occurs within the next 2 days.
If you believe this issue is still relevant, please provide the requested information.
close-issue-message: |
This issue has been automatically closed due to inactivity.
If you have the requested information, feel free to reopen it or create a new issue.
days-before-issue-stale: 60
days-before-issue-close: 2
days-before-pr-stale: -1
days-before-pr-close: -1
stale-issue-label: "lifecycle/stale"
any-of-issue-labels: "triage/needs-information,priority/awaiting-more-evidence,help wanted"
operations-per-run: 100
ascending: true
================================================
FILE: .gitignore
================================================
### Maven
target/
logs/
!.mvn/wrapper/maven-wrapper.jar
### Gradle
.gradle
build/
out/
!gradle/wrapper/gradle-wrapper.jar
bin/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
log/
### NetBeans ###
nbproject/private/
build/
nbbuild/
dist/
nbdist/
.nb-gradle/
### Mac
.DS_Store
*/.DS_Store
### VS Code ###
*.project
*.factorypath
### Compiled class file
*.class
### Log file
*.log
### BlueJ files
*.ctxt
### Mobile Tools for Java (J2ME)
.mtj.tmp/
### Package Files
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
### VSCode
.vscode
!.vscode/settings.json
!.vscode/extensions.json
### Local file
application-local.yml
application-local.yaml
application-local.properties
### Zip file for test
!application/src/test/resources/themes/*.zip
!application/src/main/resources/themes/*.zip
application/src/main/resources/console/
application/src/main/resources/uc/
application/src/main/resources/presets/
### Node
node_modules
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
### Frontend
dist
coverage
*.local
### Cypress
/cypress/videos/
/cypress/screenshots/
### Frontend build
!src/build
storybook-static
tsconfig.tsbuildinfo
.tgz
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
hi@halo.run.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing Guide
Thank you for your interest in contributing to Halo.
This document explains the recommended workflow for submitting high-quality contributions, including code, tests, and documentation updates.
## Before You Start
- For new features or major behavior changes, please open an issue first so we can align on scope and design.
- For clear bug fixes, you can submit a pull request directly.
- If your report is not about the core project itself (for example, deployment questions), please use Discussions instead of Issues.
## Development Environment
This repository mainly contains:
- Backend and platform modules built with Gradle.
- Frontend code in `ui`, managed with `pnpm` workspaces.
### Prerequisites
- Git
- JDK (version compatible with the project build)
- Node.js and `pnpm` (see `ui/package.json` for the current package manager)
- Docker / Docker Compose (required for e2e scenarios)
## Contribution Workflow
### 1. Fork and Clone
Fork this repository, then clone your fork:
```bash
git clone https://github.com/{YOUR_USERNAME}/{REPOSITORY}.git
cd {REPOSITORY}
```
### 2. Add Upstream Remote
```bash
git remote add upstream https://github.com/halo-dev/halo.git
git fetch upstream
```
### 3. Create a Branch
Use a focused branch name that reflects your change:
```bash
git checkout -b feat/short-description
```
### 4. Implement and Validate
Run relevant checks before opening a PR.
Backend and general checks:
```bash
./gradlew clean check
```
Frontend checks (in `ui`):
```bash
cd ui
pnpm install
pnpm build:packages
pnpm lint
pnpm typecheck
pnpm test:unit
```
### 5. Commit and Push
```bash
git push origin <your-branch>
```
### 6. Open a Pull Request
Open a PR from your branch to `main` and fill out the PR template carefully:
- Describe what changed and why.
- Link related issues (for example, `Fixes #123`).
- Add release note content or `NONE` when no user-facing change is introduced.
- Add proper `/kind` labels as requested in the template.
## AI-Assisted Contribution Policy
AI-assisted development is not prohibited, including code generation and refactoring support.
However, you are fully responsible for any code in your PR.
If you used AI tools, please follow these rules:
- Review all AI-generated content before submission.
- Verify correctness, security, performance, and maintainability.
- Ensure generated code follows project conventions and architecture.
- Remove low-quality or redundant generated code.
- Mention AI assistance in your PR description when AI materially contributed to the final changes.
In short: AI assistance is allowed, but unreviewed AI output is not acceptable.
## Testing Expectations
- Add or update tests whenever you change behavior.
- If you add or modify APIs, please include corresponding e2e test cases.
- See `e2e/README.md` for e2e workflow and local execution details.
## Coding Standards
- Follow the project coding style guide: <https://docs.halo.run/developer-guide/core/code-style>
- Keep changes focused and avoid unrelated refactors in the same PR.
- Run formatters and linters before pushing.
## Keep Your Fork Updated
Before starting new work, sync your branch with upstream:
```bash
git fetch upstream
git checkout main
git merge upstream/main
git push origin main
```
## Need Help?
- Open an issue for confirmed bugs and feature proposals.
- Use Discussions for general questions and usage/deployment topics.
Thanks again for helping improve Halo.
================================================
FILE: Dockerfile
================================================
FROM eclipse-temurin:21-jre as builder
WORKDIR application
ARG JAR_FILE=application/build/libs/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract
################################
FROM ibm-semeru-runtimes:open-21-jre
LABEL maintainer="johnniang <johnniang@foxmail.com>"
WORKDIR application
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/spring-boot-loader/ ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/application/ ./
ENV JVM_OPTS="" \
HALO_WORK_DIR="/root/.halo2" \
SPRING_CONFIG_LOCATION="optional:classpath:/;optional:file:/root/.halo2/" \
TZ=Asia/Shanghai
RUN ln -sf /usr/share/zoneinfo/$TZ /etc/localtime \
&& echo $TZ > /etc/timezone
Expose 8090
ENTRYPOINT ["sh", "-c", "java ${JVM_OPTS} org.springframework.boot.loader.launch.JarLauncher ${0} ${@}"]
================================================
FILE: LICENSE
================================================
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
================================================
FILE: OWNERS
================================================
approvers:
- ruibaby
- guqing
- JohnNiang
- LIlGG
================================================
FILE: README.md
================================================
<p align="center">
<a href="https://www.halo.run" target="_blank" rel="noopener noreferrer">
<img width="100" src="https://www.halo.run/logo" alt="Halo logo" />
</a>
</p>
<p align="center"><b>Halo</b> [ˈheɪloʊ],强大易用的开源建站工具。</p>
<p align="center">
<a href="https://github.com/halo-dev/halo/releases"><img alt="GitHub release" src="https://img.shields.io/github/release/halo-dev/halo.svg?style=flat-square&include_prereleases" /></a>
<a href="https://hub.docker.com/r/halohub/halo"><img alt="Docker pulls" src="https://img.shields.io/docker/pulls/halohub/halo?style=flat-square" /></a>
<a href="https://github.com/halo-dev/halo/commits"><img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/halo-dev/halo.svg?style=flat-square" /></a>
<a href="https://github.com/halo-dev/halo/actions"><img alt="GitHub Workflow Status" src="https://img.shields.io/github/actions/workflow/status/halo-dev/halo/halo.yaml?branch=main&style=flat-square" /></a>
<a href="https://codecov.io/gh/halo-dev/halo"><img alt="Codecov percentage" src="https://img.shields.io/codecov/c/github/halo-dev/halo/main?style=flat-square&token=YsRUg9fall"/></a>
<a href="https://gitcode.com/feizhiyun/Halo"><img src="https://gitcode.com/feizhiyun/Halo/star/badge.svg" alt="GitCode Stars"></a>
<a href="https://www.producthunt.com/posts/halo-6b401e75-bb58-4dff-9fe9-2ada3323c874?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-halo-6b401e75-bb58-4dff-9fe9-2ada3323c874" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=407442&theme=light" alt="Halo - Powerful and easy-to-use Open-Source website building tool | Product Hunt" style="height: 20px;" height="20px" /></a>
<br />
<a href="https://www.halo.run">官网</a>
<a href="https://docs.halo.run">文档</a>
<a href="https://bbs.halo.run">社区</a>
<a href="https://gitee.com/halo-dev">Gitee</a>
<a href="https://t.me/halo_dev">Telegram 频道</a>
</p>
[](https://www.bilibili.com/video/BV15x4y1U7RU/?share_source=copy_web&vd_source=0ab6cf86ca512a363f04f18b86f55b86)
------------------------------
## 快速开始
如果你的设备有 Docker 环境,可以使用以下命令快速启动一个 Halo 的体验环境:
```bash
docker run -d --name halo -p 8090:8090 -v ~/.halo2:/root/.halo2 halohub/halo:2.22
```
或者点击下方按钮使用 [Gitpod](https://gitpod.io/) 或 [ClawCloud Run](https://template.us-west-1.run.claw.cloud/deploy?templateName=halo) 启动一个体验环境:
[](https://gitpod.io/#https://github.com/halo-sigs/gitpod-demo)
[](https://template.us-west-1.run.claw.cloud/deploy?templateName=halo)
**以上方式仅作为体验使用,推荐使用开源 Linux 服务器运维管理面板 [1Panel](https://github.com/1Panel-dev/1Panel) 进行部署([查看文档](https://docs.halo.run/getting-started/install/1panel)),轻松搞定反向代理、SSL 证书及升级备份任务。更多部署方式,请[查看文档](https://docs.halo.run/category/%E5%AE%89%E8%A3%85%E6%8C%87%E5%8D%97)。**
## 在线体验
- 环境地址:<https://demo.halocms.site>
- 后台地址:<https://demo.halocms.site/console>
- 用户名:`demo`
- 密码:`P@ssw0rd123..`
## 付费版
相比于社区版,Halo 付费版为用户提供了大量增强功能及技术支持服务,增强功能包括商城、短信验证码注册登录、全站私有化、LDAP 登录、三方账号登录及自定义 Logo 等。 [点击查看付费版详细介绍](https://www.lxware.cn/halo)。
## 生态
可访问 [官方应用市场](https://www.halo.run/store/apps) 或 [awesome-halo 仓库](https://github.com/halo-sigs/awesome-halo) 查看适用于 Halo 2.x 的主题和插件。
## 许可证
[](https://github.com/halo-dev/halo/blob/master/LICENSE)
Halo 使用 GPL-v3.0 协议开源,请遵守开源协议。
## 贡献
参考 [CONTRIBUTING](https://github.com/halo-dev/halo/blob/main/CONTRIBUTING.md)。
<a href="https://github.com/halo-dev/halo/graphs/contributors"><img src="https://opencollective.com/halo/contributors.svg?width=890&button=false" /></a>
## 状态

================================================
FILE: SECURITY.md
================================================
# Security Policy
## Supported Versions
Halo currently supports the versions listed below, where as:
- :white_check_mark: indicates an active development roadmap, is therefore maintaining, and **will** receive Security
Vulnerability Report.
- :x: indicates such version has already deprecated and **will not** be receiving Security Vulnerability Report.
| Version | Supported |
| ------- | ------------------ |
| 0.x | :x: |
| 1.x | :x: |
| 2.x | :white_check_mark: |
## Reporting a Vulnerability
We first appreciate and are very thankful that you've found a vulnerability issue in Halo! By disclosing such issue to
Halo development team you are helping Halo to become a much more safer project than before! ;)
To protect the existing users of Halo, we kindly ask you to not disclose the vulnerability to anyone except the Halo
development team before a fix has been rolled out.
To Report a Vulnerability, please complete the form below, and send such report by email to `hi@halo.run`.
```
Vulnerability has been observed in...
- Docker? [n/y]:
if yes for the question above,
- `docker -v`:
- `docker images halohub/halo`:
- by `java -jar halo.jar`? [n/y]:
if yes for the question above,
- `uname -a`:
- `java -version`:
- Affected by Halo version(s) [e.g. v2.4.0]:
- Vulnerability self-scoring [1-10]:
- Would you like to be attributed? (Whether you agree us to appreciate you by putting your name in the CHANGELOG of the next fix release) [n/y]:
```
================================================
FILE: api/build.gradle
================================================
plugins {
id 'checkstyle'
id 'java-library'
id 'halo.publish'
id 'jacoco'
alias(libs.plugins.lombok)
alias(libs.plugins.versions)
}
group = 'run.halo.app'
description = 'API of halo project, connecting by other projects.'
tasks.withType(JavaCompile).configureEach {
options.release = 21
options.encoding = 'UTF-8'
}
tasks.withType(Javadoc).configureEach {
options.encoding = 'UTF-8'
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
withJavadocJar()
withSourcesJar()
}
checkstyle {
toolVersion = libs.versions.checkstyle.get()
showViolations = false
ignoreFailures = false
}
jar {
manifest {
attributes(
'Implementation-Title': project.name,
'Implementation-Version': project.version,
'Implementation-Vendor': 'Halo Project',
)
}
}
repositories {
mavenCentral()
}
dependencies {
api platform(project(':platform:application'))
annotationProcessor platform(project(':platform:application'))
api 'org.springframework.boot:spring-boot-starter-actuator'
api 'org.springframework.boot:spring-boot-starter-mail'
api 'org.springframework.boot:spring-boot-starter-thymeleaf'
api 'org.springframework.boot:spring-boot-starter-webflux'
api 'org.springframework.boot:spring-boot-starter-validation'
api 'org.springframework.boot:spring-boot-starter-data-r2dbc'
api 'org.springframework.session:spring-session-core'
api 'org.springframework.boot:spring-boot-jackson2'
api 'org.springframework.boot:spring-boot-integration'
api 'org.springframework.boot:spring-boot-session'
// Spring Security
api 'org.springframework.boot:spring-boot-starter-security'
api 'org.springframework.security:spring-security-oauth2-jose'
api 'org.springframework.security:spring-security-oauth2-client'
api 'org.springframework.security:spring-security-oauth2-resource-server'
api 'io.micrometer:context-propagation'
// Cache
api "org.springframework.boot:spring-boot-starter-cache"
api "com.github.ben-manes.caffeine:caffeine"
api "org.springdoc:springdoc-openapi-starter-webflux-ui"
api 'org.openapi4j:openapi-schema-validator'
api "net.bytebuddy:byte-buddy"
api "org.bouncycastle:bcpkix-jdk18on"
// Apache Lucene
api "org.apache.lucene:lucene-core"
api "org.apache.lucene:lucene-queryparser"
api "org.apache.lucene:lucene-highlighter"
api "org.apache.lucene:lucene-backward-codecs"
api 'org.apache.lucene:lucene-analysis-common'
api "org.apache.commons:commons-lang3"
api "io.seruco.encoding:base62"
api "org.pf4j:pf4j"
api "com.google.guava:guava"
api "org.jsoup:jsoup"
api "io.github.java-diff-utils:java-diff-utils"
api "org.springframework.integration:spring-integration-core"
api "com.github.java-json-tools:json-patch"
api "org.thymeleaf.extras:thymeleaf-extras-springsecurity6"
api 'org.apache.tika:tika-core'
api 'net.coobird:thumbnailator'
api "io.github.resilience4j:resilience4j-spring-boot3"
api "io.github.resilience4j:resilience4j-reactor"
api "com.j256.two-factor-auth:two-factor-auth"
runtimeOnly 'io.r2dbc:r2dbc-h2'
runtimeOnly 'org.postgresql:postgresql'
runtimeOnly 'org.postgresql:r2dbc-postgresql'
runtimeOnly 'org.mariadb:r2dbc-mariadb'
runtimeOnly 'io.asyncer:r2dbc-mysql'
runtimeOnly 'com.github.therapi:therapi-runtime-javadoc'
annotationProcessor "com.github.therapi:therapi-runtime-javadoc-scribe"
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
testImplementation 'io.projectreactor:reactor-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
publishing {
publications.named('mavenJava', MavenPublication) {
from components.java
pom {
name = 'API library'
description = "$project.description"
}
}
}
tasks.named('test') {
useJUnitPlatform()
finalizedBy jacocoTestReport
}
tasks.named('jacocoTestReport') {
reports {
xml.required = true
html.required = false
}
}
tasks.named('uploadBundle') {
mustRunAfter project(':platform:application').tasks.named('uploadBundle')
}
================================================
FILE: api/src/main/java/run/halo/app/content/ContentWrapper.java
================================================
package run.halo.app.content;
import lombok.Builder;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;
import run.halo.app.core.extension.content.Snapshot;
/**
* @author guqing
* @since 2.0.0
*/
@Data
@Builder
public class ContentWrapper {
private String snapshotName;
private String raw;
private String content;
private String rawType;
public static ContentWrapper patchSnapshot(Snapshot patchSnapshot, Snapshot baseSnapshot) {
Assert.notNull(baseSnapshot, "The baseSnapshot must not be null.");
String baseSnapshotName = baseSnapshot.getMetadata().getName();
if (StringUtils.equals(patchSnapshot.getMetadata().getName(), baseSnapshotName)) {
return ContentWrapper.builder()
.snapshotName(patchSnapshot.getMetadata().getName())
.raw(patchSnapshot.getSpec().getRawPatch())
.content(patchSnapshot.getSpec().getContentPatch())
.rawType(patchSnapshot.getSpec().getRawType())
.build();
}
String patchedContent = PatchUtils.applyPatch(baseSnapshot.getSpec().getContentPatch(),
patchSnapshot.getSpec().getContentPatch());
String patchedRaw = PatchUtils.applyPatch(baseSnapshot.getSpec().getRawPatch(),
patchSnapshot.getSpec().getRawPatch());
return ContentWrapper.builder()
.snapshotName(patchSnapshot.getMetadata().getName())
.raw(patchedRaw)
.content(patchedContent)
.rawType(patchSnapshot.getSpec().getRawType())
.build();
}
}
================================================
FILE: api/src/main/java/run/halo/app/content/ExcerptGenerator.java
================================================
package run.halo.app.content;
import java.util.Set;
import lombok.Data;
import lombok.experimental.Accessors;
import org.pf4j.ExtensionPoint;
import reactor.core.publisher.Mono;
public interface ExcerptGenerator extends ExtensionPoint {
Mono<String> generate(ExcerptGenerator.Context context);
@Data
@Accessors(chain = true)
class Context {
private String raw;
/**
* html content.
*/
private String content;
private String rawType;
/**
* keywords in the content to help the excerpt generation more accurate.
*/
private Set<String> keywords;
/**
* Max length of the generated excerpt.
*/
private int maxLength;
}
}
================================================
FILE: api/src/main/java/run/halo/app/content/PatchUtils.java
================================================
package run.halo.app.content;
import com.fasterxml.jackson.core.type.TypeReference;
import com.github.difflib.DiffUtils;
import com.github.difflib.patch.AbstractDelta;
import com.github.difflib.patch.ChangeDelta;
import com.github.difflib.patch.Chunk;
import com.github.difflib.patch.DeleteDelta;
import com.github.difflib.patch.DeltaType;
import com.github.difflib.patch.InsertDelta;
import com.github.difflib.patch.Patch;
import com.github.difflib.patch.PatchFailedException;
import com.google.common.base.Splitter;
import java.util.Collections;
import java.util.List;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import run.halo.app.infra.utils.JsonUtils;
/**
* @author guqing
* @since 2.0.0
*/
public class PatchUtils {
private static final String DELIMITER = "\n";
private static final Splitter lineSplitter = Splitter.on(DELIMITER);
public static Patch<String> create(String deltasJson) {
List<Delta> deltas = JsonUtils.jsonToObject(deltasJson, new TypeReference<>() {
});
Patch<String> patch = new Patch<>();
for (Delta delta : deltas) {
StringChunk sourceChunk = delta.getSource();
StringChunk targetChunk = delta.getTarget();
Chunk<String> orgChunk = new Chunk<>(sourceChunk.getPosition(), sourceChunk.getLines(),
sourceChunk.getChangePosition());
Chunk<String> revChunk = new Chunk<>(targetChunk.getPosition(), targetChunk.getLines(),
targetChunk.getChangePosition());
switch (delta.getType()) {
case DELETE -> patch.addDelta(new DeleteDelta<>(orgChunk, revChunk));
case INSERT -> patch.addDelta(new InsertDelta<>(orgChunk, revChunk));
case CHANGE -> patch.addDelta(new ChangeDelta<>(orgChunk, revChunk));
default -> throw new IllegalArgumentException("Unsupported delta type.");
}
}
return patch;
}
public static String patchToJson(Patch<String> patch) {
List<AbstractDelta<String>> deltas = patch.getDeltas();
return JsonUtils.objectToJson(deltas);
}
public static String applyPatch(String original, String patchJson) {
Patch<String> patch = PatchUtils.create(patchJson);
try {
return String.join(DELIMITER, patch.applyTo(breakLine(original)));
} catch (PatchFailedException e) {
throw new RuntimeException(e);
}
}
public static String diffToJsonPatch(String original, String revised) {
Patch<String> patch = DiffUtils.diff(breakLine(original), breakLine(revised));
return PatchUtils.patchToJson(patch);
}
public static List<String> breakLine(String content) {
if (StringUtils.isBlank(content)) {
return Collections.emptyList();
}
return lineSplitter.splitToList(content);
}
@Data
public static class Delta {
private StringChunk source;
private StringChunk target;
private DeltaType type;
}
@Data
public static class StringChunk {
private int position;
private List<String> lines;
private List<Integer> changePosition;
}
}
================================================
FILE: api/src/main/java/run/halo/app/content/PostContentService.java
================================================
package run.halo.app.content;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public interface PostContentService {
Mono<ContentWrapper> getHeadContent(String postName);
Mono<ContentWrapper> getReleaseContent(String postName);
Mono<ContentWrapper> getSpecifiedContent(String postName, String snapshotName);
Flux<String> listSnapshots(String postName);
}
================================================
FILE: api/src/main/java/run/halo/app/content/comment/CommentSubject.java
================================================
package run.halo.app.content.comment;
import org.pf4j.ExtensionPoint;
import reactor.core.publisher.Mono;
import run.halo.app.extension.Extension;
import run.halo.app.extension.Ref;
/**
* Comment subject.
*
* @author guqing
* @since 2.0.0
*/
public interface CommentSubject<T extends Extension> extends ExtensionPoint {
Mono<T> get(String name);
default Mono<SubjectDisplay> getSubjectDisplay(String name) {
return Mono.empty();
}
boolean supports(Ref ref);
record SubjectDisplay(String title, String url, String kindName) {
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/attachment/ThumbnailProvider.java
================================================
package run.halo.app.core.attachment;
import java.net.URI;
import java.net.URL;
import lombok.Builder;
import lombok.Data;
import org.pf4j.ExtensionPoint;
import reactor.core.publisher.Mono;
import run.halo.app.core.extension.attachment.endpoint.AttachmentHandler;
/**
* Thumbnail provider extension.
*
* @since 2.22.0
* @deprecated Use {@link AttachmentHandler} instead. We are planing to remove this extension
* point in future release.
*/
@Deprecated(forRemoval = true, since = "2.22.0")
public interface ThumbnailProvider extends ExtensionPoint {
/**
* Generate thumbnail URI for given image URL and size.
*
* @param context Thumbnail context including image URI and size
* @return Generated thumbnail URI
*/
Mono<URI> generate(ThumbnailContext context);
/**
* Delete thumbnail file for given image URL.
*
* @param imageUrl original image URL
*/
Mono<Void> delete(URL imageUrl);
/**
* Whether the provider supports the given image URI.
*
* @return {@code true} if supports, {@code false} otherwise
*/
Mono<Boolean> supports(ThumbnailContext context);
@Data
@Builder
class ThumbnailContext {
private final URL imageUrl;
private final ThumbnailSize size;
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/attachment/ThumbnailSize.java
================================================
package run.halo.app.core.attachment;
import java.util.Arrays;
import java.util.Optional;
import lombok.Getter;
@Getter
public enum ThumbnailSize {
S(400),
M(800),
L(1200),
XL(1600);
private final int width;
ThumbnailSize(int width) {
this.width = width;
}
/**
* Convert width string to {@link ThumbnailSize}.
*
* @param width width string
*/
public static ThumbnailSize fromWidth(String width) {
for (ThumbnailSize value : values()) {
if (String.valueOf(value.getWidth()).equals(width)) {
return value;
}
}
return ThumbnailSize.M;
}
/**
* Convert name to {@link ThumbnailSize}.
*/
public static ThumbnailSize fromName(String name) {
for (ThumbnailSize value : values()) {
if (value.name().equalsIgnoreCase(name)) {
return value;
}
}
throw new IllegalArgumentException("No such thumbnail size: " + name);
}
public static Optional<ThumbnailSize> optionalValueOf(String name) {
for (ThumbnailSize value : values()) {
if (value.name().equalsIgnoreCase(name)) {
return Optional.of(value);
}
}
return Optional.empty();
}
public static Integer[] allowedWidths() {
return Arrays.stream(ThumbnailSize.values())
.map(ThumbnailSize::getWidth)
.toArray(Integer[]::new);
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/endpoint/WebSocketEndpoint.java
================================================
package run.halo.app.core.endpoint;
import org.springframework.web.reactive.socket.WebSocketHandler;
import run.halo.app.extension.GroupVersion;
/**
* Endpoint for WebSocket.
*
* @author johnniang
*/
public interface WebSocketEndpoint {
/**
* Path of the URL after group version.
*
* @return path of the URL.
*/
String urlPath();
/**
* Group and version parts of the endpoint.
*
* @return GroupVersion.
*/
GroupVersion groupVersion();
/**
* Real WebSocket handler for the endpoint.
*
* @return WebSocket handler.
*/
WebSocketHandler handler();
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/AnnotationSetting.java
================================================
package run.halo.app.core.extension;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import static run.halo.app.core.extension.AnnotationSetting.KIND;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
import run.halo.app.extension.GroupKind;
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@GVK(group = "", version = "v1alpha1", kind = KIND,
plural = "annotationsettings", singular = "annotationsetting")
public class AnnotationSetting extends AbstractExtension {
public static final String TARGET_REF_LABEL = "halo.run/target-ref";
public static final String KIND = "AnnotationSetting";
@Schema(requiredMode = REQUIRED)
private AnnotationSettingSpec spec;
@Data
public static class AnnotationSettingSpec {
@Schema(requiredMode = REQUIRED)
private GroupKind targetRef;
@Schema(requiredMode = REQUIRED, minLength = 1)
private List<Object> formSchema;
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/AuthProvider.java
================================================
package run.halo.app.core.extension;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.NOT_REQUIRED;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import org.springframework.lang.NonNull;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
/**
* Auth provider extension.
*
* @author guqing
* @since 2.4.0
*/
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@GVK(group = "auth.halo.run", version = "v1alpha1", kind = "AuthProvider",
singular = "authprovider", plural = "authproviders")
public class AuthProvider extends AbstractExtension {
public static final String AUTH_BINDING_LABEL = "auth.halo.run/auth-binding";
public static final String PRIVILEGED_LABEL = "auth.halo.run/privileged";
@Schema(requiredMode = REQUIRED)
private AuthProviderSpec spec;
@Data
@ToString
public static class AuthProviderSpec {
@Schema(requiredMode = REQUIRED, description = "Display name of the auth provider")
private String displayName;
private String description;
private String logo;
private String website;
private String helpPage;
@Schema(requiredMode = REQUIRED, description = "Authentication url of the auth provider")
private String authenticationUrl;
private String method = "GET";
private boolean rememberMeSupport = false;
/**
* Auth type: form or oauth2.
*/
@Getter(onMethod_ = @NonNull)
@Schema(requiredMode = REQUIRED)
private AuthType authType = AuthType.OAUTH2;
private String bindingUrl;
private String unbindUrl;
@Schema(requiredMode = NOT_REQUIRED)
private SettingRef settingRef;
@Schema(requiredMode = NOT_REQUIRED)
private ConfigMapRef configMapRef;
public void setAuthType(AuthType authType) {
this.authType = (authType == null ? AuthType.OAUTH2 : authType);
}
}
@Data
@ToString
public static class SettingRef {
@Schema(requiredMode = REQUIRED, minLength = 1)
private String name;
@Schema(requiredMode = REQUIRED, minLength = 1)
private String group;
}
@Data
@ToString
public static class ConfigMapRef {
@Schema(requiredMode = REQUIRED, minLength = 1)
private String name;
}
public enum AuthType {
FORM,
OAUTH2
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/Counter.java
================================================
package run.halo.app.core.extension;
import lombok.Data;
import lombok.EqualsAndHashCode;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
import run.halo.app.extension.Metadata;
/**
* A counter for number of requests by extension resource name.
*
* @author guqing
* @since 2.0.0
*/
@Data
@GVK(group = "metrics.halo.run", version = "v1alpha1", kind = "Counter", plural = "counters",
singular = "counter")
@EqualsAndHashCode(callSuper = true)
public class Counter extends AbstractExtension {
private Integer visit;
private Integer upvote;
private Integer downvote;
private Integer totalComment;
private Integer approvedComment;
public static Counter emptyCounter(String name) {
Counter counter = new Counter();
counter.setMetadata(new Metadata());
counter.getMetadata().setName(name);
counter.setUpvote(0);
counter.setTotalComment(0);
counter.setApprovedComment(0);
counter.setVisit(0);
return counter;
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/Device.java
================================================
package run.halo.app.core.extension;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.Instant;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.experimental.Accessors;
import org.springframework.lang.NonNull;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
@Data
@EqualsAndHashCode(callSuper = true)
@GVK(group = Device.GROUP, version = Device.VERSION, kind = Device.KIND, plural = "devices",
singular = "device")
public class Device extends AbstractExtension {
public static final String GROUP = "security.halo.run";
public static final String VERSION = "v1alpha1";
public static final String KIND = "Device";
@Schema(requiredMode = REQUIRED)
private Spec spec;
@Getter(onMethod_ = @NonNull)
private Status status = new Status();
public void setStatus(Status status) {
this.status = (status == null ? new Status() : status);
}
@Data
@Accessors(chain = true)
@Schema(name = "DeviceSpec")
public static class Spec {
@Schema(requiredMode = REQUIRED, minLength = 1)
private String sessionId;
@Schema(requiredMode = REQUIRED, minLength = 1)
private String principalName;
@Schema(requiredMode = REQUIRED, maxLength = 129)
private String ipAddress;
@Schema(maxLength = 500)
private String userAgent;
private String rememberMeSeriesId;
private Instant lastAccessedTime;
private Instant lastAuthenticatedTime;
}
@Data
@Accessors(chain = true)
@Schema(name = "DeviceStatus")
public static class Status {
private String browser;
private String os;
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/Menu.java
================================================
package run.halo.app.core.extension;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.LinkedHashSet;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@GVK(group = "", version = "v1alpha1", kind = "Menu", plural = "menus", singular = "menu")
public class Menu extends AbstractExtension {
@Schema(description = "The spec of menu.", requiredMode = REQUIRED)
private Spec spec;
@Data
@Schema(name = "MenuSpec")
public static class Spec {
@Schema(description = "The display name of the menu.", requiredMode = REQUIRED)
private String displayName;
@ArraySchema(
uniqueItems = true,
arraySchema = @Schema(description = "Menu items of this menu."),
schema = @Schema(description = "Name of menu item.")
)
private LinkedHashSet<String> menuItems;
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/MenuItem.java
================================================
package run.halo.app.core.extension;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.LinkedHashSet;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
import run.halo.app.extension.Ref;
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@GVK(group = "", version = "v1alpha1", kind = "MenuItem",
plural = "menuitems", singular = "menuitem")
public class MenuItem extends AbstractExtension {
@Schema(description = "The spec of menu item.", requiredMode = REQUIRED)
private MenuItemSpec spec;
@Schema(description = "The status of menu item.")
private MenuItemStatus status;
public enum Target {
BLANK("_blank"),
SELF("_self"),
PARENT("_parent"),
TOP("_top");
private final String value;
@JsonCreator
Target(String value) {
this.value = value;
}
@JsonValue
public String getValue() {
return value;
}
}
@Data
public static class MenuItemSpec {
@Schema(description = "The display name of menu item.")
private String displayName;
@Schema(description = "The href of this menu item.")
private String href;
@Schema(description = "The <a> target attribute of this menu item.")
private Target target;
@Schema(description = "The priority is for ordering.")
private Integer priority;
@ArraySchema(
uniqueItems = true,
arraySchema = @Schema(description = "Children of this menu item"),
schema = @Schema(description = "The name of menu item child"))
private LinkedHashSet<String> children;
@Schema(description = "Target reference. Like Category, Tag, Post or SinglePage")
private Ref targetRef;
}
@Data
public static class MenuItemStatus {
@Schema(description = "Calculated Display name of menu item.")
private String displayName;
@Schema(description = "Calculated href of manu item.")
private String href;
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/Plugin.java
================================================
package run.halo.app.core.extension;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import java.net.URI;
import java.time.Instant;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.pf4j.PluginState;
import org.springframework.lang.NonNull;
import org.springframework.util.Assert;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
import run.halo.app.infra.ConditionList;
/**
* A custom resource for Plugin.
*
* @author guqing
* @since 2.0.0
*/
@Data
@ToString(callSuper = true)
@GVK(group = "plugin.halo.run", version = "v1alpha1", kind = "Plugin", plural = "plugins",
singular = "plugin")
@EqualsAndHashCode(callSuper = true)
public class Plugin extends AbstractExtension {
public static final String SYSTEM_RESERVED_LABEL_KEY = "plugin.halo.run/system-reserved";
public static final String BUILT_IN_KEEPER_FINALIZER = "plugin.halo.run/built-in-keeper";
@Schema(requiredMode = REQUIRED)
private PluginSpec spec;
private PluginStatus status;
/**
* Gets plugin status.
*
* @return empty object if status is null.
*/
@NonNull
@JsonIgnore
public PluginStatus statusNonNull() {
if (this.status == null) {
this.status = new PluginStatus();
}
return status;
}
@Data
public static class PluginSpec {
private String displayName;
/**
* plugin version.
*
* @see <a href="semver.org">semantic version</a>
*/
@Schema(requiredMode = REQUIRED,
pattern = "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-("
+ "(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\."
+ "(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\"
+ ".[0-9a-zA-Z-]+)*))?$")
private String version;
private PluginAuthor author;
private String logo;
private Map<String, String> pluginDependencies = new HashMap<>(4);
private String homepage;
private String repo;
private String issues;
private String description;
private List<License> license;
/**
* SemVer format.
*/
private String requires = "*";
private Boolean enabled = false;
private String settingName;
private String configMapName;
}
/**
* In the future, we may consider using {@link run.halo.app.infra.model.License} instead of it.
* But now, replace it will lead to incompatibility with downstream.
*/
@Data
public static class License {
private String name;
private String url;
}
@Data
public static class PluginStatus {
private Phase phase;
private ConditionList conditions;
private Instant lastStartTime;
private PluginState lastProbeState;
private String entry;
private String stylesheet;
private String logo;
@Schema(description = "Load location of the plugin, often a path.")
private URI loadLocation;
public static ConditionList nullSafeConditions(@NonNull PluginStatus status) {
Assert.notNull(status, "The status must not be null.");
if (status.getConditions() == null) {
status.setConditions(new ConditionList());
}
return status.getConditions();
}
}
public enum Phase {
PENDING,
STARTING,
CREATED,
DISABLING,
DISABLED,
RESOLVED,
STARTED,
STOPPED,
FAILED,
UNKNOWN,
;
}
@Data
@ToString
public static class PluginAuthor {
@Schema(requiredMode = REQUIRED, minLength = 1)
private String name;
private String website;
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/RememberMeToken.java
================================================
package run.halo.app.core.extension;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.Instant;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
@Data
@EqualsAndHashCode(callSuper = true)
@GVK(group = "security.halo.run", version = "v1alpha1", kind = "RememberMeToken", plural =
"remembermetokens", singular = "remembermetoken")
public class RememberMeToken extends AbstractExtension {
@Schema(requiredMode = REQUIRED)
private Spec spec;
@Data
@Accessors(chain = true)
@Schema(name = "RememberMeTokenSpec")
public static class Spec {
@Schema(requiredMode = REQUIRED, minLength = 1)
private String username;
@Schema(requiredMode = REQUIRED, minLength = 1)
private String series;
@Schema(requiredMode = REQUIRED, minLength = 1)
private String tokenValue;
private Instant lastUsed;
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/ReverseProxy.java
================================================
package run.halo.app.core.extension;
import java.util.List;
import lombok.Data;
import lombok.EqualsAndHashCode;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
/**
* <p>The reverse proxy custom resource is used to configure a path to proxy it to a directory or
* file.</p>
* <p>HTTP proxy may be added in the future.</p>
*
* @author guqing
* @since 2.0.0
*/
@Data
@EqualsAndHashCode(callSuper = true)
@GVK(group = "plugin.halo.run", kind = "ReverseProxy", version = "v1alpha1",
plural = "reverseproxies", singular = "reverseproxy")
public class ReverseProxy extends AbstractExtension {
private List<ReverseProxyRule> rules;
public record ReverseProxyRule(String path, FileReverseProxyProvider file) {
}
public record FileReverseProxyProvider(String directory, String filename) {
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/Role.java
================================================
package run.halo.app.core.extension;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import static java.util.Arrays.compare;
import static run.halo.app.core.extension.Role.GROUP;
import static run.halo.app.core.extension.Role.KIND;
import static run.halo.app.core.extension.Role.VERSION;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import org.springframework.lang.NonNull;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
/**
* @author guqing
* @since 2.0.0
*/
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@GVK(group = GROUP,
version = VERSION,
kind = KIND,
plural = "roles",
singular = "role")
public class Role extends AbstractExtension {
public static final String ROLE_DEPENDENCY_RULES =
"rbac.authorization.halo.run/dependency-rules";
public static final String ROLE_AGGREGATE_LABEL_PREFIX =
"rbac.authorization.halo.run/aggregate-to-";
public static final String ROLE_DEPENDENCIES_ANNO = "rbac.authorization.halo.run/dependencies";
public static final String UI_PERMISSIONS_ANNO = "rbac.authorization.halo.run/ui-permissions";
public static final String SYSTEM_RESERVED_LABELS =
"rbac.authorization.halo.run/system-reserved";
public static final String HIDDEN_LABEL_NAME = "halo.run/hidden";
public static final String TEMPLATE_LABEL_NAME = "halo.run/role-template";
public static final String UI_PERMISSIONS_AGGREGATED_ANNO =
"rbac.authorization.halo.run/ui-permissions-aggregated";
public static final String GROUP = "";
public static final String VERSION = "v1alpha1";
public static final String KIND = "Role";
@Schema(requiredMode = REQUIRED)
List<PolicyRule> rules;
/**
* PolicyRule holds information that describes a policy rule, but does not contain information
* about whom the rule applies to or which namespace the rule applies to.
*
* @author guqing
* @since 2.0.0
*/
@Getter
@EqualsAndHashCode
public static class PolicyRule implements Comparable<PolicyRule> {
/**
* APIGroups is the name of the APIGroup that contains the resources.
* If multiple API groups are specified, any action requested against one of the enumerated
* resources in any API group will be allowed.
*/
final String[] apiGroups;
/**
* Resources is a list of resources this rule applies to. '*' represents all resources in
* the specified apiGroups.
* '*/foo' represents the subresource 'foo' for all resources in the specified
* apiGroups.
*/
final String[] resources;
/**
* ResourceNames is an optional white list of names that the rule applies to. An empty set
* means that everything is allowed.
*/
final String[] resourceNames;
/**
* NonResourceURLs is a set of partial urls that a user should have access to.
* *s are allowed, but only as the full, final step in the path
* If an action is not a resource API request, then the URL is split on '/' and is checked
* against the NonResourceURLs to look for a match.
* Since non-resource URLs are not namespaced, this field is only applicable for
* ClusterRoles referenced from a ClusterRoleBinding.
* Rules can either apply to API resources (such as "pods" or "secrets") or non-resource
* URL paths (such as "/api"), but not both.
*/
final String[] nonResourceURLs;
/**
* about who the rule applies to or which namespace the rule applies to.
*/
final String[] verbs;
public PolicyRule() {
this(null, null, null, null, null);
}
public PolicyRule(String[] apiGroups, String[] resources,
String[] resourceNames,
String[] nonResourceURLs, String[] verbs) {
this.apiGroups = nullElseEmpty(apiGroups);
this.resources = nullElseEmpty(resources);
this.resourceNames = nullElseEmpty(resourceNames);
this.nonResourceURLs = nullElseEmpty(nonResourceURLs);
this.verbs = nullElseEmpty(verbs);
}
String[] nullElseEmpty(String... items) {
if (items == null) {
return new String[] {};
}
return items;
}
@Override
public int compareTo(@NonNull PolicyRule other) {
int result = compare(apiGroups, other.apiGroups);
if (result != 0) {
return result;
}
result = compare(resources, other.resources);
if (result != 0) {
return result;
}
result = compare(resourceNames, other.resourceNames);
if (result != 0) {
return result;
}
result = compare(nonResourceURLs, other.nonResourceURLs);
if (result != 0) {
return result;
}
result = compare(verbs, other.verbs);
return result;
}
public static class Builder {
String[] apiGroups;
String[] resources;
String[] resourceNames;
String[] nonResourceURLs;
String[] verbs;
public Builder apiGroups(String... apiGroups) {
this.apiGroups = apiGroups;
return this;
}
public Builder resources(String... resources) {
this.resources = resources;
return this;
}
public Builder resourceNames(String... resourceNames) {
this.resourceNames = resourceNames;
return this;
}
public Builder nonResourceURLs(String... nonResourceURLs) {
this.nonResourceURLs = nonResourceURLs;
return this;
}
public Builder verbs(String... verbs) {
this.verbs = verbs;
return this;
}
public PolicyRule build() {
return new PolicyRule(apiGroups, resources, resourceNames,
nonResourceURLs,
verbs);
}
}
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/RoleBinding.java
================================================
package run.halo.app.core.extension;
import static run.halo.app.core.extension.RoleBinding.GROUP;
import static run.halo.app.core.extension.RoleBinding.KIND;
import static run.halo.app.core.extension.RoleBinding.VERSION;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.util.StringUtils;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.ExtensionOperator;
import run.halo.app.extension.GVK;
import run.halo.app.extension.Metadata;
/**
* RoleBinding references a role, but does not contain it.
* It can reference a Role in the global.
* It adds who information via Subjects.
*
* @author guqing
* @since 2.0.0
*/
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@GVK(group = GROUP,
version = VERSION,
kind = KIND,
plural = "rolebindings",
singular = "rolebinding")
public class RoleBinding extends AbstractExtension {
public static final String GROUP = "";
public static final String VERSION = "v1alpha1";
public static final String KIND = "RoleBinding";
/**
* Subjects holds references to the objects the role applies to.
*/
List<Subject> subjects;
/**
* RoleRef can reference a Role in the current namespace or a ClusterRole in the global
* namespace.
* If the RoleRef cannot be resolved, the Authorizer must return an error.
*/
RoleRef roleRef;
/**
* RoleRef contains information that points to the role being used.
*
* @author guqing
* @since 2.0.0
*/
@Data
public static class RoleRef {
/**
* Kind is the type of resource being referenced.
*/
String kind;
/**
* Name is the name of resource being referenced.
*/
String name;
/**
* APIGroup is the group for the resource being referenced.
*/
String apiGroup;
}
/**
* @author guqing
* @since 2.0.0
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Subject {
/**
* Kind of object being referenced. Values defined by this API group are "User", "Group",
* and "ServiceAccount".
* If the Authorizer does not recognize the kind value, the Authorizer should report
* an error.
*/
String kind;
/**
* Name of the object being referenced.
*/
String name;
/**
* APIGroup holds the API group of the referenced subject.
* Defaults to "" for ServiceAccount subjects.
* Defaults to "rbac.authorization.halo.run" for User and Group subjects.
*/
String apiGroup;
public static Predicate<Subject> isUser(String username) {
return subject -> User.KIND.equals(subject.getKind())
&& User.GROUP.equals(subject.getApiGroup())
&& username.equals(subject.getName());
}
public static Predicate<Subject> containsUser(Set<String> usernames) {
return subject -> User.KIND.equals(subject.getKind())
&& User.GROUP.equals(subject.apiGroup)
&& usernames.contains(subject.getName());
}
@Override
public String toString() {
if (StringUtils.hasText(apiGroup)) {
return apiGroup + "/" + kind + "/" + name;
}
return kind + "/" + name;
}
}
public static RoleBinding create(String username, String roleName) {
var metadata = new Metadata();
metadata.setName(String.join("-", username, roleName, "binding"));
var roleRef = new RoleRef();
roleRef.setKind(Role.KIND);
roleRef.setName(roleName);
roleRef.setApiGroup(Role.GROUP);
var subject = new Subject();
subject.setKind(User.KIND);
subject.setName(username);
subject.setApiGroup(User.GROUP);
var binding = new RoleBinding();
binding.setMetadata(metadata);
binding.setRoleRef(roleRef);
// keep the subjects mutable
var subjects = new LinkedList<Subject>();
subjects.add(subject);
binding.setSubjects(subjects);
return binding;
}
public static Predicate<RoleBinding> containsUser(String username) {
return ExtensionOperator.<RoleBinding>isNotDeleted().and(
binding -> binding.getSubjects().stream()
.anyMatch(Subject.isUser(username)));
}
public static Predicate<RoleBinding> containsUser(Set<String> usernames) {
return ExtensionOperator.<RoleBinding>isNotDeleted()
.and(binding -> binding.getSubjects().stream()
.anyMatch(Subject.containsUser(usernames)));
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/Setting.java
================================================
package run.halo.app.core.extension;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import static run.halo.app.extension.GroupVersionKind.fromExtension;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import lombok.Data;
import lombok.EqualsAndHashCode;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
import run.halo.app.extension.GroupVersionKind;
/**
* {@link Setting} is a custom extension to generate forms based on configuration.
*
* @author guqing
* @since 2.0.0
*/
@Data
@EqualsAndHashCode(callSuper = true)
@GVK(group = "", version = "v1alpha1", kind = Setting.KIND,
plural = "settings", singular = "setting")
public class Setting extends AbstractExtension {
public static final String KIND = "Setting";
public static final GroupVersionKind GVK = fromExtension(Setting.class);
@Schema(requiredMode = REQUIRED)
private SettingSpec spec;
@Data
public static class SettingSpec {
@Schema(requiredMode = REQUIRED, minLength = 1)
private List<SettingForm> forms;
}
@Data
public static class SettingForm {
@Schema(requiredMode = REQUIRED)
private String group;
private String label;
@Schema(requiredMode = REQUIRED)
private List<Object> formSchema;
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/Theme.java
================================================
package run.halo.app.core.extension;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.NOT_REQUIRED;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import java.util.Objects;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.util.Assert;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
import run.halo.app.infra.ConditionList;
import run.halo.app.infra.model.License;
/**
* <p>Theme extension.</p>
*
* @author guqing
* @since 2.0.0
*/
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@GVK(group = "theme.halo.run", version = "v1alpha1", kind = Theme.KIND,
plural = "themes", singular = "theme")
public class Theme extends AbstractExtension {
public static final String KIND = "Theme";
public static final String THEME_NAME_LABEL = "theme.halo.run/theme-name";
@Schema(requiredMode = REQUIRED)
private ThemeSpec spec;
private ThemeStatus status;
@Data
@ToString
public static class ThemeSpec {
private static final String WILDCARD = "*";
@Schema(requiredMode = REQUIRED, minLength = 1)
private String displayName;
@Schema(requiredMode = REQUIRED)
private Author author;
private String description;
private String logo;
private String homepage;
private String repo;
private String issues;
private String version = WILDCARD;
@Schema(requiredMode = NOT_REQUIRED)
private String requires = WILDCARD;
private String settingName;
private String configMapName;
private List<License> license;
@Schema
private CustomTemplates customTemplates;
}
@Data
public static class ThemeStatus {
private ThemePhase phase;
private ConditionList conditions;
private String location;
}
/**
* Null-safe get {@link ConditionList} from theme status.
*
* @param theme theme must not be null
* @return condition list
*/
public static ConditionList nullSafeConditionList(Theme theme) {
Assert.notNull(theme, "The theme must not be null");
var status = Objects.requireNonNullElseGet(theme.getStatus(), ThemeStatus::new);
theme.setStatus(status);
var conditions = Objects.requireNonNullElseGet(status.getConditions(), ConditionList::new);
status.setConditions(conditions);
return conditions;
}
public enum ThemePhase {
READY,
FAILED,
UNKNOWN,
}
@Data
@ToString
public static class Author {
@Schema(requiredMode = REQUIRED, minLength = 1)
private String name;
private String website;
}
@Data
public static class CustomTemplates {
private List<TemplateDescriptor> post;
private List<TemplateDescriptor> category;
private List<TemplateDescriptor> page;
}
/**
* Type used to describe custom template page.
*
* @author guqing
* @since 2.0.0
*/
@Data
public static class TemplateDescriptor {
@Schema(requiredMode = REQUIRED, minLength = 1)
private String name;
private String description;
private String screenshot;
@Schema(requiredMode = REQUIRED, minLength = 1)
private String file;
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/User.java
================================================
package run.halo.app.core.extension;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import static run.halo.app.core.extension.User.GROUP;
import static run.halo.app.core.extension.User.KIND;
import static run.halo.app.core.extension.User.VERSION;
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.Instant;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
/**
* The extension represents user details of Halo.
*
* @author johnniang
*/
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@GVK(group = GROUP,
version = VERSION,
kind = KIND,
singular = "user",
plural = "users")
public class User extends AbstractExtension {
public static final String GROUP = "";
public static final String VERSION = "v1alpha1";
public static final String KIND = "User";
public static final String USER_RELATED_ROLES_INDEX = "roles";
public static final String ROLE_NAMES_ANNO = "rbac.authorization.halo.run/role-names";
public static final String EMAIL_TO_VERIFY = "halo.run/email-to-verify";
public static final String LAST_AVATAR_ATTACHMENT_NAME_ANNO =
"halo.run/last-avatar-attachment-name";
public static final String AVATAR_ATTACHMENT_NAME_ANNO = "halo.run/avatar-attachment-name";
public static final String HIDDEN_USER_LABEL = "halo.run/hidden-user";
public static final String REQUEST_TO_UPDATE = "halo.run/request-to-update";
@Schema(requiredMode = REQUIRED)
private UserSpec spec = new UserSpec();
private UserStatus status = new UserStatus();
@Data
public static class UserSpec {
@Schema(requiredMode = REQUIRED)
private String displayName;
private String avatar;
@Schema(requiredMode = REQUIRED)
private String email;
private boolean emailVerified;
private String phone;
private String password;
private String bio;
private Instant registeredAt;
private Boolean twoFactorAuthEnabled;
private String totpEncryptedSecret;
private Boolean disabled;
private Integer loginHistoryLimit;
}
@Data
public static class UserStatus {
private String permalink;
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/UserConnection.java
================================================
package run.halo.app.core.extension;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.Instant;
import lombok.Data;
import lombok.EqualsAndHashCode;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
import run.halo.app.extension.Metadata;
/**
* User connection extension.
*
* @author guqing
* @since 2.4.0
*/
@Data
@EqualsAndHashCode(callSuper = true)
@GVK(group = "auth.halo.run", version = "v1alpha1", kind = "UserConnection",
singular = "userconnection", plural = "userconnections")
public class UserConnection extends AbstractExtension {
@Schema(requiredMode = REQUIRED)
private UserConnectionSpec spec;
@Data
public static class UserConnectionSpec {
/**
* The name of the OAuth provider (e.g. Google, Facebook, Twitter).
*/
@Schema(requiredMode = REQUIRED)
private String registrationId;
/**
* The {@link Metadata#getName()} of the user associated with the OAuth connection.
*/
@Schema(requiredMode = REQUIRED)
private String username;
/**
* The unique identifier for the user's connection to the OAuth provider.
* for example, the user's GitHub id.
*/
@Schema(requiredMode = REQUIRED)
private String providerUserId;
/**
* The time when the user connection was last updated.
*/
private Instant updatedAt;
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/attachment/Attachment.java
================================================
package run.halo.app.core.extension.attachment;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import static run.halo.app.core.extension.attachment.Attachment.KIND;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.Map;
import java.util.Set;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.jspecify.annotations.Nullable;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@GVK(group = Constant.GROUP, version = Constant.VERSION, kind = KIND,
plural = "attachments", singular = "attachment")
public class Attachment extends AbstractExtension {
public static final String KIND = "Attachment";
@Schema(requiredMode = REQUIRED)
private AttachmentSpec spec;
private AttachmentStatus status;
@Data
public static class AttachmentSpec {
@Schema(description = "Display name of attachment")
private String displayName;
@Schema(description = "Group name")
private String groupName;
@Schema(description = "Policy name")
private String policyName;
@Schema(description = "Name of User who uploads the attachment")
private String ownerName;
@Schema(description = "Media type of attachment")
@Nullable
private String mediaType;
@Schema(description = "Size of attachment. Unit is Byte", minimum = "0")
private Long size;
@ArraySchema(
arraySchema = @Schema(description = "Tags of attachment"),
schema = @Schema(description = "Tag name"))
private Set<String> tags;
}
@Data
public static class AttachmentStatus {
@Schema(description = """
Permalink of attachment.
If it is in local storage, the public URL will be set.
If it is in s3 storage, the Object URL will be set.
""")
private String permalink;
private Map<String, String> thumbnails;
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/attachment/Constant.java
================================================
package run.halo.app.core.extension.attachment;
import run.halo.app.core.extension.attachment.endpoint.AttachmentHandler;
public enum Constant {
;
public static final String GROUP = "storage.halo.run";
public static final String VERSION = "v1alpha1";
/**
* The relative path starting from attachments folder is for deletion.
*/
public static final String LOCAL_REL_PATH_ANNO_KEY = GROUP + "/local-relative-path";
/**
* The encoded URI is for building external url.
*/
public static final String URI_ANNO_KEY = GROUP + "/uri";
/**
* Do not use this key to set external link. You could implement
* {@link AttachmentHandler#getPermalink} by your self.
* <p>
*/
public static final String EXTERNAL_LINK_ANNO_KEY = GROUP + "/external-link";
public static final String FINALIZER_NAME = "attachment-manager";
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/attachment/Group.java
================================================
package run.halo.app.core.extension.attachment;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import static run.halo.app.core.extension.attachment.Group.KIND;
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.Instant;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@GVK(group = Constant.GROUP, version = Constant.VERSION, kind = KIND,
plural = "groups", singular = "group")
public class Group extends AbstractExtension {
public static final String KIND = "Group";
public static final String HIDDEN_LABEL = "halo.run/hidden";
@Schema(requiredMode = REQUIRED)
private GroupSpec spec;
private GroupStatus status;
@Data
public static class GroupSpec {
@Schema(requiredMode = REQUIRED, description = "Display name of group")
private String displayName;
}
@Data
public static class GroupStatus {
@Schema(description = "Update timestamp of the group")
private Instant updateTimestamp;
@Schema(description = "Total of attachments under the current group", minimum = "0")
private Long totalAttachments;
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/attachment/Policy.java
================================================
package run.halo.app.core.extension.attachment;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import static run.halo.app.core.extension.attachment.Policy.KIND;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@GVK(group = Constant.GROUP, version = Constant.VERSION, kind = KIND,
plural = "policies", singular = "policy")
public class Policy extends AbstractExtension {
public static final String POLICY_OWNER_LABEL = "storage.halo.run/policy-owner";
public static final String KIND = "Policy";
@Schema(requiredMode = REQUIRED)
private PolicySpec spec;
@Data
public static class PolicySpec {
@Schema(requiredMode = REQUIRED, description = "Display name of policy")
private String displayName;
@Schema(requiredMode = REQUIRED, description = "Reference name of PolicyTemplate")
private String templateName;
@Schema(description = "Reference name of ConfigMap extension")
private String configMapName;
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/attachment/PolicyTemplate.java
================================================
package run.halo.app.core.extension.attachment;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import static run.halo.app.core.extension.attachment.PolicyTemplate.KIND;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@GVK(group = Constant.GROUP, version = Constant.VERSION, kind = KIND,
plural = "policytemplates", singular = "policytemplate")
public class PolicyTemplate extends AbstractExtension {
public static final String KIND = "PolicyTemplate";
private PolicyTemplateSpec spec;
@Data
public static class PolicyTemplateSpec {
private String displayName;
@Schema(requiredMode = REQUIRED)
private String settingName;
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/attachment/endpoint/AttachmentHandler.java
================================================
package run.halo.app.core.extension.attachment.endpoint;
import java.net.URI;
import java.time.Duration;
import java.util.Map;
import org.jspecify.annotations.Nullable;
import org.pf4j.ExtensionPoint;
import org.springframework.http.codec.multipart.FilePart;
import reactor.core.publisher.Mono;
import run.halo.app.core.attachment.ThumbnailSize;
import run.halo.app.core.extension.attachment.Attachment;
import run.halo.app.core.extension.attachment.Group;
import run.halo.app.core.extension.attachment.Policy;
import run.halo.app.extension.ConfigMap;
public interface AttachmentHandler extends ExtensionPoint {
Mono<Attachment> upload(UploadContext context);
Mono<Attachment> delete(DeleteContext context);
/**
* Gets a shared URL which could be accessed publicly.
* 1. If the attachment is in local storage, the permalink will be returned.
* 2. If the attachment is in s3 storage, the Presigned URL will be returned.
* <p>
* Please note that the default implementation is only for back compatibility.
*
* @param attachment contains detail of attachment.
* @param policy is storage policy.
* @param configMap contains configuration needed by handler.
* @param ttl indicates how long the URL is alive.
* @return shared URL which could be accessed publicly. Might be relative URL.
*/
default Mono<URI> getSharedURL(Attachment attachment,
Policy policy,
ConfigMap configMap,
Duration ttl) {
return Mono.empty();
}
/**
* Gets a permalink representing a unique attachment.
* If the attachment is in local storage, the permalink will be returned.
* If the attachment is in s3 storage, the Object URL will be returned.
* <p>
* Please note that the default implementation is only for back compatibility.
*
* @param attachment contains detail of attachment.
* @param policy is storage policy.
* @param configMap contains configuration needed by handler.
* @return permalink representing a unique attachment. Might be relative URL.
*/
default Mono<URI> getPermalink(Attachment attachment,
Policy policy,
ConfigMap configMap) {
return Mono.empty();
}
/**
* Gets thumbnail links for given attachment.
*
* @param attachment the attachment
* @param policy the policy
* @param configMap the config map
* @return a map of thumbnail sizes to their respective URIs
*/
default Mono<Map<ThumbnailSize, URI>> getThumbnailLinks(Attachment attachment,
Policy policy,
ConfigMap configMap) {
return Mono.empty();
}
interface UploadContext {
FilePart file();
Policy policy();
ConfigMap configMap();
/**
* Gets the group info if available.
*
* @return the group info, or null if not available
*/
@Nullable
default Group group() {
return null;
}
}
interface DeleteContext {
Attachment attachment();
Policy policy();
ConfigMap configMap();
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/attachment/endpoint/DeleteOption.java
================================================
package run.halo.app.core.extension.attachment.endpoint;
import run.halo.app.core.extension.attachment.Attachment;
import run.halo.app.core.extension.attachment.Policy;
import run.halo.app.extension.ConfigMap;
public record DeleteOption(Attachment attachment, Policy policy, ConfigMap configMap)
implements AttachmentHandler.DeleteContext {
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/attachment/endpoint/SimpleFilePart.java
================================================
package run.halo.app.core.extension.attachment.endpoint;
import java.nio.file.Path;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.codec.multipart.FilePart;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* SimpleFilePart is an adapter of simple data for uploading.
*
* @param filename is name of the attachment file.
* @param content is binary data of the attachment file.
* @param mediaType is media type of the attachment file.
*/
public record SimpleFilePart(
String filename,
Flux<DataBuffer> content,
MediaType mediaType
) implements FilePart {
@Override
public Mono<Void> transferTo(Path dest) {
return DataBufferUtils.write(content(), dest);
}
@Override
public String name() {
return filename();
}
@Override
public HttpHeaders headers() {
var headers = new HttpHeaders();
headers.setContentType(mediaType);
return HttpHeaders.readOnlyHttpHeaders(headers);
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/attachment/endpoint/UploadOption.java
================================================
package run.halo.app.core.extension.attachment.endpoint;
import lombok.Builder;
import org.jspecify.annotations.Nullable;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.MediaType;
import org.springframework.http.codec.multipart.FilePart;
import reactor.core.publisher.Flux;
import run.halo.app.core.extension.attachment.Group;
import run.halo.app.core.extension.attachment.Policy;
import run.halo.app.extension.ConfigMap;
@Builder
public record UploadOption(FilePart file,
Policy policy,
ConfigMap configMap,
@Nullable Group group) implements AttachmentHandler.UploadContext {
public static UploadOption from(String filename,
Flux<DataBuffer> content,
MediaType mediaType,
Policy policy,
ConfigMap configMap) {
var filePart = new SimpleFilePart(filename, content, mediaType);
return new UploadOption(filePart, policy, configMap, null);
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/content/Category.java
================================================
package run.halo.app.core.extension.content;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.NOT_REQUIRED;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import static run.halo.app.core.extension.content.Category.KIND;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
import run.halo.app.extension.GroupVersionKind;
/**
* @author guqing
* @see <a href="https://github.com/halo-dev/halo/issues/2322">issue#2322</a>
* @since 2.0.0
*/
@Data
@ToString(callSuper = true)
@GVK(group = Constant.GROUP, version = Constant.VERSION,
kind = KIND, plural = "categories", singular = "category")
@EqualsAndHashCode(callSuper = true)
public class Category extends AbstractExtension {
public static final String KIND = "Category";
public static final String LAST_HIDDEN_STATE_ANNO = "content.halo.run/last-hidden-state";
public static final GroupVersionKind GVK = GroupVersionKind.fromExtension(Category.class);
@Schema(requiredMode = REQUIRED)
private CategorySpec spec;
@Schema
private CategoryStatus status;
@JsonIgnore
public boolean isDeleted() {
return getMetadata().getDeletionTimestamp() != null;
}
@Data
public static class CategorySpec {
@Schema(requiredMode = REQUIRED, minLength = 1)
private String displayName;
@Schema(requiredMode = REQUIRED, minLength = 1)
private String slug;
private String description;
private String cover;
@Schema(requiredMode = NOT_REQUIRED, maxLength = 255)
private String template;
/**
* <p>Used to specify the template for the posts associated with the category.</p>
* <p>The priority is not as high as that of the post.</p>
* <p>If the post also specifies a template, the post's template will prevail.</p>
*/
@Schema(requiredMode = NOT_REQUIRED, maxLength = 255)
private String postTemplate;
@Schema(requiredMode = REQUIRED, defaultValue = "0")
private Integer priority;
private List<String> children;
/**
* <p>if a category is queried for related posts, the default behavior is to
* query all posts under the category including its subcategories, but if this field is
* set to true, cascade query behavior will be terminated here.</p>
* <p>For example, if a category has subcategories A and B, and A has subcategories C and
* D and C marked this field as true, when querying posts under A category,all posts under A
* and B will be queried, but C and D will not be queried.</p>
*/
private boolean preventParentPostCascadeQuery;
/**
* <p>Whether to hide the category from the category list.</p>
* <p>When set to true, the category including its subcategories and related posts will
* not be displayed in the category list, but it can still be accessed by permalink.</p>
* <p>Limitation: It only takes effect on the theme-side categorized list and it only
* allows to be set to true on the first level(root node) of categories.</p>
*/
private boolean hideFromList;
}
@JsonIgnore
public CategoryStatus getStatusOrDefault() {
if (this.status == null) {
this.status = new CategoryStatus();
}
return this.status;
}
@Data
public static class CategoryStatus {
private String permalink;
/**
* 包括当前和其下所有层级的文章数量 (depth=max).
*/
public Integer postCount;
/**
* 包括当前和其下所有层级的已发布且公开的文章数量 (depth=max).
*/
public Integer visiblePostCount;
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/content/Comment.java
================================================
package run.halo.app.core.extension.content;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
import run.halo.app.extension.Ref;
/**
* @author guqing
* @see <a href="https://github.com/halo-dev/halo/issues/2322">issue#2322</a>
* @since 2.0.0
*/
@Data
@ToString(callSuper = true)
@GVK(group = Constant.GROUP, version = Constant.VERSION, kind = Comment.KIND,
plural = "comments", singular = "comment")
@EqualsAndHashCode(callSuper = true)
public class Comment extends AbstractExtension {
public static final String KIND = "Comment";
public static final String REQUIRE_SYNC_ON_STARTUP_INDEX_NAME = "requireSyncOnStartup";
@Schema(requiredMode = REQUIRED)
private CommentSpec spec;
@Schema
private CommentStatus status;
@JsonIgnore
public CommentStatus getStatusOrDefault() {
if (this.status == null) {
this.status = new CommentStatus();
}
return this.status;
}
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public static class CommentSpec extends BaseCommentSpec {
@Schema(requiredMode = REQUIRED)
private Ref subjectRef;
private Instant lastReadTime;
}
@Data
public static class BaseCommentSpec {
@Schema(requiredMode = REQUIRED, minLength = 1)
private String raw;
@Schema(requiredMode = REQUIRED, minLength = 1)
private String content;
@Schema(requiredMode = REQUIRED)
private CommentOwner owner;
private String userAgent;
private String ipAddress;
private Instant approvedTime;
/**
* The user-defined creation time default is <code>metadata.creationTimestamp</code>.
*/
private Instant creationTime;
@Schema(requiredMode = REQUIRED, defaultValue = "0")
private Integer priority;
@Schema(requiredMode = REQUIRED, defaultValue = "false")
private Boolean top;
@Schema(requiredMode = REQUIRED, defaultValue = "true")
private Boolean allowNotification;
@Schema(requiredMode = REQUIRED, defaultValue = "false")
private Boolean approved;
@Schema(requiredMode = REQUIRED, defaultValue = "false")
private Boolean hidden;
}
@Data
public static class CommentOwner {
public static final String KIND_EMAIL = "Email";
public static final String AVATAR_ANNO = "avatar";
public static final String WEBSITE_ANNO = "website";
public static final String EMAIL_HASH_ANNO = "email-hash";
@Schema(requiredMode = REQUIRED, minLength = 1)
private String kind;
@Schema(requiredMode = REQUIRED, maxLength = 64)
private String name;
private String displayName;
private Map<String, String> annotations;
@Nullable
@JsonIgnore
public String getAnnotation(String key) {
return annotations == null ? null : annotations.get(key);
}
public static String ownerIdentity(String kind, String name) {
return kind + "#" + name;
}
}
@Data
public static class CommentStatus {
private Instant lastReplyTime;
private Integer replyCount;
private Integer visibleReplyCount;
private Integer unreadReplyCount;
private Boolean hasNewReply;
private Long observedVersion;
}
public static String toSubjectRefKey(Ref subjectRef) {
return subjectRef.getGroup() + "/" + subjectRef.getKind() + "/" + subjectRef.getName();
}
public static int getUnreadReplyCount(List<Reply> replies, Instant lastReadTime) {
if (CollectionUtils.isEmpty(replies)) {
return 0;
}
long unreadReplyCount = replies.stream()
.filter(existingReply -> {
if (lastReadTime == null) {
return true;
}
Instant creationTime = defaultIfNull(existingReply.getSpec().getCreationTime(),
existingReply.getMetadata().getCreationTimestamp());
return creationTime.isAfter(lastReadTime);
})
.count();
return (int) unreadReplyCount;
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/content/Constant.java
================================================
package run.halo.app.core.extension.content;
public enum Constant {
;
public static final String GROUP = "content.halo.run";
public static final String VERSION = "v1alpha1";
public static final String LAST_READ_TIME_ANNO = "content.halo.run/last-read-time";
public static final String PERMALINK_PATTERN_ANNO = "content.halo.run/permalink-pattern";
public static final String CHECKSUM_CONFIG_ANNO = "checksum/config";
public static final String CONTENT_CHECKSUM_ANNO = "checksum/content";
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/content/Post.java
================================================
package run.halo.app.core.extension.content;
import static java.lang.Boolean.parseBoolean;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
import run.halo.app.extension.GroupVersionKind;
import run.halo.app.extension.MetadataOperator;
import run.halo.app.infra.ConditionList;
/**
* <p>Post extension.</p>
*
* @author guqing
* @see <a href="https://github.com/halo-dev/halo/issues/2322">issue#2322</a>
* @since 2.0.0
*/
@Data
@ToString(callSuper = true)
@GVK(group = Constant.GROUP, version = Constant.VERSION, kind = Post.KIND,
plural = "posts", singular = "post")
@EqualsAndHashCode(callSuper = true)
public class Post extends AbstractExtension {
public static final String KIND = "Post";
public static final String REQUIRE_SYNC_ON_STARTUP_INDEX_NAME = "requireSyncOnStartup";
public static final GroupVersionKind GVK = GroupVersionKind.fromExtension(Post.class);
public static final String CATEGORIES_ANNO = "content.halo.run/categories";
public static final String LAST_RELEASED_SNAPSHOT_ANNO =
"content.halo.run/last-released-snapshot";
public static final String LAST_ASSOCIATED_TAGS_ANNO = "content.halo.run/last-associated-tags";
public static final String LAST_ASSOCIATED_CATEGORIES_ANNO =
"content.halo.run/last-associated-categories";
public static final String STATS_ANNO = "content.halo.run/stats";
/**
* <p>The key of the label that indicates that the post is scheduled to be published.</p>
* <p>Can be used to query posts that are scheduled to be published.</p>
*/
public static final String SCHEDULING_PUBLISH_LABEL = "content.halo.run/scheduling-publish";
public static final String DELETED_LABEL = "content.halo.run/deleted";
public static final String PUBLISHED_LABEL = "content.halo.run/published";
public static final String OWNER_LABEL = "content.halo.run/owner";
public static final String VISIBLE_LABEL = "content.halo.run/visible";
public static final String ARCHIVE_YEAR_LABEL = "content.halo.run/archive-year";
public static final String ARCHIVE_MONTH_LABEL = "content.halo.run/archive-month";
public static final String ARCHIVE_DAY_LABEL = "content.halo.run/archive-day";
@Schema(requiredMode = RequiredMode.REQUIRED)
private PostSpec spec;
@Schema
private PostStatus status;
@JsonIgnore
public PostStatus getStatusOrDefault() {
if (this.status == null) {
this.status = new PostStatus();
}
return status;
}
@JsonIgnore
public boolean isDeleted() {
return Objects.equals(true, spec.getDeleted())
|| getMetadata().getDeletionTimestamp() != null;
}
@JsonIgnore
public boolean isPublished() {
return isPublished(this.getMetadata());
}
public static boolean isPublished(MetadataOperator metadata) {
var labels = metadata.getLabels();
return labels != null && parseBoolean(labels.getOrDefault(PUBLISHED_LABEL, "false"));
}
public static boolean isRecycled(MetadataOperator metadata) {
var labels = metadata.getLabels();
return labels != null && parseBoolean(labels.getOrDefault(DELETED_LABEL, "false"));
}
public static boolean isPublic(PostSpec spec) {
return spec.getVisible() == null || VisibleEnum.PUBLIC.equals(spec.getVisible());
}
@Data
public static class PostSpec {
@Schema(requiredMode = RequiredMode.REQUIRED, minLength = 1)
private String title;
@Schema(requiredMode = RequiredMode.REQUIRED, minLength = 1)
private String slug;
/**
* 文章引用到的已发布的内容,用于主题端显示.
*/
private String releaseSnapshot;
private String headSnapshot;
private String baseSnapshot;
private String owner;
private String template;
private String cover;
@Schema(requiredMode = RequiredMode.REQUIRED, defaultValue = "false")
private Boolean deleted;
@Schema(requiredMode = RequiredMode.REQUIRED, defaultValue = "false")
private Boolean publish;
private Instant publishTime;
@Schema(requiredMode = RequiredMode.REQUIRED, defaultValue = "false")
private Boolean pinned;
@Schema(requiredMode = RequiredMode.REQUIRED, defaultValue = "true")
private Boolean allowComment;
@Schema(requiredMode = RequiredMode.REQUIRED, defaultValue = "PUBLIC")
private VisibleEnum visible;
@Schema(requiredMode = RequiredMode.REQUIRED, defaultValue = "0")
private Integer priority;
@Schema(requiredMode = RequiredMode.REQUIRED)
private Excerpt excerpt;
private List<String> categories;
private List<String> tags;
private List<Map<String, String>> htmlMetas;
}
@Data
public static class PostStatus {
private String phase;
@Schema
private ConditionList conditions;
private String permalink;
private String excerpt;
private Boolean inProgress;
private Integer commentsCount;
private List<String> contributors;
/**
* see {@link Category.CategorySpec#isHideFromList()}.
*/
private Boolean hideFromList;
private Instant lastModifyTime;
private Long observedVersion;
@JsonIgnore
public ConditionList getConditionsOrDefault() {
if (this.conditions == null) {
this.conditions = new ConditionList();
}
return conditions;
}
}
@Data
public static class Excerpt {
@Schema(requiredMode = RequiredMode.REQUIRED, defaultValue = "true")
private Boolean autoGenerate;
private String raw;
}
public enum PostPhase {
DRAFT,
PENDING_APPROVAL,
PUBLISHED,
FAILED;
/**
* Convert string value to {@link PostPhase}.
*
* @param value enum value string
* @return {@link PostPhase} if found, otherwise null
*/
public static PostPhase from(String value) {
for (PostPhase phase : PostPhase.values()) {
if (phase.name().equalsIgnoreCase(value)) {
return phase;
}
}
return null;
}
}
public enum VisibleEnum {
PUBLIC,
INTERNAL,
PRIVATE;
/**
* Convert value string to {@link VisibleEnum}.
*
* @param value enum value string
* @return {@link VisibleEnum} if found, otherwise null
*/
public static VisibleEnum from(String value) {
for (VisibleEnum visible : VisibleEnum.values()) {
if (visible.name().equalsIgnoreCase(value)) {
return visible;
}
}
return null;
}
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/content/Reply.java
================================================
package run.halo.app.core.extension.content;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import org.springframework.lang.NonNull;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
/**
* @author guqing
* @see <a href="https://github.com/halo-dev/halo/issues/2322">issue#2322</a>
* @since 2.0.0
*/
@Data
@ToString(callSuper = true)
@GVK(group = Constant.GROUP, version = Constant.VERSION, kind = Reply.KIND,
plural = "replies", singular = "reply")
@EqualsAndHashCode(callSuper = true)
public class Reply extends AbstractExtension {
public static final String KIND = "Reply";
public static final String REQUIRE_SYNC_ON_STARTUP_INDEX_NAME = "requireSyncOnStartup";
@Schema(requiredMode = REQUIRED)
private ReplySpec spec;
@Schema
@Getter(onMethod_ = @NonNull)
private Status status = new Status();
@Data
@EqualsAndHashCode(callSuper = true)
public static class ReplySpec extends Comment.BaseCommentSpec {
@Schema(requiredMode = REQUIRED, minLength = 1)
private String commentName;
private String quoteReply;
}
@Data
@Schema(name = "ReplyStatus")
public static class Status {
private Long observedVersion;
}
public void setStatus(Status status) {
this.status = status == null ? new Status() : status;
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/content/SinglePage.java
================================================
package run.halo.app.core.extension.content;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
import run.halo.app.extension.GroupVersionKind;
import run.halo.app.extension.MetadataUtil;
/**
* <p>Single page extension.</p>
*
* @author guqing
* @since 2.0.0
*/
@Data
@ToString(callSuper = true)
@GVK(group = Constant.GROUP, version = Constant.VERSION, kind = SinglePage.KIND,
plural = "singlepages", singular = "singlepage")
@EqualsAndHashCode(callSuper = true)
public class SinglePage extends AbstractExtension {
public static final String KIND = "SinglePage";
public static final GroupVersionKind GVK = GroupVersionKind.fromExtension(SinglePage.class);
public static final String DELETED_LABEL = "content.halo.run/deleted";
public static final String PUBLISHED_LABEL = "content.halo.run/published";
public static final String LAST_RELEASED_SNAPSHOT_ANNO =
"content.halo.run/last-released-snapshot";
public static final String OWNER_LABEL = "content.halo.run/owner";
public static final String VISIBLE_LABEL = "content.halo.run/visible";
@Schema(requiredMode = REQUIRED)
private SinglePageSpec spec;
@Schema
private SinglePageStatus status;
@JsonIgnore
public SinglePageStatus getStatusOrDefault() {
if (this.status == null) {
this.status = new SinglePageStatus();
}
return this.status;
}
@JsonIgnore
public boolean isPublished() {
Map<String, String> labels = getMetadata().getLabels();
return labels != null && labels.getOrDefault(PUBLISHED_LABEL, "false").equals("true");
}
@Data
public static class SinglePageSpec {
@Schema(requiredMode = REQUIRED, minLength = 1)
private String title;
@Schema(requiredMode = REQUIRED, minLength = 1)
private String slug;
/**
* 引用到的已发布的内容,用于主题端显示.
*/
private String releaseSnapshot;
private String headSnapshot;
private String baseSnapshot;
private String owner;
private String template;
private String cover;
@Schema(requiredMode = REQUIRED, defaultValue = "false")
private Boolean deleted;
@Schema(requiredMode = REQUIRED, defaultValue = "false")
private Boolean publish;
private Instant publishTime;
@Schema(requiredMode = REQUIRED, defaultValue = "false")
private Boolean pinned;
@Schema(requiredMode = REQUIRED, defaultValue = "true")
private Boolean allowComment;
@Schema(requiredMode = REQUIRED, defaultValue = "PUBLIC")
private Post.VisibleEnum visible;
@Schema(requiredMode = REQUIRED, defaultValue = "0")
private Integer priority;
@Schema(requiredMode = REQUIRED)
private Post.Excerpt excerpt;
private List<Map<String, String>> htmlMetas;
}
@Data
@EqualsAndHashCode(callSuper = true)
public static class SinglePageStatus extends Post.PostStatus {
}
public static void changePublishedState(SinglePage page, boolean value) {
Map<String, String> labels = MetadataUtil.nullSafeLabels(page);
labels.put(PUBLISHED_LABEL, String.valueOf(value));
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/content/Snapshot.java
================================================
package run.halo.app.core.extension.content;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.Instant;
import java.util.LinkedHashSet;
import java.util.Set;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.lang.NonNull;
import org.springframework.util.Assert;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
import run.halo.app.extension.Ref;
/**
* @author guqing
* @see <a href="https://github.com/halo-dev/halo/issues/2322">issue#2322</a>
* @since 2.0.0
*/
@Data
@ToString(callSuper = true)
@GVK(group = Constant.GROUP, version = Constant.VERSION, kind = Snapshot.KIND,
plural = "snapshots", singular = "snapshot")
@EqualsAndHashCode(callSuper = true)
public class Snapshot extends AbstractExtension {
public static final String KIND = "Snapshot";
public static final String KEEP_RAW_ANNO = "content.halo.run/keep-raw";
public static final String PATCHED_CONTENT_ANNO = "content.halo.run/patched-content";
public static final String PATCHED_RAW_ANNO = "content.halo.run/patched-raw";
@Schema(requiredMode = REQUIRED)
private SnapShotSpec spec;
@Data
public static class SnapShotSpec {
@Schema(requiredMode = REQUIRED)
private Ref subjectRef;
/**
* such as: markdown | html | json | asciidoc | latex.
*/
@Schema(requiredMode = REQUIRED, minLength = 1, maxLength = 50)
private String rawType;
private String rawPatch;
private String contentPatch;
private String parentSnapshotName;
private Instant lastModifyTime;
@Schema(requiredMode = REQUIRED, minLength = 1)
private String owner;
private Set<String> contributors;
}
public static void addContributor(Snapshot snapshot, String name) {
Assert.notNull(name, "The username must not be null.");
Set<String> contributors = snapshot.getSpec().getContributors();
if (contributors == null) {
contributors = new LinkedHashSet<>();
snapshot.getSpec().setContributors(contributors);
}
contributors.add(name);
}
/**
* Check if the given snapshot is a base snapshot.
*
* @param snapshot must not be null.
* @return true if the given snapshot is a base snapshot; false otherwise.
*/
public static boolean isBaseSnapshot(@NonNull Snapshot snapshot) {
var annotations = snapshot.getMetadata().getAnnotations();
if (annotations == null) {
return false;
}
return Boolean.parseBoolean(annotations.get(Snapshot.KEEP_RAW_ANNO));
}
public static String toSubjectRefKey(Ref subjectRef) {
return subjectRef.getGroup() + "/" + subjectRef.getKind() + "/" + subjectRef.getName();
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/content/Tag.java
================================================
package run.halo.app.core.extension.content;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
import run.halo.app.extension.GroupVersionKind;
/**
* @author guqing
* @see <a href="https://github.com/halo-dev/halo/issues/2322">issue#2322</a>
* @since 2.0.0
*/
@Data
@ToString(callSuper = true)
@GVK(group = Constant.GROUP, version = Constant.VERSION,
kind = Tag.KIND, plural = "tags", singular = "tag")
@EqualsAndHashCode(callSuper = true)
public class Tag extends AbstractExtension {
public static final String KIND = "Tag";
public static final GroupVersionKind GVK = GroupVersionKind.fromExtension(Tag.class);
public static final String REQUIRE_SYNC_ON_STARTUP_INDEX_NAME = "requireSyncOnStartup";
@Schema(requiredMode = REQUIRED)
private TagSpec spec;
@Schema
private TagStatus status;
@Data
public static class TagSpec {
@Schema(requiredMode = REQUIRED, minLength = 1)
private String displayName;
@Schema(requiredMode = REQUIRED, minLength = 1)
private String slug;
private String description;
/**
* Color regex explanation.
* <pre>
* ^ # start of the line
* # # start with a number sign `#`
* ( # start of (group 1)
* [a-fA-F0-9]{6} # support z-f, A-F and 0-9, with a length of 6
* | # or
* [a-fA-F0-9]{3} # support z-f, A-F and 0-9, with a length of 3
* ) # end of (group 1)
* $ # end of the line
* </pre>
*/
@Schema(pattern = "^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$")
private String color;
private String cover;
}
@JsonIgnore
public TagStatus getStatusOrDefault() {
if (this.status == null) {
this.status = new TagStatus();
}
return this.status;
}
@Data
public static class TagStatus {
private String permalink;
public Integer visiblePostCount;
public Integer postCount;
private Long observedVersion;
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/endpoint/CustomEndpoint.java
================================================
package run.halo.app.core.extension.endpoint;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerResponse;
import run.halo.app.extension.GroupVersion;
/**
* RouterFunction provider for custom endpoints.
*
* @author johnniang
*/
public interface CustomEndpoint {
RouterFunction<ServerResponse> endpoint();
default GroupVersion groupVersion() {
return GroupVersion.parseAPIVersion("api.console.halo.run/v1alpha1");
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/endpoint/SortResolver.java
================================================
package run.halo.app.core.extension.endpoint;
import org.springframework.core.MethodParameter;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.ReactiveSortHandlerMethodArgumentResolver;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.web.server.ServerWebExchange;
public interface SortResolver {
SortResolver defaultInstance = new DefaultSortResolver();
@NonNull
Sort resolve(@NonNull ServerWebExchange exchange);
class DefaultSortResolver extends ReactiveSortHandlerMethodArgumentResolver
implements SortResolver {
@Override
@NonNull
protected Sort getDefaultFromAnnotationOrFallback(@Nullable MethodParameter parameter) {
return Sort.unsorted();
}
@Override
public Sort resolve(ServerWebExchange exchange) {
return resolveArgumentValue(null, null, exchange);
}
}
}
================================================
FILE: api/src/main/java/run/halo/app/core/extension/n
gitextract_qe2hhq1p/
├── .dockerignore
├── .editorconfig
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.en.yml
│ │ ├── bug_report.zh.yml
│ │ ├── config.yml
│ │ ├── feature_request.en.yml
│ │ └── feature_request.zh.yml
│ ├── actions/
│ │ ├── docker-buildx-push/
│ │ │ └── action.yaml
│ │ └── setup-env/
│ │ └── action.yaml
│ ├── pull_request_template.md
│ └── workflows/
│ ├── halo.yaml
│ ├── openapi-check.yaml
│ ├── packages-preview-release.yaml
│ ├── release-ui-packages.yaml
│ └── stale-issues.yaml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── OWNERS
├── README.md
├── SECURITY.md
├── api/
│ ├── build.gradle
│ └── src/
│ ├── main/
│ │ └── java/
│ │ └── run/
│ │ └── halo/
│ │ └── app/
│ │ ├── content/
│ │ │ ├── ContentWrapper.java
│ │ │ ├── ExcerptGenerator.java
│ │ │ ├── PatchUtils.java
│ │ │ ├── PostContentService.java
│ │ │ └── comment/
│ │ │ └── CommentSubject.java
│ │ ├── core/
│ │ │ ├── attachment/
│ │ │ │ ├── ThumbnailProvider.java
│ │ │ │ └── ThumbnailSize.java
│ │ │ ├── endpoint/
│ │ │ │ └── WebSocketEndpoint.java
│ │ │ ├── extension/
│ │ │ │ ├── AnnotationSetting.java
│ │ │ │ ├── AuthProvider.java
│ │ │ │ ├── Counter.java
│ │ │ │ ├── Device.java
│ │ │ │ ├── Menu.java
│ │ │ │ ├── MenuItem.java
│ │ │ │ ├── Plugin.java
│ │ │ │ ├── RememberMeToken.java
│ │ │ │ ├── ReverseProxy.java
│ │ │ │ ├── Role.java
│ │ │ │ ├── RoleBinding.java
│ │ │ │ ├── Setting.java
│ │ │ │ ├── Theme.java
│ │ │ │ ├── User.java
│ │ │ │ ├── UserConnection.java
│ │ │ │ ├── attachment/
│ │ │ │ │ ├── Attachment.java
│ │ │ │ │ ├── Constant.java
│ │ │ │ │ ├── Group.java
│ │ │ │ │ ├── Policy.java
│ │ │ │ │ ├── PolicyTemplate.java
│ │ │ │ │ └── endpoint/
│ │ │ │ │ ├── AttachmentHandler.java
│ │ │ │ │ ├── DeleteOption.java
│ │ │ │ │ ├── SimpleFilePart.java
│ │ │ │ │ └── UploadOption.java
│ │ │ │ ├── content/
│ │ │ │ │ ├── Category.java
│ │ │ │ │ ├── Comment.java
│ │ │ │ │ ├── Constant.java
│ │ │ │ │ ├── Post.java
│ │ │ │ │ ├── Reply.java
│ │ │ │ │ ├── SinglePage.java
│ │ │ │ │ ├── Snapshot.java
│ │ │ │ │ └── Tag.java
│ │ │ │ ├── endpoint/
│ │ │ │ │ ├── CustomEndpoint.java
│ │ │ │ │ └── SortResolver.java
│ │ │ │ ├── notification/
│ │ │ │ │ ├── Notification.java
│ │ │ │ │ ├── NotificationTemplate.java
│ │ │ │ │ ├── NotifierDescriptor.java
│ │ │ │ │ ├── Reason.java
│ │ │ │ │ ├── ReasonType.java
│ │ │ │ │ └── Subscription.java
│ │ │ │ └── service/
│ │ │ │ └── AttachmentService.java
│ │ │ └── user/
│ │ │ └── service/
│ │ │ ├── RoleService.java
│ │ │ ├── SignUpData.java
│ │ │ ├── UserPostCreatingHandler.java
│ │ │ ├── UserPreCreatingHandler.java
│ │ │ └── UserService.java
│ │ ├── event/
│ │ │ ├── post/
│ │ │ │ ├── PostDeletedEvent.java
│ │ │ │ ├── PostEvent.java
│ │ │ │ ├── PostPublishedEvent.java
│ │ │ │ ├── PostUnpublishedEvent.java
│ │ │ │ ├── PostUpdatedEvent.java
│ │ │ │ └── PostVisibleChangedEvent.java
│ │ │ └── user/
│ │ │ ├── UserConnectionDisconnectedEvent.java
│ │ │ ├── UserLoginEvent.java
│ │ │ └── UserLogoutEvent.java
│ │ ├── extension/
│ │ │ ├── AbstractExtension.java
│ │ │ ├── Comparators.java
│ │ │ ├── ConfigMap.java
│ │ │ ├── DefaultExtensionMatcher.java
│ │ │ ├── Extension.java
│ │ │ ├── ExtensionClient.java
│ │ │ ├── ExtensionMatcher.java
│ │ │ ├── ExtensionOperator.java
│ │ │ ├── ExtensionUtil.java
│ │ │ ├── GVK.java
│ │ │ ├── GroupKind.java
│ │ │ ├── GroupVersion.java
│ │ │ ├── GroupVersionKind.java
│ │ │ ├── JsonExtension.java
│ │ │ ├── ListOptions.java
│ │ │ ├── ListResult.java
│ │ │ ├── Metadata.java
│ │ │ ├── MetadataOperator.java
│ │ │ ├── MetadataUtil.java
│ │ │ ├── PageRequest.java
│ │ │ ├── PageRequestImpl.java
│ │ │ ├── ReactiveExtensionClient.java
│ │ │ ├── Ref.java
│ │ │ ├── Scheme.java
│ │ │ ├── SchemeManager.java
│ │ │ ├── Secret.java
│ │ │ ├── Unstructured.java
│ │ │ ├── Watcher.java
│ │ │ ├── WatcherExtensionMatchers.java
│ │ │ ├── WatcherPredicates.java
│ │ │ ├── controller/
│ │ │ │ ├── Controller.java
│ │ │ │ ├── ControllerBuilder.java
│ │ │ │ ├── DefaultController.java
│ │ │ │ ├── DefaultQueue.java
│ │ │ │ ├── ExtensionWatcher.java
│ │ │ │ ├── Reconciler.java
│ │ │ │ ├── RequestQueue.java
│ │ │ │ ├── RequestSynchronizer.java
│ │ │ │ ├── RequeueException.java
│ │ │ │ └── Synchronizer.java
│ │ │ ├── exception/
│ │ │ │ ├── ExtensionException.java
│ │ │ │ ├── NotImplementedException.java
│ │ │ │ └── SchemeNotFoundException.java
│ │ │ ├── index/
│ │ │ │ ├── AbstractValueIndexSpecBuilder.java
│ │ │ │ ├── DefaultIndexAttribute.java
│ │ │ │ ├── IndexAttribute.java
│ │ │ │ ├── IndexAttributeFactory.java
│ │ │ │ ├── IndexSpec.java
│ │ │ │ ├── IndexSpecBuilder.java
│ │ │ │ ├── IndexSpecs.java
│ │ │ │ ├── IndexedQueryEngine.java
│ │ │ │ ├── KeyComparator.java
│ │ │ │ ├── MultiValueBuilder.java
│ │ │ │ ├── MultiValueIndexSpec.java
│ │ │ │ ├── MultiValueIndexSpecBuilder.java
│ │ │ │ ├── SingleValueBuilder.java
│ │ │ │ ├── SingleValueIndexSpec.java
│ │ │ │ ├── SingleValueIndexSpecBuilder.java
│ │ │ │ ├── UnknownKey.java
│ │ │ │ ├── ValueIndexSpec.java
│ │ │ │ └── query/
│ │ │ │ ├── AllCondition.java
│ │ │ │ ├── And.java
│ │ │ │ ├── AndCondition.java
│ │ │ │ ├── BetweenCondition.java
│ │ │ │ ├── Condition.java
│ │ │ │ ├── EmptyCondition.java
│ │ │ │ ├── EqualCondition.java
│ │ │ │ ├── GreaterThanCondition.java
│ │ │ │ ├── InCondition.java
│ │ │ │ ├── IndexCondition.java
│ │ │ │ ├── IsNotNullCondition.java
│ │ │ │ ├── IsNullCondition.java
│ │ │ │ ├── LabelCondition.java
│ │ │ │ ├── LabelEqualsCondition.java
│ │ │ │ ├── LabelExistsCondition.java
│ │ │ │ ├── LabelInCondition.java
│ │ │ │ ├── LabelNotEqualsCondition.java
│ │ │ │ ├── LabelNotExistsCondition.java
│ │ │ │ ├── LabelNotInCondition.java
│ │ │ │ ├── LessThanCondition.java
│ │ │ │ ├── NoneCondition.java
│ │ │ │ ├── NotBetweenCondition.java
│ │ │ │ ├── NotCondition.java
│ │ │ │ ├── NotEqualCondition.java
│ │ │ │ ├── NotInCondition.java
│ │ │ │ ├── OrCondition.java
│ │ │ │ ├── Queries.java
│ │ │ │ ├── Query.java
│ │ │ │ ├── QueryFactory.java
│ │ │ │ ├── StringContainsCondition.java
│ │ │ │ ├── StringEndsWithCondition.java
│ │ │ │ ├── StringNotContainsCondition.java
│ │ │ │ ├── StringNotEndsWithCondition.java
│ │ │ │ ├── StringNotStartsWithCondition.java
│ │ │ │ └── StringStartsWithCondition.java
│ │ │ └── router/
│ │ │ ├── IListRequest.java
│ │ │ ├── QueryParamBuildUtil.java
│ │ │ ├── SortableRequest.java
│ │ │ └── selector/
│ │ │ ├── FieldSelector.java
│ │ │ ├── FieldSelectorConverter.java
│ │ │ ├── LabelSelector.java
│ │ │ ├── LabelSelectorConverter.java
│ │ │ ├── Operator.java
│ │ │ ├── SelectorConverter.java
│ │ │ ├── SelectorCriteria.java
│ │ │ └── SelectorUtil.java
│ │ ├── infra/
│ │ │ ├── AnonymousUserConst.java
│ │ │ ├── BackupRootGetter.java
│ │ │ ├── Condition.java
│ │ │ ├── ConditionList.java
│ │ │ ├── ConditionStatus.java
│ │ │ ├── ExternalLinkProcessor.java
│ │ │ ├── ExternalUrlSupplier.java
│ │ │ ├── FileCategoryMatcher.java
│ │ │ ├── SystemInfo.java
│ │ │ ├── SystemInfoGetter.java
│ │ │ ├── SystemSetting.java
│ │ │ ├── SystemVersionSupplier.java
│ │ │ ├── ValidationUtils.java
│ │ │ ├── model/
│ │ │ │ └── License.java
│ │ │ └── utils/
│ │ │ ├── FileTypeDetectUtils.java
│ │ │ ├── GenericClassUtils.java
│ │ │ ├── JsonParseException.java
│ │ │ ├── JsonUtils.java
│ │ │ └── PathUtils.java
│ │ ├── migration/
│ │ │ ├── Backup.java
│ │ │ └── Constant.java
│ │ ├── notification/
│ │ │ ├── NotificationCenter.java
│ │ │ ├── NotificationContext.java
│ │ │ ├── NotificationReasonEmitter.java
│ │ │ ├── ReactiveNotifier.java
│ │ │ ├── ReasonAttributes.java
│ │ │ ├── ReasonPayload.java
│ │ │ └── UserIdentity.java
│ │ ├── plugin/
│ │ │ ├── ApiVersion.java
│ │ │ ├── BasePlugin.java
│ │ │ ├── PluginConfigUpdatedEvent.java
│ │ │ ├── PluginContext.java
│ │ │ ├── PluginsRootGetter.java
│ │ │ ├── ReactiveSettingFetcher.java
│ │ │ ├── SettingFetcher.java
│ │ │ ├── SharedEvent.java
│ │ │ ├── event/
│ │ │ │ └── PluginStartedEvent.java
│ │ │ └── extensionpoint/
│ │ │ └── ExtensionGetter.java
│ │ ├── search/
│ │ │ ├── HaloDocument.java
│ │ │ ├── HaloDocumentsProvider.java
│ │ │ ├── SearchEngine.java
│ │ │ ├── SearchOption.java
│ │ │ ├── SearchResult.java
│ │ │ ├── SearchService.java
│ │ │ └── event/
│ │ │ ├── HaloDocumentAddRequestEvent.java
│ │ │ ├── HaloDocumentDeleteRequestEvent.java
│ │ │ └── HaloDocumentRebuildRequestEvent.java
│ │ ├── security/
│ │ │ ├── AdditionalWebFilter.java
│ │ │ ├── AfterSecurityWebFilter.java
│ │ │ ├── AnonymousAuthenticationSecurityWebFilter.java
│ │ │ ├── AuthenticationSecurityWebFilter.java
│ │ │ ├── BeforeSecurityWebFilter.java
│ │ │ ├── FormLoginSecurityWebFilter.java
│ │ │ ├── HttpBasicSecurityWebFilter.java
│ │ │ ├── LoginHandlerEnhancer.java
│ │ │ ├── OAuth2AuthorizationCodeSecurityWebFilter.java
│ │ │ ├── PersonalAccessToken.java
│ │ │ ├── authentication/
│ │ │ │ ├── CryptoService.java
│ │ │ │ ├── login/
│ │ │ │ │ └── UsernamePasswordAuthenticationManager.java
│ │ │ │ └── oauth2/
│ │ │ │ └── HaloOAuth2AuthenticationToken.java
│ │ │ └── device/
│ │ │ └── DeviceService.java
│ │ └── theme/
│ │ ├── Constant.java
│ │ ├── ReactivePostContentHandler.java
│ │ ├── ReactiveSinglePageContentHandler.java
│ │ ├── TemplateNameResolver.java
│ │ ├── dialect/
│ │ │ ├── CommentWidget.java
│ │ │ ├── ElementTagPostProcessor.java
│ │ │ ├── TemplateFooterProcessor.java
│ │ │ └── TemplateHeadProcessor.java
│ │ ├── finders/
│ │ │ ├── Finder.java
│ │ │ └── vo/
│ │ │ └── ExtensionVoOperator.java
│ │ └── router/
│ │ ├── ModelConst.java
│ │ ├── PageUrlUtils.java
│ │ └── UrlContextListResult.java
│ └── test/
│ └── java/
│ └── run/
│ └── halo/
│ └── app/
│ ├── core/
│ │ └── extension/
│ │ ├── content/
│ │ │ └── PostTest.java
│ │ └── notification/
│ │ └── SubscriptionTest.java
│ ├── extension/
│ │ ├── ExtensionUtilTest.java
│ │ ├── FakeExtension.java
│ │ ├── ListOptionsTest.java
│ │ ├── PageRequestImplTest.java
│ │ ├── SecretTest.java
│ │ ├── controller/
│ │ │ ├── ControllerBuilderTest.java
│ │ │ ├── DefaultControllerTest.java
│ │ │ ├── DefaultDelayQueueTest.java
│ │ │ ├── DelayedEntryTest.java
│ │ │ ├── ExtensionWatcherTest.java
│ │ │ └── RequestSynchronizerTest.java
│ │ ├── index/
│ │ │ ├── IndexAttributeFactoryTest.java
│ │ │ ├── IndexSpecTest.java
│ │ │ ├── KeyComparatorTest.java
│ │ │ ├── MultiValueBuilderTest.java
│ │ │ ├── SingleValueBuilderTest.java
│ │ │ ├── UnknownKeyTest.java
│ │ │ └── query/
│ │ │ └── QueriesTest.java
│ │ ├── indexer/
│ │ │ ├── DefaultIndexEngineTest.java
│ │ │ └── LabelIndexImplTest.java
│ │ └── router/
│ │ └── selector/
│ │ ├── LabelSelectorTest.java
│ │ ├── OperatorTest.java
│ │ └── SelectorConverterTest.java
│ └── infra/
│ └── utils/
│ ├── GenericClassUtilsTest.java
│ ├── JsonUtilsTest.java
│ └── PathUtilsTest.java
├── api-docs/
│ └── openapi/
│ └── v3_0/
│ ├── aggregated.json
│ ├── apis_console.api_v1alpha1.json
│ ├── apis_extension.api_v1alpha1.json
│ ├── apis_public.api_v1alpha1.json
│ └── apis_uc.api_v1alpha1.json
├── application/
│ ├── build.gradle
│ ├── libs/
│ │ ├── thymeleaf-3.1.3.RELEASE.jar
│ │ └── thymeleaf-spring6-3.1.3.RELEASE.jar
│ └── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── run/
│ │ │ └── halo/
│ │ │ └── app/
│ │ │ ├── Application.java
│ │ │ ├── content/
│ │ │ │ ├── AbstractContentService.java
│ │ │ │ ├── AbstractEventReconciler.java
│ │ │ │ ├── CategoryPostCountUpdater.java
│ │ │ │ ├── CategoryService.java
│ │ │ │ ├── Content.java
│ │ │ │ ├── ContentRequest.java
│ │ │ │ ├── ContentUpdateParam.java
│ │ │ │ ├── Contributor.java
│ │ │ │ ├── ListedPost.java
│ │ │ │ ├── ListedSinglePage.java
│ │ │ │ ├── ListedSnapshotDto.java
│ │ │ │ ├── NotificationReasonConst.java
│ │ │ │ ├── PostContentServiceImpl.java
│ │ │ │ ├── PostHideFromListStateUpdater.java
│ │ │ │ ├── PostQuery.java
│ │ │ │ ├── PostRequest.java
│ │ │ │ ├── PostService.java
│ │ │ │ ├── PostSorter.java
│ │ │ │ ├── SinglePageQuery.java
│ │ │ │ ├── SinglePageRequest.java
│ │ │ │ ├── SinglePageService.java
│ │ │ │ ├── SnapshotService.java
│ │ │ │ ├── Stats.java
│ │ │ │ ├── comment/
│ │ │ │ │ ├── AbstractCommentService.java
│ │ │ │ │ ├── CommentEmailOwner.java
│ │ │ │ │ ├── CommentNotificationReasonPublisher.java
│ │ │ │ │ ├── CommentQuery.java
│ │ │ │ │ ├── CommentRequest.java
│ │ │ │ │ ├── CommentService.java
│ │ │ │ │ ├── CommentServiceImpl.java
│ │ │ │ │ ├── CommentStats.java
│ │ │ │ │ ├── ListedComment.java
│ │ │ │ │ ├── ListedReply.java
│ │ │ │ │ ├── OwnerInfo.java
│ │ │ │ │ ├── PostCommentSubject.java
│ │ │ │ │ ├── ReplyNotificationSubscriptionHelper.java
│ │ │ │ │ ├── ReplyQuery.java
│ │ │ │ │ ├── ReplyRequest.java
│ │ │ │ │ ├── ReplyService.java
│ │ │ │ │ ├── ReplyServiceImpl.java
│ │ │ │ │ └── SinglePageCommentSubject.java
│ │ │ │ ├── impl/
│ │ │ │ │ ├── CategoryServiceImpl.java
│ │ │ │ │ ├── PostServiceImpl.java
│ │ │ │ │ ├── SinglePageServiceImpl.java
│ │ │ │ │ └── SnapshotServiceImpl.java
│ │ │ │ ├── permalinks/
│ │ │ │ │ ├── CategoryPermalinkPolicy.java
│ │ │ │ │ ├── ExtensionLocator.java
│ │ │ │ │ ├── PermalinkPolicy.java
│ │ │ │ │ ├── PostPermalinkPolicy.java
│ │ │ │ │ └── TagPermalinkPolicy.java
│ │ │ │ └── stats/
│ │ │ │ ├── PostStatsUpdater.java
│ │ │ │ ├── ReplyEventReconciler.java
│ │ │ │ ├── TagPostCountUpdater.java
│ │ │ │ ├── VisitedEventReconciler.java
│ │ │ │ └── VotedEventReconciler.java
│ │ │ ├── core/
│ │ │ │ ├── attachment/
│ │ │ │ │ ├── AttachmentChangedEvent.java
│ │ │ │ │ ├── AttachmentLister.java
│ │ │ │ │ ├── AttachmentRootGetter.java
│ │ │ │ │ ├── PolicyConfigChangeDetector.java
│ │ │ │ │ ├── SearchRequest.java
│ │ │ │ │ ├── endpoint/
│ │ │ │ │ │ ├── AttachmentEndpoint.java
│ │ │ │ │ │ ├── LocalAttachmentUploadHandler.java
│ │ │ │ │ │ └── PolicyEndpoint.java
│ │ │ │ │ ├── extension/
│ │ │ │ │ │ ├── LocalThumbnail.java
│ │ │ │ │ │ └── Thumbnail.java
│ │ │ │ │ ├── impl/
│ │ │ │ │ │ ├── AttachmentListerImpl.java
│ │ │ │ │ │ └── AttachmentRootGetterImpl.java
│ │ │ │ │ ├── reconciler/
│ │ │ │ │ │ ├── AttachmentReconciler.java
│ │ │ │ │ │ ├── LocalThumbnailsReconciler.java
│ │ │ │ │ │ ├── PolicyReconciler.java
│ │ │ │ │ │ └── ThumbnailReconciler.java
│ │ │ │ │ └── thumbnail/
│ │ │ │ │ ├── DefaultLocalThumbnailService.java
│ │ │ │ │ ├── DefaultThumbnailService.java
│ │ │ │ │ ├── LocalThumbnailService.java
│ │ │ │ │ ├── ThumbnailImgTagPostProcessor.java
│ │ │ │ │ ├── ThumbnailResourceTransformer.java
│ │ │ │ │ ├── ThumbnailService.java
│ │ │ │ │ └── ThumbnailUtils.java
│ │ │ │ ├── counter/
│ │ │ │ │ ├── CounterService.java
│ │ │ │ │ ├── CounterServiceImpl.java
│ │ │ │ │ └── MeterUtils.java
│ │ │ │ ├── endpoint/
│ │ │ │ │ ├── AttachmentHandler.java
│ │ │ │ │ ├── WebSocketEndpointManager.java
│ │ │ │ │ ├── WebSocketHandlerMapping.java
│ │ │ │ │ ├── console/
│ │ │ │ │ │ ├── AttachmentConsoleEndpoint.java
│ │ │ │ │ │ ├── AuthProviderEndpoint.java
│ │ │ │ │ │ ├── CommentEndpoint.java
│ │ │ │ │ │ ├── ConsoleUserEndpoint.java
│ │ │ │ │ │ ├── CustomEndpointsBuilder.java
│ │ │ │ │ │ ├── PluginEndpoint.java
│ │ │ │ │ │ ├── PostEndpoint.java
│ │ │ │ │ │ ├── ReplyEndpoint.java
│ │ │ │ │ │ ├── SinglePageEndpoint.java
│ │ │ │ │ │ ├── StatsEndpoint.java
│ │ │ │ │ │ ├── SystemConfigEndpoint.java
│ │ │ │ │ │ ├── TagEndpoint.java
│ │ │ │ │ │ ├── TrackerEndpoint.java
│ │ │ │ │ │ └── UserEndpoint.java
│ │ │ │ │ ├── theme/
│ │ │ │ │ │ ├── CategoryQueryEndpoint.java
│ │ │ │ │ │ ├── CommentFinderEndpoint.java
│ │ │ │ │ │ ├── MenuQueryEndpoint.java
│ │ │ │ │ │ ├── PluginQueryEndpoint.java
│ │ │ │ │ │ ├── PostPublicQuery.java
│ │ │ │ │ │ ├── PostQueryEndpoint.java
│ │ │ │ │ │ ├── PublicApiUtils.java
│ │ │ │ │ │ ├── SinglePageQueryEndpoint.java
│ │ │ │ │ │ ├── SiteStatsQueryEndpoint.java
│ │ │ │ │ │ ├── TagQueryEndpoint.java
│ │ │ │ │ │ └── ThumbnailEndpoint.java
│ │ │ │ │ └── uc/
│ │ │ │ │ ├── AnnotationSettingEndpoint.java
│ │ │ │ │ ├── AttachmentUcEndpoint.java
│ │ │ │ │ ├── UcPostEndpoint.java
│ │ │ │ │ ├── UcSnapshotEndpoint.java
│ │ │ │ │ ├── UcUserPreferenceEndpoint.java
│ │ │ │ │ └── UserConnectionEndpoint.java
│ │ │ │ ├── reconciler/
│ │ │ │ │ ├── AnnotationSettingReconciler.java
│ │ │ │ │ ├── AuthProviderReconciler.java
│ │ │ │ │ ├── CategoryReconciler.java
│ │ │ │ │ ├── CommentReconciler.java
│ │ │ │ │ ├── MenuItemReconciler.java
│ │ │ │ │ ├── PluginReconciler.java
│ │ │ │ │ ├── PostCounterReconciler.java
│ │ │ │ │ ├── PostReconciler.java
│ │ │ │ │ ├── ReplyReconciler.java
│ │ │ │ │ ├── ReverseProxyReconciler.java
│ │ │ │ │ ├── RoleReconciler.java
│ │ │ │ │ ├── SinglePageReconciler.java
│ │ │ │ │ ├── SystemConfigReconciler.java
│ │ │ │ │ ├── TagReconciler.java
│ │ │ │ │ ├── ThemeReconciler.java
│ │ │ │ │ └── UserReconciler.java
│ │ │ │ └── user/
│ │ │ │ └── service/
│ │ │ │ ├── DefaultRoleService.java
│ │ │ │ ├── EmailPasswordRecoveryService.java
│ │ │ │ ├── EmailVerificationService.java
│ │ │ │ ├── InMemoryResetTokenRepository.java
│ │ │ │ ├── InvalidResetTokenException.java
│ │ │ │ ├── PatService.java
│ │ │ │ ├── ResetToken.java
│ │ │ │ ├── ResetTokenRepository.java
│ │ │ │ ├── SettingConfigService.java
│ │ │ │ ├── UserConnectionService.java
│ │ │ │ ├── UserLoginOrLogoutProcessing.java
│ │ │ │ └── impl/
│ │ │ │ ├── DefaultAttachmentService.java
│ │ │ │ ├── EmailPasswordRecoveryServiceImpl.java
│ │ │ │ ├── EmailVerificationServiceImpl.java
│ │ │ │ ├── PatServiceImpl.java
│ │ │ │ ├── SettingConfigServiceImpl.java
│ │ │ │ ├── UserConnectionServiceImpl.java
│ │ │ │ └── UserServiceImpl.java
│ │ │ ├── event/
│ │ │ │ ├── post/
│ │ │ │ │ ├── CategoryHiddenStateChangeEvent.java
│ │ │ │ │ ├── CommentCreatedEvent.java
│ │ │ │ │ ├── CommentUnreadReplyCountChangedEvent.java
│ │ │ │ │ ├── DownvotedEvent.java
│ │ │ │ │ ├── PostStatsChangedEvent.java
│ │ │ │ │ ├── ReplyChangedEvent.java
│ │ │ │ │ ├── ReplyCreatedEvent.java
│ │ │ │ │ ├── ReplyDeletedEvent.java
│ │ │ │ │ ├── ReplyEvent.java
│ │ │ │ │ ├── UpvotedEvent.java
│ │ │ │ │ ├── VisitedEvent.java
│ │ │ │ │ └── VotedEvent.java
│ │ │ │ └── user/
│ │ │ │ └── PasswordChangedEvent.java
│ │ │ ├── extension/
│ │ │ │ ├── DefaultSchemeManager.java
│ │ │ │ ├── DelegateExtensionClient.java
│ │ │ │ ├── ExtensionConverter.java
│ │ │ │ ├── ExtensionStoreUtil.java
│ │ │ │ ├── JSONExtensionConverter.java
│ │ │ │ ├── ReactiveExtensionClientImpl.java
│ │ │ │ ├── availability/
│ │ │ │ │ └── IndexBuildState.java
│ │ │ │ ├── controller/
│ │ │ │ │ └── DefaultControllerManager.java
│ │ │ │ ├── event/
│ │ │ │ │ ├── IndexerBuiltEvent.java
│ │ │ │ │ ├── SchemeAddedEvent.java
│ │ │ │ │ └── SchemeRemovedEvent.java
│ │ │ │ ├── exception/
│ │ │ │ │ ├── ExtensionConvertException.java
│ │ │ │ │ ├── ExtensionNotFoundException.java
│ │ │ │ │ └── SchemaViolationException.java
│ │ │ │ ├── gc/
│ │ │ │ │ ├── GcControllerInitializer.java
│ │ │ │ │ ├── GcReconciler.java
│ │ │ │ │ ├── GcRequest.java
│ │ │ │ │ ├── GcSynchronizer.java
│ │ │ │ │ └── GcWatcher.java
│ │ │ │ ├── index/
│ │ │ │ │ ├── DefaultIndexEngine.java
│ │ │ │ │ ├── DefaultIndices.java
│ │ │ │ │ ├── DefaultIndicesManager.java
│ │ │ │ │ ├── Index.java
│ │ │ │ │ ├── IndexEngine.java
│ │ │ │ │ ├── Indices.java
│ │ │ │ │ ├── IndicesInitializer.java
│ │ │ │ │ ├── IndicesManager.java
│ │ │ │ │ ├── LabelIndex.java
│ │ │ │ │ ├── LabelIndexQuery.java
│ │ │ │ │ ├── MultiValueIndex.java
│ │ │ │ │ ├── SingleValueIndex.java
│ │ │ │ │ ├── StringUnknownKeyConverter.java
│ │ │ │ │ ├── TransactionalOperation.java
│ │ │ │ │ ├── ValueIndexQuery.java
│ │ │ │ │ └── query/
│ │ │ │ │ └── QueryVisitor.java
│ │ │ │ ├── indexer/
│ │ │ │ │ └── DefaultIndicesInitializer.java
│ │ │ │ ├── router/
│ │ │ │ │ ├── ExtensionCompositeRouterFunction.java
│ │ │ │ │ ├── ExtensionCreateHandler.java
│ │ │ │ │ ├── ExtensionDeleteHandler.java
│ │ │ │ │ ├── ExtensionGetHandler.java
│ │ │ │ │ ├── ExtensionListHandler.java
│ │ │ │ │ ├── ExtensionPatchHandler.java
│ │ │ │ │ ├── ExtensionRouterFunctionFactory.java
│ │ │ │ │ ├── ExtensionUpdateHandler.java
│ │ │ │ │ └── JsonPatch.java
│ │ │ │ └── store/
│ │ │ │ ├── ExtensionStore.java
│ │ │ │ ├── ExtensionStoreClient.java
│ │ │ │ ├── ExtensionStoreClientJPAImpl.java
│ │ │ │ ├── ExtensionStoreRepository.java
│ │ │ │ ├── ReactiveExtensionStoreClient.java
│ │ │ │ └── ReactiveExtensionStoreClientImpl.java
│ │ │ ├── infra/
│ │ │ │ ├── DefaultBackupRootGetter.java
│ │ │ │ ├── DefaultExternalLinkProcessor.java
│ │ │ │ ├── DefaultInitializationStateGetter.java
│ │ │ │ ├── DefaultReactiveUrlDataBufferFetcher.java
│ │ │ │ ├── DefaultSystemConfigFetcher.java
│ │ │ │ ├── DefaultSystemVersionSupplier.java
│ │ │ │ ├── DefaultThemeRootGetter.java
│ │ │ │ ├── ExtensionInitializedEvent.java
│ │ │ │ ├── ExtensionResourceInitializer.java
│ │ │ │ ├── ExternalUrlChangedEvent.java
│ │ │ │ ├── InitializationPhase.java
│ │ │ │ ├── InitializationStateGetter.java
│ │ │ │ ├── ReactiveExtensionPaginatedOperator.java
│ │ │ │ ├── ReactiveExtensionPaginatedOperatorImpl.java
│ │ │ │ ├── ReactiveUrlDataBufferFetcher.java
│ │ │ │ ├── SchemeInitializer.java
│ │ │ │ ├── SecureRequestMappingHandlerAdapter.java
│ │ │ │ ├── SecureServerRequest.java
│ │ │ │ ├── SecureServerWebExchange.java
│ │ │ │ ├── SystemConfigChangedEvent.java
│ │ │ │ ├── SystemConfigFetcher.java
│ │ │ │ ├── SystemConfigFirstExternalUrlSupplier.java
│ │ │ │ ├── SystemConfigInitializer.java
│ │ │ │ ├── SystemInfoGetterImpl.java
│ │ │ │ ├── SystemState.java
│ │ │ │ ├── ThemeRootGetter.java
│ │ │ │ ├── actuator/
│ │ │ │ │ ├── DatabaseInfoContributor.java
│ │ │ │ │ ├── GlobalInfo.java
│ │ │ │ │ ├── GlobalInfoEndpoint.java
│ │ │ │ │ ├── GlobalInfoService.java
│ │ │ │ │ ├── GlobalInfoServiceImpl.java
│ │ │ │ │ └── RestartEndpoint.java
│ │ │ │ ├── config/
│ │ │ │ │ ├── ExtensionConfiguration.java
│ │ │ │ │ ├── HaloConfiguration.java
│ │ │ │ │ ├── JacksonAdapterModule.java
│ │ │ │ │ ├── R2dbcConfiguration.java
│ │ │ │ │ ├── SessionConfiguration.java
│ │ │ │ │ ├── SwaggerConfig.java
│ │ │ │ │ ├── WebFluxConfig.java
│ │ │ │ │ └── WebServerSecurityConfig.java
│ │ │ │ ├── exception/
│ │ │ │ │ ├── AccessDeniedException.java
│ │ │ │ │ ├── AttachmentAlreadyExistsException.java
│ │ │ │ │ ├── DuplicateNameException.java
│ │ │ │ │ ├── EmailAlreadyTakenException.java
│ │ │ │ │ ├── EmailVerificationFailed.java
│ │ │ │ │ ├── Exceptions.java
│ │ │ │ │ ├── FileSizeExceededException.java
│ │ │ │ │ ├── FileTypeNotAllowedException.java
│ │ │ │ │ ├── NotFoundException.java
│ │ │ │ │ ├── OAuth2UserAlreadyBoundException.java
│ │ │ │ │ ├── PluginAlreadyExistsException.java
│ │ │ │ │ ├── PluginDependenciesNotEnabledException.java
│ │ │ │ │ ├── PluginDependencyException.java
│ │ │ │ │ ├── PluginDependentsNotDisabledException.java
│ │ │ │ │ ├── PluginInstallationException.java
│ │ │ │ │ ├── PluginRuntimeIncompatibleException.java
│ │ │ │ │ ├── RateLimitExceededException.java
│ │ │ │ │ ├── RequestBodyValidationException.java
│ │ │ │ │ ├── RequestRestrictedException.java
│ │ │ │ │ ├── RestrictedNameException.java
│ │ │ │ │ ├── ThemeAlreadyExistsException.java
│ │ │ │ │ ├── ThemeInstallationException.java
│ │ │ │ │ ├── ThemeUninstallException.java
│ │ │ │ │ ├── ThemeUpgradeException.java
│ │ │ │ │ ├── UnsatisfiedAttributeValueException.java
│ │ │ │ │ ├── UserNotFoundException.java
│ │ │ │ │ └── handlers/
│ │ │ │ │ ├── HaloErrorConfiguration.java
│ │ │ │ │ ├── HaloErrorWebExceptionHandler.java
│ │ │ │ │ └── ProblemDetailErrorAttributes.java
│ │ │ │ ├── properties/
│ │ │ │ │ ├── AttachmentProperties.java
│ │ │ │ │ ├── CacheProperties.java
│ │ │ │ │ ├── ExtensionProperties.java
│ │ │ │ │ ├── HaloProperties.java
│ │ │ │ │ ├── JwtProperties.java
│ │ │ │ │ ├── ProxyProperties.java
│ │ │ │ │ ├── SecurityProperties.java
│ │ │ │ │ ├── ThemeProperties.java
│ │ │ │ │ └── UiProperties.java
│ │ │ │ ├── ui/
│ │ │ │ │ ├── ProxyFilter.java
│ │ │ │ │ ├── WebSocketRequestPredicate.java
│ │ │ │ │ ├── WebSocketServerWebExchangeMatcher.java
│ │ │ │ │ └── WebSocketUtils.java
│ │ │ │ ├── utils/
│ │ │ │ │ ├── Base62Utils.java
│ │ │ │ │ ├── FileNameUtils.java
│ │ │ │ │ ├── FileUtils.java
│ │ │ │ │ ├── HaloUtils.java
│ │ │ │ │ ├── IpAddressUtils.java
│ │ │ │ │ ├── ReactiveUtils.java
│ │ │ │ │ ├── SettingUtils.java
│ │ │ │ │ ├── SortUtils.java
│ │ │ │ │ ├── SystemConfigUtils.java
│ │ │ │ │ ├── VersionUtils.java
│ │ │ │ │ └── YamlUnstructuredLoader.java
│ │ │ │ └── webfilter/
│ │ │ │ ├── AdditionalWebFilterChainProxy.java
│ │ │ │ └── LocaleChangeWebFilter.java
│ │ │ ├── migration/
│ │ │ │ ├── BackupFile.java
│ │ │ │ ├── BackupReconciler.java
│ │ │ │ ├── MigrationEndpoint.java
│ │ │ │ ├── MigrationService.java
│ │ │ │ └── impl/
│ │ │ │ └── MigrationServiceImpl.java
│ │ │ ├── notification/
│ │ │ │ ├── DefaultNotificationCenter.java
│ │ │ │ ├── DefaultNotificationReasonEmitter.java
│ │ │ │ ├── DefaultNotificationSender.java
│ │ │ │ ├── DefaultNotificationService.java
│ │ │ │ ├── DefaultNotificationTemplateRender.java
│ │ │ │ ├── DefaultNotifierConfigStore.java
│ │ │ │ ├── DefaultSubscriberEmailResolver.java
│ │ │ │ ├── EmailNotifier.java
│ │ │ │ ├── EmailSenderHelper.java
│ │ │ │ ├── EmailSenderHelperImpl.java
│ │ │ │ ├── LanguageUtils.java
│ │ │ │ ├── NotificationSender.java
│ │ │ │ ├── NotificationTemplateRender.java
│ │ │ │ ├── NotificationTrigger.java
│ │ │ │ ├── NotifierConfigStore.java
│ │ │ │ ├── ReasonNotificationTemplateSelector.java
│ │ │ │ ├── ReasonNotificationTemplateSelectorImpl.java
│ │ │ │ ├── RecipientResolver.java
│ │ │ │ ├── RecipientResolverImpl.java
│ │ │ │ ├── Subscriber.java
│ │ │ │ ├── SubscriberEmailResolver.java
│ │ │ │ ├── SubscriptionService.java
│ │ │ │ ├── SubscriptionServiceImpl.java
│ │ │ │ ├── UserNotificationPreference.java
│ │ │ │ ├── UserNotificationPreferenceService.java
│ │ │ │ ├── UserNotificationPreferenceServiceImpl.java
│ │ │ │ ├── UserNotificationQuery.java
│ │ │ │ ├── UserNotificationService.java
│ │ │ │ └── endpoint/
│ │ │ │ ├── ConsoleNotifierEndpoint.java
│ │ │ │ ├── EmailConfigValidationEndpoint.java
│ │ │ │ ├── SubscriptionRouter.java
│ │ │ │ ├── UserNotificationEndpoint.java
│ │ │ │ ├── UserNotificationPreferencesEndpoint.java
│ │ │ │ └── UserNotifierEndpoint.java
│ │ │ ├── plugin/
│ │ │ │ ├── AggregatedRouterFunction.java
│ │ │ │ ├── BuiltInPluginsInitializer.java
│ │ │ │ ├── DefaultDevelopmentPluginRepository.java
│ │ │ │ ├── DefaultPluginApplicationContextFactory.java
│ │ │ │ ├── DefaultPluginGetter.java
│ │ │ │ ├── DefaultPluginRouterFunctionRegistry.java
│ │ │ │ ├── DefaultReactiveSettingFetcher.java
│ │ │ │ ├── DefaultSettingFetcher.java
│ │ │ │ ├── DefaultSpringPlugin.java
│ │ │ │ ├── DevPluginLoader.java
│ │ │ │ ├── HaloPluginManager.java
│ │ │ │ ├── HaloSharedEventDelegator.java
│ │ │ │ ├── OptionalDependentResolver.java
│ │ │ │ ├── PluginApplicationContext.java
│ │ │ │ ├── PluginApplicationContextFactory.java
│ │ │ │ ├── PluginAutoConfiguration.java
│ │ │ │ ├── PluginBeforeStopSyncListener.java
│ │ │ │ ├── PluginConst.java
│ │ │ │ ├── PluginControllerManager.java
│ │ │ │ ├── PluginDevelopmentInitializer.java
│ │ │ │ ├── PluginExtensionLoaderUtils.java
│ │ │ │ ├── PluginFinder.java
│ │ │ │ ├── PluginGetter.java
│ │ │ │ ├── PluginNotFoundException.java
│ │ │ │ ├── PluginProperties.java
│ │ │ │ ├── PluginRequestMappingHandlerMapping.java
│ │ │ │ ├── PluginRouterFunctionRegistry.java
│ │ │ │ ├── PluginService.java
│ │ │ │ ├── PluginServiceImpl.java
│ │ │ │ ├── PluginSharedEventDelegator.java
│ │ │ │ ├── PluginStartedListener.java
│ │ │ │ ├── PluginUtils.java
│ │ │ │ ├── PluginsRootGetterImpl.java
│ │ │ │ ├── PropertyPluginStatusProvider.java
│ │ │ │ ├── SharedApplicationContextFactory.java
│ │ │ │ ├── SharedEventDispatcher.java
│ │ │ │ ├── SpringComponentsFinder.java
│ │ │ │ ├── SpringExtensionFactory.java
│ │ │ │ ├── SpringPlugin.java
│ │ │ │ ├── SpringPluginFactory.java
│ │ │ │ ├── SpringPluginManager.java
│ │ │ │ ├── YamlPluginDescriptorFinder.java
│ │ │ │ ├── YamlPluginFinder.java
│ │ │ │ ├── event/
│ │ │ │ │ ├── HaloPluginBeforeStopEvent.java
│ │ │ │ │ ├── HaloPluginStartedEvent.java
│ │ │ │ │ ├── HaloPluginStoppedEvent.java
│ │ │ │ │ ├── SpringPluginStartedEvent.java
│ │ │ │ │ ├── SpringPluginStartingEvent.java
│ │ │ │ │ ├── SpringPluginStoppedEvent.java
│ │ │ │ │ └── SpringPluginStoppingEvent.java
│ │ │ │ ├── extensionpoint/
│ │ │ │ │ ├── AbstractDefinitionGetter.java
│ │ │ │ │ ├── DefaultExtensionGetter.java
│ │ │ │ │ ├── ExtensionDefinition.java
│ │ │ │ │ ├── ExtensionDefinitionGetter.java
│ │ │ │ │ ├── ExtensionDefinitionGetterImpl.java
│ │ │ │ │ ├── ExtensionPointDefinition.java
│ │ │ │ │ ├── ExtensionPointDefinitionGetter.java
│ │ │ │ │ └── ExtensionPointDefinitionGetterImpl.java
│ │ │ │ └── resources/
│ │ │ │ ├── BundleResourceUtils.java
│ │ │ │ ├── ReverseProxyRouterFunctionFactory.java
│ │ │ │ └── ReverseProxyRouterFunctionRegistry.java
│ │ │ ├── search/
│ │ │ │ ├── HaloDocumentEventsListener.java
│ │ │ │ ├── IndexEndpoint.java
│ │ │ │ ├── IndicesEndpoint.java
│ │ │ │ ├── SearchEngineUnavailableException.java
│ │ │ │ ├── SearchServiceImpl.java
│ │ │ │ ├── lucene/
│ │ │ │ │ └── LuceneSearchEngine.java
│ │ │ │ └── post/
│ │ │ │ ├── PostEventsListener.java
│ │ │ │ └── PostHaloDocumentsProvider.java
│ │ │ ├── security/
│ │ │ │ ├── AuthProviderService.java
│ │ │ │ ├── AuthProviderServiceImpl.java
│ │ │ │ ├── CorsConfigurer.java
│ │ │ │ ├── CsrfConfigurer.java
│ │ │ │ ├── DefaultServerAuthenticationEntryPoint.java
│ │ │ │ ├── DefaultSuperAdminInitializer.java
│ │ │ │ ├── DefaultUserDetailService.java
│ │ │ │ ├── ExceptionSecurityConfigurer.java
│ │ │ │ ├── HaloRedirectAuthenticationSuccessHandler.java
│ │ │ │ ├── HaloServerRequestCache.java
│ │ │ │ ├── HaloUserDetails.java
│ │ │ │ ├── InitializeRedirectionWebFilter.java
│ │ │ │ ├── ListedAuthProvider.java
│ │ │ │ ├── LoginHandlerEnhancerImpl.java
│ │ │ │ ├── LogoutSecurityConfigurer.java
│ │ │ │ ├── RedirectAccessDeniedHandler.java
│ │ │ │ ├── SecurityWebFiltersConfigurer.java
│ │ │ │ ├── SuperAdminInitializer.java
│ │ │ │ ├── authentication/
│ │ │ │ │ ├── SecurityConfigurer.java
│ │ │ │ │ ├── WebExchangeMatchers.java
│ │ │ │ │ ├── exception/
│ │ │ │ │ │ ├── TooManyRequestsException.java
│ │ │ │ │ │ └── TwoFactorAuthException.java
│ │ │ │ │ ├── impl/
│ │ │ │ │ │ └── RsaKeyService.java
│ │ │ │ │ ├── login/
│ │ │ │ │ │ ├── HaloUser.java
│ │ │ │ │ │ ├── InvalidEncryptedMessageException.java
│ │ │ │ │ │ ├── LoginAuthenticationConverter.java
│ │ │ │ │ │ ├── LoginSecurityConfigurer.java
│ │ │ │ │ │ ├── PublicKeyRouteBuilder.java
│ │ │ │ │ │ ├── UsernamePasswordDelegatingAuthenticationManager.java
│ │ │ │ │ │ └── UsernamePasswordHandler.java
│ │ │ │ │ ├── oauth2/
│ │ │ │ │ │ ├── DefaultOAuth2LoginHandlerEnhancer.java
│ │ │ │ │ │ ├── MapOAuth2AuthenticationFilter.java
│ │ │ │ │ │ ├── OAuth2AuthenticationTokenCache.java
│ │ │ │ │ │ ├── OAuth2LoginHandlerEnhancer.java
│ │ │ │ │ │ ├── OAuth2SecurityConfigurer.java
│ │ │ │ │ │ └── WebSessionOAuth2AuthenticationTokenCache.java
│ │ │ │ │ ├── pat/
│ │ │ │ │ │ ├── PatAuthenticationConverter.java
│ │ │ │ │ │ ├── PatAuthenticationManager.java
│ │ │ │ │ │ ├── PatEndpoint.java
│ │ │ │ │ │ ├── PatSecurityConfigurer.java
│ │ │ │ │ │ ├── UserScopedPatHandler.java
│ │ │ │ │ │ └── UserScopedPatHandlerImpl.java
│ │ │ │ │ ├── rememberme/
│ │ │ │ │ │ ├── CookieSignatureKeyResolver.java
│ │ │ │ │ │ ├── DefaultCookieSignatureKeyResolver.java
│ │ │ │ │ │ ├── PersistentRememberMeTokenRepository.java
│ │ │ │ │ │ ├── PersistentRememberMeTokenRepositoryImpl.java
│ │ │ │ │ │ ├── PersistentTokenBasedRememberMeServices.java
│ │ │ │ │ │ ├── RememberMeAuthenticationManager.java
│ │ │ │ │ │ ├── RememberMeConfigurer.java
│ │ │ │ │ │ ├── RememberMeCookieResolver.java
│ │ │ │ │ │ ├── RememberMeCookieResolverImpl.java
│ │ │ │ │ │ ├── RememberMeRequestCache.java
│ │ │ │ │ │ ├── RememberMeServices.java
│ │ │ │ │ │ ├── RememberMeTokenRevoker.java
│ │ │ │ │ │ ├── RememberTokenCleaner.java
│ │ │ │ │ │ ├── TokenBasedRememberMeServices.java
│ │ │ │ │ │ └── WebSessionRememberMeRequestCache.java
│ │ │ │ │ └── twofactor/
│ │ │ │ │ ├── TotpAuthenticationSuccessHandler.java
│ │ │ │ │ ├── TwoFactorAuthEndpoint.java
│ │ │ │ │ ├── TwoFactorAuthRequiredException.java
│ │ │ │ │ ├── TwoFactorAuthSecurityConfigurer.java
│ │ │ │ │ ├── TwoFactorAuthSettings.java
│ │ │ │ │ ├── TwoFactorAuthentication.java
│ │ │ │ │ ├── TwoFactorAuthenticationEntryPoint.java
│ │ │ │ │ ├── TwoFactorUtils.java
│ │ │ │ │ └── totp/
│ │ │ │ │ ├── DefaultTotpAuthService.java
│ │ │ │ │ ├── TotpAuthService.java
│ │ │ │ │ ├── TotpAuthenticationManager.java
│ │ │ │ │ ├── TotpAuthenticationToken.java
│ │ │ │ │ └── TotpCodeAuthenticationConverter.java
│ │ │ │ ├── authorization/
│ │ │ │ │ ├── Attributes.java
│ │ │ │ │ ├── AttributesRecord.java
│ │ │ │ │ ├── AuthorityUtils.java
│ │ │ │ │ ├── AuthorizationExchangeConfigurers.java
│ │ │ │ │ ├── AuthorizationRuleResolver.java
│ │ │ │ │ ├── AuthorizingVisitor.java
│ │ │ │ │ ├── DefaultRuleResolver.java
│ │ │ │ │ ├── PolicyRuleList.java
│ │ │ │ │ ├── RbacRequestEvaluation.java
│ │ │ │ │ ├── RequestInfo.java
│ │ │ │ │ ├── RequestInfoAuthorizationManager.java
│ │ │ │ │ ├── RequestInfoFactory.java
│ │ │ │ │ └── RuleAccumulator.java
│ │ │ │ ├── device/
│ │ │ │ │ ├── DeviceCookieResolver.java
│ │ │ │ │ ├── DeviceCookieResolverImpl.java
│ │ │ │ │ ├── DeviceEndpoint.java
│ │ │ │ │ ├── DeviceReconciler.java
│ │ │ │ │ ├── DeviceSecurityConfigurer.java
│ │ │ │ │ ├── DeviceServiceImpl.java
│ │ │ │ │ ├── DeviceSessionFilter.java
│ │ │ │ │ ├── NewDeviceLoginEvent.java
│ │ │ │ │ └── NewDeviceLoginListener.java
│ │ │ │ ├── jackson2/
│ │ │ │ │ ├── HaloOAuth2AuthenticationTokenMixin.java
│ │ │ │ │ ├── HaloSecurityJackson2Module.java
│ │ │ │ │ ├── HaloUserMixin.java
│ │ │ │ │ ├── SwitchUserGrantedAuthorityMixIn.java
│ │ │ │ │ └── TwoFactorAuthenticationMixin.java
│ │ │ │ ├── preauth/
│ │ │ │ │ ├── DefaultPasswordResetAvailabilityProviders.java
│ │ │ │ │ ├── EmailPasswordResetAvailabilityProvider.java
│ │ │ │ │ ├── PasswordResetAvailabilityProvider.java
│ │ │ │ │ ├── PasswordResetAvailabilityProviders.java
│ │ │ │ │ ├── PreAuthEmailPasswordResetEndpoint.java
│ │ │ │ │ ├── PreAuthLoginEndpoint.java
│ │ │ │ │ ├── PreAuthSignUpEndpoint.java
│ │ │ │ │ ├── PreAuthTwoFactorEndpoint.java
│ │ │ │ │ └── SystemSetupEndpoint.java
│ │ │ │ ├── session/
│ │ │ │ │ ├── InMemoryReactiveIndexedSessionRepository.java
│ │ │ │ │ ├── ReactiveIndexedSessionRepository.java
│ │ │ │ │ └── SessionInvalidationListener.java
│ │ │ │ └── switchuser/
│ │ │ │ └── SwitchUserConfigurer.java
│ │ │ └── theme/
│ │ │ ├── CompositeTemplateResolver.java
│ │ │ ├── DefaultTemplateEnum.java
│ │ │ ├── DefaultTemplateNameResolver.java
│ │ │ ├── DefaultViewNameResolver.java
│ │ │ ├── HaloViewResolver.java
│ │ │ ├── ReactiveSpelVariableExpressionEvaluator.java
│ │ │ ├── SiteSettingVariablesAcquirer.java
│ │ │ ├── TemplateEngineManager.java
│ │ │ ├── ThemeContext.java
│ │ │ ├── ThemeContextBasedVariablesAcquirer.java
│ │ │ ├── ThemeLinkBuilder.java
│ │ │ ├── ThemeLocaleContextResolver.java
│ │ │ ├── ThemeResolver.java
│ │ │ ├── UserLocaleRequestAttributeWriteFilter.java
│ │ │ ├── ViewContextBasedVariablesAcquirer.java
│ │ │ ├── ViewNameResolver.java
│ │ │ ├── config/
│ │ │ │ ├── ThemeConfiguration.java
│ │ │ │ └── ThemeWebFluxConfigurer.java
│ │ │ ├── dialect/
│ │ │ │ ├── CommentElementTagProcessor.java
│ │ │ │ ├── CommentEnabledVariableProcessor.java
│ │ │ │ ├── ContentTemplateHeadProcessor.java
│ │ │ │ ├── DefaultFaviconHeadProcessor.java
│ │ │ │ ├── DefaultLinkExpressionFactory.java
│ │ │ │ ├── DuplicateMetaTagProcessor.java
│ │ │ │ ├── EvaluationContextEnhancer.java
│ │ │ │ ├── GeneratorMetaProcessor.java
│ │ │ │ ├── GlobalHeadInjectionProcessor.java
│ │ │ │ ├── GlobalSeoProcessor.java
│ │ │ │ ├── HaloExpressionObjectFactory.java
│ │ │ │ ├── HaloPostTemplateHandler.java
│ │ │ │ ├── HaloProcessorDialect.java
│ │ │ │ ├── HaloSpringSecurityDialect.java
│ │ │ │ ├── HaloTrackerProcessor.java
│ │ │ │ ├── IndexSeoProcessor.java
│ │ │ │ ├── InjectionExcluderProcessor.java
│ │ │ │ ├── LinkExpressionObjectDialect.java
│ │ │ │ ├── SecureTemplateContext.java
│ │ │ │ ├── SecureTemplateContextWrapper.java
│ │ │ │ ├── SecureTemplateWebContext.java
│ │ │ │ ├── TemplateFooterElementTagProcessor.java
│ │ │ │ ├── TemplateGlobalHeadProcessor.java
│ │ │ │ └── expression/
│ │ │ │ └── Annotations.java
│ │ │ ├── endpoint/
│ │ │ │ └── ThemeEndpoint.java
│ │ │ ├── engine/
│ │ │ │ ├── DefaultThemeTemplateAvailabilityProvider.java
│ │ │ │ ├── HaloTemplateEngine.java
│ │ │ │ ├── PluginClassloaderTemplateResolver.java
│ │ │ │ └── ThemeTemplateAvailabilityProvider.java
│ │ │ ├── finders/
│ │ │ │ ├── CategoryFinder.java
│ │ │ │ ├── CommentFinder.java
│ │ │ │ ├── CommentPublicQueryService.java
│ │ │ │ ├── ContributorFinder.java
│ │ │ │ ├── DefaultFinderRegistry.java
│ │ │ │ ├── FinderRegistry.java
│ │ │ │ ├── MenuFinder.java
│ │ │ │ ├── PluginFinder.java
│ │ │ │ ├── PostFinder.java
│ │ │ │ ├── PostPublicQueryService.java
│ │ │ │ ├── SinglePageConversionService.java
│ │ │ │ ├── SinglePageFinder.java
│ │ │ │ ├── SiteStatsFinder.java
│ │ │ │ ├── TagFinder.java
│ │ │ │ ├── ThemeFinder.java
│ │ │ │ ├── ThumbnailFinder.java
│ │ │ │ ├── impl/
│ │ │ │ │ ├── CategoryFinderImpl.java
│ │ │ │ │ ├── CommentFinderImpl.java
│ │ │ │ │ ├── CommentPublicQueryServiceImpl.java
│ │ │ │ │ ├── ContributorFinderImpl.java
│ │ │ │ │ ├── MenuFinderImpl.java
│ │ │ │ │ ├── PluginFinderImpl.java
│ │ │ │ │ ├── PostFinderImpl.java
│ │ │ │ │ ├── PostPublicQueryServiceImpl.java
│ │ │ │ │ ├── SinglePageConversionServiceImpl.java
│ │ │ │ │ ├── SinglePageFinderImpl.java
│ │ │ │ │ ├── SiteStatsFinderImpl.java
│ │ │ │ │ ├── TagFinderImpl.java
│ │ │ │ │ ├── ThemeFinderImpl.java
│ │ │ │ │ └── ThumbnailFinderImpl.java
│ │ │ │ └── vo/
│ │ │ │ ├── CategoryTreeVo.java
│ │ │ │ ├── CategoryVo.java
│ │ │ │ ├── CommentStatsVo.java
│ │ │ │ ├── CommentVo.java
│ │ │ │ ├── CommentWithReplyVo.java
│ │ │ │ ├── ContentVo.java
│ │ │ │ ├── ContributorVo.java
│ │ │ │ ├── ListedPostVo.java
│ │ │ │ ├── ListedSinglePageVo.java
│ │ │ │ ├── MenuItemVo.java
│ │ │ │ ├── MenuVo.java
│ │ │ │ ├── NavigationPostVo.java
│ │ │ │ ├── PostArchiveVo.java
│ │ │ │ ├── PostArchiveYearMonthVo.java
│ │ │ │ ├── PostVo.java
│ │ │ │ ├── ReplyVo.java
│ │ │ │ ├── SinglePageVo.java
│ │ │ │ ├── SiteSettingVo.java
│ │ │ │ ├── SiteStatsVo.java
│ │ │ │ ├── StatsVo.java
│ │ │ │ ├── TagVo.java
│ │ │ │ ├── ThemeVo.java
│ │ │ │ ├── UserVo.java
│ │ │ │ └── VisualizableTreeNode.java
│ │ │ ├── message/
│ │ │ │ ├── ThemeMessageResolutionUtils.java
│ │ │ │ └── ThemeMessageResolver.java
│ │ │ ├── router/
│ │ │ │ ├── DefaultQueryPostPredicateResolver.java
│ │ │ │ ├── ExtensionPermalinkPatternUpdater.java
│ │ │ │ ├── ModelMapUtils.java
│ │ │ │ ├── PermalinkRuleChangedEvent.java
│ │ │ │ ├── PreviewRouterFunction.java
│ │ │ │ ├── ReactiveQueryPostPredicateResolver.java
│ │ │ │ ├── SinglePageRoute.java
│ │ │ │ ├── ThemeCompositeRouterFunction.java
│ │ │ │ ├── TitleVisibilityIdentifyCalculator.java
│ │ │ │ └── factories/
│ │ │ │ ├── ArchiveRouteFactory.java
│ │ │ │ ├── AuthorPostsRouteFactory.java
│ │ │ │ ├── CategoriesRouteFactory.java
│ │ │ │ ├── CategoryPostRouteFactory.java
│ │ │ │ ├── IndexRouteFactory.java
│ │ │ │ ├── PostRouteFactory.java
│ │ │ │ ├── RouteFactory.java
│ │ │ │ ├── TagPostRouteFactory.java
│ │ │ │ └── TagsRouteFactory.java
│ │ │ ├── service/
│ │ │ │ ├── ThemeService.java
│ │ │ │ ├── ThemeServiceImpl.java
│ │ │ │ └── ThemeUtils.java
│ │ │ └── utils/
│ │ │ └── PatternUtils.java
│ │ └── resources/
│ │ ├── META-INF/
│ │ │ └── spring-devtools.properties
│ │ ├── application-dev.yaml
│ │ ├── application-doc.yaml
│ │ ├── application-mariadb.yaml
│ │ ├── application-mysql.yaml
│ │ ├── application-postgresql.yaml
│ │ ├── application-win.yaml
│ │ ├── application.yaml
│ │ ├── banner.txt
│ │ ├── config/
│ │ │ └── i18n/
│ │ │ ├── messages.properties
│ │ │ ├── messages_es.properties
│ │ │ └── messages_zh.properties
│ │ ├── db/
│ │ │ └── migration/
│ │ │ ├── h2/
│ │ │ │ └── .gitkeep
│ │ │ ├── mariadb/
│ │ │ │ └── .gitkeep
│ │ │ ├── mysql/
│ │ │ │ └── .gitkeep
│ │ │ └── postgresql/
│ │ │ └── .gitkeep
│ │ ├── extensions/
│ │ │ ├── attachment-local-policy.yaml
│ │ │ ├── authproviders.yaml
│ │ │ ├── extension-definitions.yaml
│ │ │ ├── extensionpoint-definitions.yaml
│ │ │ ├── notification-templates.yaml
│ │ │ ├── notification.yaml
│ │ │ ├── role-template-actuator.yaml
│ │ │ ├── role-template-anonymous.yaml
│ │ │ ├── role-template-attachment.yaml
│ │ │ ├── role-template-authenticated.yaml
│ │ │ ├── role-template-cache.yaml
│ │ │ ├── role-template-category.yaml
│ │ │ ├── role-template-comment.yaml
│ │ │ ├── role-template-configmap.yaml
│ │ │ ├── role-template-menu.yaml
│ │ │ ├── role-template-migration.yaml
│ │ │ ├── role-template-notification.yaml
│ │ │ ├── role-template-permissions.yaml
│ │ │ ├── role-template-plugin.yaml
│ │ │ ├── role-template-post.yaml
│ │ │ ├── role-template-role.yaml
│ │ │ ├── role-template-setting.yaml
│ │ │ ├── role-template-singlepage.yaml
│ │ │ ├── role-template-snapshot.yaml
│ │ │ ├── role-template-tag.yaml
│ │ │ ├── role-template-theme.yaml
│ │ │ ├── role-template-uc-attachment.yaml
│ │ │ ├── role-template-uc-content.yaml
│ │ │ ├── role-template-user.yaml
│ │ │ ├── system-configurable-configmap.yaml
│ │ │ ├── system-default-role.yaml
│ │ │ ├── system-setting.yaml
│ │ │ └── user.yaml
│ │ ├── initial-data.yaml
│ │ ├── schema-h2.sql
│ │ ├── schema-mariadb.sql
│ │ ├── schema-mysql.sql
│ │ ├── schema-postgresql.sql
│ │ ├── static/
│ │ │ ├── halo-tracker.js
│ │ │ ├── js/
│ │ │ │ └── main.js
│ │ │ └── styles/
│ │ │ └── main.css
│ │ ├── templates/
│ │ │ ├── challenges/
│ │ │ │ └── two-factor/
│ │ │ │ ├── totp.html
│ │ │ │ ├── totp.properties
│ │ │ │ ├── totp_en.properties
│ │ │ │ ├── totp_es.properties
│ │ │ │ └── totp_zh_TW.properties
│ │ │ ├── error/
│ │ │ │ └── error.html
│ │ │ ├── gateway_fragments/
│ │ │ │ ├── common.html
│ │ │ │ ├── common.properties
│ │ │ │ ├── common_en.properties
│ │ │ │ ├── common_es.properties
│ │ │ │ ├── common_zh_TW.properties
│ │ │ │ ├── input.html
│ │ │ │ ├── layout.html
│ │ │ │ ├── login.html
│ │ │ │ ├── login.properties
│ │ │ │ ├── login_en.properties
│ │ │ │ ├── login_es.properties
│ │ │ │ ├── login_zh_TW.properties
│ │ │ │ ├── logout.html
│ │ │ │ ├── logout.properties
│ │ │ │ ├── logout_en.properties
│ │ │ │ ├── logout_es.properties
│ │ │ │ ├── logout_zh_TW.properties
│ │ │ │ ├── password_reset_email_reset.html
│ │ │ │ ├── password_reset_email_reset.properties
│ │ │ │ ├── password_reset_email_reset_en.properties
│ │ │ │ ├── password_reset_email_reset_es.properties
│ │ │ │ ├── password_reset_email_reset_zh_TW.properties
│ │ │ │ ├── password_reset_email_send.html
│ │ │ │ ├── password_reset_email_send.properties
│ │ │ │ ├── password_reset_email_send_en.properties
│ │ │ │ ├── password_reset_email_send_es.properties
│ │ │ │ ├── password_reset_email_send_zh_TW.properties
│ │ │ │ ├── signup.html
│ │ │ │ ├── signup.properties
│ │ │ │ ├── signup_en.properties
│ │ │ │ ├── signup_es.properties
│ │ │ │ ├── signup_zh_TW.properties
│ │ │ │ ├── totp.html
│ │ │ │ ├── totp.properties
│ │ │ │ ├── totp_en.properties
│ │ │ │ ├── totp_es.properties
│ │ │ │ └── totp_zh_TW.properties
│ │ │ ├── login.html
│ │ │ ├── login.properties
│ │ │ ├── login_en.properties
│ │ │ ├── login_es.properties
│ │ │ ├── login_local.html
│ │ │ ├── login_local.properties
│ │ │ ├── login_local_en.properties
│ │ │ ├── login_local_es.properties
│ │ │ ├── login_local_zh_TW.properties
│ │ │ ├── login_zh_TW.properties
│ │ │ ├── logout.html
│ │ │ ├── logout.properties
│ │ │ ├── logout_en.properties
│ │ │ ├── logout_es.properties
│ │ │ ├── logout_zh_TW.properties
│ │ │ ├── password-reset/
│ │ │ │ └── email/
│ │ │ │ ├── reset.html
│ │ │ │ ├── reset.properties
│ │ │ │ ├── reset_en.properties
│ │ │ │ ├── reset_es.properties
│ │ │ │ ├── reset_zh_TW.properties
│ │ │ │ ├── send.html
│ │ │ │ ├── send.properties
│ │ │ │ ├── send_en.properties
│ │ │ │ ├── send_es.properties
│ │ │ │ └── send_zh_TW.properties
│ │ │ ├── setup.html
│ │ │ ├── setup.properties
│ │ │ ├── setup_en.properties
│ │ │ ├── setup_es.properties
│ │ │ ├── setup_zh_TW.properties
│ │ │ ├── signup.html
│ │ │ ├── signup.properties
│ │ │ ├── signup_en.properties
│ │ │ ├── signup_es.properties
│ │ │ └── signup_zh_TW.properties
│ │ └── thumbnailator.properties
│ └── test/
│ ├── java/
│ │ └── run/
│ │ └── halo/
│ │ └── app/
│ │ ├── ApplicationTests.java
│ │ ├── PathPrefixPredicateTest.java
│ │ ├── XForwardHeaderTest.java
│ │ ├── config/
│ │ │ ├── CorsTest.java
│ │ │ ├── ExtensionConfigurationTest.java
│ │ │ ├── HaloConfigurationTest.java
│ │ │ ├── SecurityConfigTest.java
│ │ │ ├── ServerCodecTest.java
│ │ │ └── WebFluxConfigTest.java
│ │ ├── content/
│ │ │ ├── CategoryPostCountUpdaterTest.java
│ │ │ ├── ContentRequestTest.java
│ │ │ ├── PostIntegrationTests.java
│ │ │ ├── TestPost.java
│ │ │ ├── comment/
│ │ │ │ ├── CommentEmailOwnerTest.java
│ │ │ │ ├── CommentNotificationReasonPublisherTest.java
│ │ │ │ ├── CommentRequestTest.java
│ │ │ │ ├── CommentServiceImplIntegrationTest.java
│ │ │ │ ├── CommentServiceImplTest.java
│ │ │ │ ├── PostCommentSubjectTest.java
│ │ │ │ ├── ReplyNotificationSubscriptionHelperTest.java
│ │ │ │ ├── ReplyServiceImplIntegrationTest.java
│ │ │ │ └── SinglePageCommentSubjectTest.java
│ │ │ └── permalinks/
│ │ │ ├── CategoryPermalinkPolicyTest.java
│ │ │ ├── PostPermalinkPolicyTest.java
│ │ │ └── TagPermalinkPolicyTest.java
│ │ ├── core/
│ │ │ ├── attachment/
│ │ │ │ ├── PolicyConfigChangeDetectorTest.java
│ │ │ │ ├── endpoint/
│ │ │ │ │ ├── LocalAttachmentUploadHandlerTest.java
│ │ │ │ │ └── PolicyEndpointTest.java
│ │ │ │ ├── impl/
│ │ │ │ │ └── AttachmentRootGetterImplTest.java
│ │ │ │ └── thumbnail/
│ │ │ │ ├── DefaultLocalThumbnailServiceTest.java
│ │ │ │ ├── DefaultThumbnailServiceTest.java
│ │ │ │ ├── ThumbnailImgTagPostProcessorTest.java
│ │ │ │ ├── ThumbnailResourceTransformerTest.java
│ │ │ │ └── ThumbnailUtilsTest.java
│ │ │ ├── counter/
│ │ │ │ └── MeterUtilsTest.java
│ │ │ ├── endpoint/
│ │ │ │ ├── WebSocketHandlerMappingTest.java
│ │ │ │ ├── console/
│ │ │ │ │ ├── EmailVerificationCodeTest.java
│ │ │ │ │ ├── PluginEndpointTest.java
│ │ │ │ │ ├── PostEndpointTest.java
│ │ │ │ │ ├── SinglePageEndpointTest.java
│ │ │ │ │ ├── TagEndpointTest.java
│ │ │ │ │ ├── UserEndpointIntegrationTest.java
│ │ │ │ │ └── UserEndpointTest.java
│ │ │ │ ├── theme/
│ │ │ │ │ ├── CategoryQueryEndpointTest.java
│ │ │ │ │ ├── CommentFinderEndpointTest.java
│ │ │ │ │ ├── MenuQueryEndpointTest.java
│ │ │ │ │ ├── PluginQueryEndpointTest.java
│ │ │ │ │ ├── PostQueryEndpointTest.java
│ │ │ │ │ ├── PublicApiUtilsTest.java
│ │ │ │ │ ├── SinglePageQueryEndpointTest.java
│ │ │ │ │ └── ThumbnailEndpointTest.java
│ │ │ │ └── uc/
│ │ │ │ ├── AnnotationSettingEndpointTest.java
│ │ │ │ └── UcUserPreferenceEndpointTest.java
│ │ │ ├── extension/
│ │ │ │ ├── PostTest.java
│ │ │ │ ├── RoleBindingTest.java
│ │ │ │ ├── SettingTest.java
│ │ │ │ ├── TestRole.java
│ │ │ │ ├── ThemeTest.java
│ │ │ │ └── attachment/
│ │ │ │ └── endpoint/
│ │ │ │ └── AttachmentEndpointTest.java
│ │ │ ├── reconciler/
│ │ │ │ ├── CommentReconcilerTest.java
│ │ │ │ ├── MenuItemReconcilerTest.java
│ │ │ │ ├── PluginReconcilerTest.java
│ │ │ │ ├── PostReconcilerTest.java
│ │ │ │ ├── ReverseProxyReconcilerTest.java
│ │ │ │ ├── SinglePageReconcilerTest.java
│ │ │ │ ├── SystemConfigReconcilerTest.java
│ │ │ │ ├── TagReconcilerTest.java
│ │ │ │ ├── ThemeReconcilerTest.java
│ │ │ │ └── UserReconcilerTest.java
│ │ │ └── user/
│ │ │ └── service/
│ │ │ ├── DefaultRoleServiceTest.java
│ │ │ └── impl/
│ │ │ ├── EmailPasswordRecoveryServiceImplTest.java
│ │ │ ├── EmailVerificationServiceImplTest.java
│ │ │ └── UserServiceImplTest.java
│ │ ├── extension/
│ │ │ ├── AbstractExtensionTest.java
│ │ │ ├── ComparatorsTest.java
│ │ │ ├── ConfigMapTest.java
│ │ │ ├── DefaultSchemeManagerTest.java
│ │ │ ├── ExtensionOperatorTest.java
│ │ │ ├── ExtensionStoreUtilTest.java
│ │ │ ├── FakeExtension.java
│ │ │ ├── GroupVersionKindTest.java
│ │ │ ├── GroupVersionTest.java
│ │ │ ├── JsonExtensionConverterTest.java
│ │ │ ├── JsonExtensionTest.java
│ │ │ ├── ListResultTest.java
│ │ │ ├── MetadataOperatorTest.java
│ │ │ ├── ReactiveExtensionClientTest.java
│ │ │ ├── RefTest.java
│ │ │ ├── SchemeTest.java
│ │ │ ├── UnstructuredTest.java
│ │ │ ├── gc/
│ │ │ │ ├── GcReconcilerTest.java
│ │ │ │ ├── GcSynchronizerTest.java
│ │ │ │ └── GcWatcherTest.java
│ │ │ ├── index/
│ │ │ │ ├── DefaultIndexEngineTest.java
│ │ │ │ ├── DefaultIndicesManagerTest.java
│ │ │ │ ├── DefaultIndicesTest.java
│ │ │ │ ├── Fake.java
│ │ │ │ ├── LabelIndexTest.java
│ │ │ │ ├── MultiValueIndexTest.java
│ │ │ │ ├── SingleValueIndexTest.java
│ │ │ │ └── query/
│ │ │ │ └── QueryVisitorTest.java
│ │ │ ├── router/
│ │ │ │ ├── ExtensionCompositeRouterFunctionTest.java
│ │ │ │ ├── ExtensionCreateHandlerTest.java
│ │ │ │ ├── ExtensionDeleteHandlerTest.java
│ │ │ │ ├── ExtensionGetHandlerTest.java
│ │ │ │ ├── ExtensionListHandlerTest.java
│ │ │ │ ├── ExtensionRouterFunctionFactoryTest.java
│ │ │ │ ├── ExtensionUpdateHandlerTest.java
│ │ │ │ └── PathPatternGeneratorTest.java
│ │ │ └── store/
│ │ │ └── ReactiveExtensionStoreClientImplTest.java
│ │ ├── infra/
│ │ │ ├── ConditionListTest.java
│ │ │ ├── DefaultBackupRootGetterTest.java
│ │ │ ├── DefaultExternalLinkProcessorTest.java
│ │ │ ├── DefaultSystemConfigFetcherTest.java
│ │ │ ├── DefaultSystemVersionSupplierTest.java
│ │ │ ├── ExtensionResourceInitializerTest.java
│ │ │ ├── InitializationStateGetterTest.java
│ │ │ ├── ReactiveExtensionPaginatedOperatorImplTest.java
│ │ │ ├── SystemConfigFirstExternalUrlSupplierTest.java
│ │ │ ├── SystemSettingTest.java
│ │ │ ├── SystemStateTest.java
│ │ │ ├── ValidationUtilsTest.java
│ │ │ ├── config/
│ │ │ │ └── SessionConfigurationTest.java
│ │ │ ├── exception/
│ │ │ │ └── handlers/
│ │ │ │ └── I18nExceptionTest.java
│ │ │ ├── properties/
│ │ │ │ └── HaloPropertiesTest.java
│ │ │ └── utils/
│ │ │ ├── Base62UtilsTest.java
│ │ │ ├── FileNameUtilsTest.java
│ │ │ ├── FileTypeDetectUtilsTest.java
│ │ │ ├── FileUtilsTest.java
│ │ │ ├── HaloUtilsTest.java
│ │ │ ├── IpAddressUtilsTest.java
│ │ │ ├── SettingUtilsTest.java
│ │ │ ├── SortUtilsTest.java
│ │ │ ├── SystemConfigUtilsTest.java
│ │ │ ├── VersionUtilsTest.java
│ │ │ └── YamlUnstructuredLoaderTest.java
│ │ ├── migration/
│ │ │ ├── BackupReconcilerTest.java
│ │ │ └── impl/
│ │ │ └── MigrationServiceImplTest.java
│ │ ├── notification/
│ │ │ ├── DefaultNotificationCenterTest.java
│ │ │ ├── DefaultNotificationReasonEmitterTest.java
│ │ │ ├── DefaultNotificationSenderTest.java
│ │ │ ├── DefaultNotificationTemplateRenderTest.java
│ │ │ ├── DefaultNotifierConfigStoreTest.java
│ │ │ ├── DefaultSubscriberEmailResolverTest.java
│ │ │ ├── LanguageUtilsTest.java
│ │ │ ├── NotificationContextTest.java
│ │ │ ├── NotificationTriggerTest.java
│ │ │ ├── ReasonNotificationTemplateSelectorImplTest.java
│ │ │ ├── ReasonPayloadTest.java
│ │ │ ├── RecipientResolverImplTest.java
│ │ │ ├── SubscriptionServiceImplTest.java
│ │ │ ├── UserIdentityTest.java
│ │ │ ├── UserNotificationPreferenceServiceImplTest.java
│ │ │ ├── UserNotificationPreferenceTest.java
│ │ │ └── endpoint/
│ │ │ ├── SubscriptionRouterTest.java
│ │ │ └── UserNotificationPreferencesEndpointTest.java
│ │ ├── plugin/
│ │ │ ├── BuiltInPluginsInitializerTest.java
│ │ │ ├── DefaultDevelopmentPluginRepositoryTest.java
│ │ │ ├── DefaultPluginApplicationContextFactoryTest.java
│ │ │ ├── DefaultPluginRouterFunctionRegistryTest.java
│ │ │ ├── DefaultSettingFetcherTest.java
│ │ │ ├── HaloPluginManagerTest.java
│ │ │ ├── OptionalDependentResolverTest.java
│ │ │ ├── PluginExtensionLoaderUtilsTest.java
│ │ │ ├── PluginRequestMappingHandlerMappingTest.java
│ │ │ ├── PluginServiceImplTest.java
│ │ │ ├── PluginsRootGetterImplTest.java
│ │ │ ├── SharedApplicationContextFactoryTest.java
│ │ │ ├── SharedEventDispatcherTest.java
│ │ │ ├── SpringComponentsFinderTest.java
│ │ │ ├── YamlPluginDescriptorFinderTest.java
│ │ │ ├── YamlPluginFinderTest.java
│ │ │ ├── extensionpoint/
│ │ │ │ └── DefaultExtensionGetterTest.java
│ │ │ └── resources/
│ │ │ ├── BundleResourceUtilsTest.java
│ │ │ ├── ReverseProxyRouterFunctionFactoryTest.java
│ │ │ └── ReverseProxyRouterFunctionRegistryTest.java
│ │ ├── search/
│ │ │ ├── HaloDocumentEventsListenerTest.java
│ │ │ ├── IndexEndpointTest.java
│ │ │ ├── IndicesEndpointTest.java
│ │ │ ├── SearchServiceImplTest.java
│ │ │ ├── lucene/
│ │ │ │ ├── LuceneSearchEngineIntegrationTest.java
│ │ │ │ └── LuceneSearchEngineTest.java
│ │ │ └── post/
│ │ │ ├── PostEventsListenerTest.java
│ │ │ └── PostHaloDocumentsProviderTest.java
│ │ ├── security/
│ │ │ ├── AuthProviderServiceImplTest.java
│ │ │ ├── CsrfSecurityTest.java
│ │ │ ├── DefaultServerAuthenticationEntryPointTest.java
│ │ │ ├── DefaultSuperAdminInitializerTest.java
│ │ │ ├── DefaultUserDetailServiceTest.java
│ │ │ ├── HaloServerRequestCacheTest.java
│ │ │ ├── InitializeRedirectionWebFilterTest.java
│ │ │ ├── ResponseMap.java
│ │ │ ├── authentication/
│ │ │ │ ├── WebExchangeMatchersTest.java
│ │ │ │ ├── impl/
│ │ │ │ │ └── RsaKeyServiceTest.java
│ │ │ │ ├── login/
│ │ │ │ │ ├── LoginAuthenticationConverterTest.java
│ │ │ │ │ └── PublicKeyRouteBuilderTest.java
│ │ │ │ ├── pat/
│ │ │ │ │ └── PatTest.java
│ │ │ │ ├── rememberme/
│ │ │ │ │ ├── PersistentTokenBasedRememberMeServicesTest.java
│ │ │ │ │ ├── RememberTokenCleanerTest.java
│ │ │ │ │ └── TokenBasedRememberMeServicesTest.java
│ │ │ │ └── twofactor/
│ │ │ │ └── TwoFactorAuthSettingsTest.java
│ │ │ ├── authorization/
│ │ │ │ ├── AuthorityUtilsTest.java
│ │ │ │ ├── AuthorizationTest.java
│ │ │ │ ├── DefaultRuleResolverTest.java
│ │ │ │ ├── PolicyRuleTest.java
│ │ │ │ ├── RbacRequestEvaluationTest.java
│ │ │ │ └── RequestInfoResolverTest.java
│ │ │ ├── device/
│ │ │ │ └── DeviceServiceImplTest.java
│ │ │ ├── jackson2/
│ │ │ │ └── HaloSecurityJacksonModuleTest.java
│ │ │ ├── preauth/
│ │ │ │ └── SystemSetupEndpointTest.java
│ │ │ ├── session/
│ │ │ │ └── InMemoryReactiveIndexedSessionRepositoryTest.java
│ │ │ └── switchuser/
│ │ │ ├── SwitchUserConfigurerTest.java
│ │ │ ├── SwitchUserSecurityContextFactory.java
│ │ │ └── WithSwitchUser.java
│ │ ├── theme/
│ │ │ ├── CompositeTemplateResolverTest.java
│ │ │ ├── ReactiveFinderExpressionParserTests.java
│ │ │ ├── SiteSettingVariablesAcquirerTest.java
│ │ │ ├── ThemeContextTest.java
│ │ │ ├── ThemeIntegrationTest.java
│ │ │ ├── ThemeLinkBuilderTest.java
│ │ │ ├── ThemeLocaleContextResolverTest.java
│ │ │ ├── ViewNameResolverTest.java
│ │ │ ├── dialect/
│ │ │ │ ├── CommentElementTagProcessorTest.java
│ │ │ │ ├── CommentEnabledVariableProcessorTest.java
│ │ │ │ ├── ContentTemplateHeadProcessorIntegrationTest.java
│ │ │ │ ├── ContentTemplateHeadProcessorTest.java
│ │ │ │ ├── DuplicateMetaTagProcessorTest.java
│ │ │ │ ├── GeneratorMetaProcessorTest.java
│ │ │ │ ├── HaloPostTemplateHandlerTest.java
│ │ │ │ ├── HaloProcessorDialectTest.java
│ │ │ │ ├── HaloSpringSecurityDialectTest.java
│ │ │ │ ├── InjectionExcluderProcessorTest.java
│ │ │ │ ├── LinkExpressionObjectDialectTest.java
│ │ │ │ └── TemplateFooterElementTagProcessorTest.java
│ │ │ ├── endpoint/
│ │ │ │ └── ThemeEndpointTest.java
│ │ │ ├── engine/
│ │ │ │ ├── DefaultThemeTemplateAvailabilityProviderTest.java
│ │ │ │ └── PluginClassloaderTemplateResolverTest.java
│ │ │ ├── finders/
│ │ │ │ ├── FinderRegistryTest.java
│ │ │ │ ├── impl/
│ │ │ │ │ ├── CategoryFinderImplTest.java
│ │ │ │ │ ├── CommentPublicQueryServiceImplTest.java
│ │ │ │ │ ├── CommentPublicQueryServiceIntegrationTest.java
│ │ │ │ │ ├── MenuFinderImplTest.java
│ │ │ │ │ ├── PluginFinderImplTest.java
│ │ │ │ │ ├── PostFinderImplIntegrationTest.java
│ │ │ │ │ ├── PostFinderImplTest.java
│ │ │ │ │ ├── PostPublicQueryServiceImplTest.java
│ │ │ │ │ ├── SinglePageConversionServiceImplTest.java
│ │ │ │ │ ├── SinglePageFinderImplTest.java
│ │ │ │ │ ├── TagFinderImplTest.java
│ │ │ │ │ └── ThumbnailFinderImplTest.java
│ │ │ │ └── vo/
│ │ │ │ └── UserVoTest.java
│ │ │ ├── message/
│ │ │ │ ├── ThemeMessageResolutionUtilsTest.java
│ │ │ │ └── ThemeMessageResolverIntegrationTest.java
│ │ │ ├── router/
│ │ │ │ ├── EmptyView.java
│ │ │ │ ├── PageUrlUtilsTest.java
│ │ │ │ ├── PreviewRouterFunctionTest.java
│ │ │ │ ├── ReactiveQueryPostPredicateResolverTest.java
│ │ │ │ ├── SinglePageRouteTest.java
│ │ │ │ └── factories/
│ │ │ │ ├── ArchiveRouteFactoryTest.java
│ │ │ │ ├── AuthorPostsRouteFactoryTest.java
│ │ │ │ ├── CategoriesRouteFactoryTest.java
│ │ │ │ ├── IndexRouteFactoryTest.java
│ │ │ │ ├── PostRouteFactoryTest.java
│ │ │ │ ├── RouteFactoryTest.java
│ │ │ │ ├── RouteFactoryTestSuite.java
│ │ │ │ └── TagPostRouteFactoryTest.java
│ │ │ ├── service/
│ │ │ │ └── ThemeServiceImplTest.java
│ │ │ └── utils/
│ │ │ └── PatternUtilsTest.java
│ │ ├── ui/
│ │ │ ├── WebSocketServerWebExchangeMatcherTest.java
│ │ │ └── WebSocketUtilsTest.java
│ │ └── webfilter/
│ │ └── LocaleChangeWebFilterTest.java
│ └── resources/
│ ├── apiToken.salt
│ ├── app.key
│ ├── app.pub
│ ├── application.yaml
│ ├── backups/
│ │ └── backup-for-restoration/
│ │ ├── extensions.data
│ │ └── workdir/
│ │ └── fake-file
│ ├── categories/
│ │ └── independent-post-count.json
│ ├── config/
│ │ └── i18n/
│ │ ├── messages.properties
│ │ └── messages_zh.properties
│ ├── console/
│ │ ├── assets/
│ │ │ └── fake.txt
│ │ └── index.html
│ ├── file-type-detect/
│ │ ├── index.html
│ │ ├── index.js
│ │ ├── other.xlsx
│ │ ├── test.docx
│ │ └── test.json
│ ├── folder-to-zip/
│ │ └── examplefile
│ ├── plugin/
│ │ ├── plugin-0.0.1/
│ │ │ ├── extensions/
│ │ │ │ ├── reverseProxy.yaml
│ │ │ │ ├── roles.yaml
│ │ │ │ ├── setting.yaml
│ │ │ │ └── test.yml
│ │ │ └── plugin.yaml
│ │ ├── plugin-0.0.2/
│ │ │ └── plugin.yaml
│ │ ├── plugin-for-finder/
│ │ │ └── META-INF/
│ │ │ └── plugin-components.idx
│ │ ├── plugin-for-reverseproxy/
│ │ │ └── static/
│ │ │ └── test.txt
│ │ └── plugin.yaml
│ ├── presets/
│ │ └── plugins/
│ │ └── fake-plugin.jar
│ ├── themes/
│ │ ├── default/
│ │ │ ├── i18n/
│ │ │ │ ├── default.properties
│ │ │ │ ├── en.properties
│ │ │ │ └── zh.properties
│ │ │ ├── templates/
│ │ │ │ ├── index.html
│ │ │ │ ├── index.properties
│ │ │ │ ├── index_zh.properties
│ │ │ │ └── timezone.html
│ │ │ └── theme.yaml
│ │ ├── invalid-missing-manifest/
│ │ │ ├── i18n/
│ │ │ │ ├── default.properties
│ │ │ │ └── en.properties
│ │ │ └── templates/
│ │ │ ├── index.html
│ │ │ └── timezone.html
│ │ └── other/
│ │ ├── i18n/
│ │ │ ├── default.properties
│ │ │ └── en.properties
│ │ ├── templates/
│ │ │ └── index.html
│ │ └── theme.yaml
│ └── ui/
│ ├── console.html
│ ├── uc.html
│ └── ui-assets/
│ └── fake.txt
├── buildSrc/
│ ├── build.gradle
│ └── src/
│ └── main/
│ └── groovy/
│ ├── UploadBundleTask.groovy
│ └── halo.publish.gradle
├── config/
│ └── checkstyle/
│ └── checkstyle.xml
├── docs/
│ ├── authentication/
│ │ └── README.md
│ ├── backup-and-restore.md
│ ├── cache/
│ │ └── page.md
│ ├── developer-guide/
│ │ ├── custom-endpoint.md
│ │ └── plugin-configuration-properties.md
│ ├── email-verification/
│ │ └── README.md
│ ├── extension-points/
│ │ ├── authentication.md
│ │ ├── content.md
│ │ └── search-engine.md
│ ├── full-text-search/
│ │ └── README.md
│ ├── index/
│ │ └── README.md
│ ├── notification/
│ │ └── README.md
│ └── plugin/
│ ├── shared-event.md
│ └── websocket.md
├── e2e/
│ ├── Dockerfile
│ ├── Makefile
│ ├── README.md
│ ├── compose-mysql.yaml
│ ├── compose-postgres.yaml
│ ├── compose.yaml
│ ├── start.sh
│ └── testsuite.yaml
├── gradle/
│ ├── libs.versions.toml
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── hack/
│ └── cherry_pick_pull.sh
├── platform/
│ ├── application/
│ │ └── build.gradle
│ └── plugin/
│ └── build.gradle
├── settings.gradle
└── ui/
├── .editorconfig
├── .husky/
│ └── pre-commit
├── .npmrc
├── .oxfmtrc.json
├── Makefile
├── build.gradle
├── console-src/
│ ├── App.vue
│ ├── components/
│ │ └── snapshots/
│ │ ├── BaseSnapshots.vue
│ │ ├── SnapshotContent.vue
│ │ ├── SnapshotDiffContent.vue
│ │ ├── SnapshotListItem.vue
│ │ └── query-keys.ts
│ ├── composables/
│ │ ├── use-content-snapshot.ts
│ │ ├── use-dashboard-stats.ts
│ │ ├── use-entity-extension-points.ts
│ │ ├── use-operation-extension-points.ts
│ │ ├── use-save-keybinding.ts
│ │ └── use-slugify.ts
│ ├── layouts/
│ │ ├── BasicLayout.vue
│ │ └── BlankLayout.vue
│ ├── main.ts
│ ├── modules/
│ │ ├── contents/
│ │ │ ├── attachments/
│ │ │ │ ├── AttachmentList.vue
│ │ │ │ ├── components/
│ │ │ │ │ ├── AttachmentDetailModal.vue
│ │ │ │ │ ├── AttachmentError.vue
│ │ │ │ │ ├── AttachmentGroupBadge.vue
│ │ │ │ │ ├── AttachmentGroupEditingModal.vue
│ │ │ │ │ ├── AttachmentGroupList.vue
│ │ │ │ │ ├── AttachmentListItem.vue
│ │ │ │ │ ├── AttachmentLoading.vue
│ │ │ │ │ ├── AttachmentPoliciesListItem.vue
│ │ │ │ │ ├── AttachmentPoliciesModal.vue
│ │ │ │ │ ├── AttachmentPolicyBadge.vue
│ │ │ │ │ ├── AttachmentPolicyEditingModal.vue
│ │ │ │ │ ├── AttachmentSelectorModal.vue
│ │ │ │ │ ├── AttachmentUploadArea.vue
│ │ │ │ │ ├── AttachmentUploadModal.vue
│ │ │ │ │ ├── DisplayNameEditForm.vue
│ │ │ │ │ ├── UploadFromUrl.vue
│ │ │ │ │ └── selector-providers/
│ │ │ │ │ ├── CoreSelectorProvider.vue
│ │ │ │ │ └── components/
│ │ │ │ │ ├── AttachmentSelectorListItem.vue
│ │ │ │ │ ├── GroupFilter.vue
│ │ │ │ │ └── PolicyFilter.vue
│ │ │ │ ├── composables/
│ │ │ │ │ ├── use-attachment-group.ts
│ │ │ │ │ ├── use-attachment-policy.ts
│ │ │ │ │ └── use-attachment.ts
│ │ │ │ └── module.ts
│ │ │ ├── comments/
│ │ │ │ ├── CommentList.vue
│ │ │ │ ├── components/
│ │ │ │ │ ├── CommentDetailModal.vue
│ │ │ │ │ ├── CommentEditor.vue
│ │ │ │ │ ├── CommentListItem.vue
│ │ │ │ │ ├── DefaultCommentContent.vue
│ │ │ │ │ ├── DefaultCommentEditor.vue
│ │ │ │ │ ├── OwnerButton.vue
│ │ │ │ │ ├── ReplyCreationModal.vue
│ │ │ │ │ ├── ReplyDetailModal.vue
│ │ │ │ │ ├── ReplyListItem.vue
│ │ │ │ │ ├── SubjectQueryCommentList.vue
│ │ │ │ │ └── SubjectQueryCommentListModal.vue
│ │ │ │ ├── composables/
│ │ │ │ │ ├── use-comment-last-readtime-mutate.ts
│ │ │ │ │ ├── use-comments-fetch.ts
│ │ │ │ │ ├── use-content-provider-extension-point.ts
│ │ │ │ │ └── use-subject-ref.ts
│ │ │ │ └── module.ts
│ │ │ ├── pages/
│ │ │ │ ├── DeletedSinglePageList.vue
│ │ │ │ ├── SinglePageEditor.vue
│ │ │ │ ├── SinglePageList.vue
│ │ │ │ ├── SinglePageSnapshots.vue
│ │ │ │ ├── components/
│ │ │ │ │ ├── SinglePageListItem.vue
│ │ │ │ │ ├── SinglePageSettingModal.vue
│ │ │ │ │ └── entity-fields/
│ │ │ │ │ ├── ContributorsField.vue
│ │ │ │ │ ├── CoverField.vue
│ │ │ │ │ ├── PublishStatusField.vue
│ │ │ │ │ ├── PublishTimeField.vue
│ │ │ │ │ ├── TitleField.vue
│ │ │ │ │ └── VisibleField.vue
│ │ │ │ ├── composables/
│ │ │ │ │ └── use-page-update-mutate.ts
│ │ │ │ └── module.ts
│ │ │ └── posts/
│ │ │ ├── DeletedPostList.vue
│ │ │ ├── PostEditor.vue
│ │ │ ├── PostList.vue
│ │ │ ├── PostSnapshots.vue
│ │ │ ├── categories/
│ │ │ │ ├── CategoryList.vue
│ │ │ │ ├── components/
│ │ │ │ │ ├── CategoryEditingModal.vue
│ │ │ │ │ ├── CategoryListItem.vue
│ │ │ │ │ └── __tests__/
│ │ │ │ │ └── CategoryEditingModal.spec.ts
│ │ │ │ ├── composables/
│ │ │ │ │ └── use-post-category.ts
│ │ │ │ └── utils/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.ts
│ │ │ │ └── index.ts
│ │ │ ├── components/
│ │ │ │ ├── PostBatchSettingModal.vue
│ │ │ │ ├── PostListItem.vue
│ │ │ │ ├── PostSettingModal.vue
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── PostSettingModal.spec.ts
│ │ │ │ └── entity-fields/
│ │ │ │ ├── ContributorsField.vue
│ │ │ │ ├── CoverField.vue
│ │ │ │ ├── PublishStatusField.vue
│ │ │ │ ├── PublishTimeField.vue
│ │ │ │ ├── TitleField.vue
│ │ │ │ └── VisibleField.vue
│ │ │ ├── composables/
│ │ │ │ └── use-post-update-mutate.ts
│ │ │ ├── module.ts
│ │ │ └── tags/
│ │ │ ├── TagList.vue
│ │ │ ├── components/
│ │ │ │ ├── PostTag.vue
│ │ │ │ ├── TagEditingModal.vue
│ │ │ │ └── TagListItem.vue
│ │ │ └── composables/
│ │ │ └── use-post-tag.ts
│ │ ├── dashboard/
│ │ │ ├── Dashboard.vue
│ │ │ ├── DashboardDesigner.vue
│ │ │ ├── components/
│ │ │ │ ├── ActionButton.vue
│ │ │ │ ├── WidgetCard.vue
│ │ │ │ ├── WidgetConfigFormModal.vue
│ │ │ │ ├── WidgetEditableItem.vue
│ │ │ │ ├── WidgetHubModal.vue
│ │ │ │ └── WidgetViewItem.vue
│ │ │ ├── composables/
│ │ │ │ ├── use-dashboard-extension-point.ts
│ │ │ │ └── use-dashboard-widgets-fetch.ts
│ │ │ ├── module.ts
│ │ │ ├── styles/
│ │ │ │ └── dashboard.css
│ │ │ └── widgets/
│ │ │ ├── defaults.ts
│ │ │ ├── index.ts
│ │ │ └── presets/
│ │ │ ├── comments/
│ │ │ │ ├── CommentItem.vue
│ │ │ │ ├── CommentStatsWidget.vue
│ │ │ │ └── PendingCommentsWidget.vue
│ │ │ ├── core/
│ │ │ │ ├── iframe/
│ │ │ │ │ └── IframeWidget.vue
│ │ │ │ ├── quick-action/
│ │ │ │ │ ├── QuickActionItem.vue
│ │ │ │ │ ├── QuickActionWidget.vue
│ │ │ │ │ ├── ThemePreviewItem.vue
│ │ │ │ │ └── composables/
│ │ │ │ │ └── use-dashboard-extension-point.ts
│ │ │ │ ├── stack/
│ │ │ │ │ ├── StackWidget.vue
│ │ │ │ │ ├── StackWidgetConfigModal.vue
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── IndexIndicator.vue
│ │ │ │ │ │ ├── WidgetEditableItem.vue
│ │ │ │ │ │ └── WidgetViewItem.vue
│ │ │ │ │ └── types.ts
│ │ │ │ ├── upvotes-stats/
│ │ │ │ │ └── UpvotesStatsWidget.vue
│ │ │ │ └── view-stats/
│ │ │ │ └── ViewsStatsWidget.vue
│ │ │ ├── posts/
│ │ │ │ ├── PostStatsWidget.vue
│ │ │ │ ├── RecentPublishedWidget.vue
│ │ │ │ └── components/
│ │ │ │ └── PostListItem.vue
│ │ │ ├── single-pages/
│ │ │ │ └── SinglePageStatsWidget.vue
│ │ │ └── users/
│ │ │ ├── NotificationWidget.vue
│ │ │ └── UserStatsWidget.vue
│ │ ├── index.ts
│ │ ├── interface/
│ │ │ ├── menus/
│ │ │ │ ├── Menus.vue
│ │ │ │ ├── components/
│ │ │ │ │ ├── MenuEditingModal.vue
│ │ │ │ │ ├── MenuItemEditingModal.vue
│ │ │ │ │ └── MenuList.vue
│ │ │ │ ├── module.ts
│ │ │ │ └── utils/
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── index.spec.ts.snap
│ │ │ │ │ └── index.spec.ts
│ │ │ │ └── index.ts
│ │ │ └── themes/
│ │ │ ├── ThemeDetail.vue
│ │ │ ├── ThemeSetting.vue
│ │ │ ├── components/
│ │ │ │ ├── ThemeListItem.vue
│ │ │ │ ├── ThemeListModal.vue
│ │ │ │ ├── list-tabs/
│ │ │ │ │ ├── InstalledThemes.vue
│ │ │ │ │ ├── LocalUpload.vue
│ │ │ │ │ ├── NotInstalledThemes.vue
│ │ │ │ │ └── RemoteDownload.vue
│ │ │ │ ├── operation/
│ │ │ │ │ ├── MoreOperationItem.vue
│ │ │ │ │ └── UninstallOperationItem.vue
│ │ │ │ └── preview/
│ │ │ │ ├── ThemePreviewListItem.vue
│ │ │ │ └── ThemePreviewModal.vue
│ │ │ ├── composables/
│ │ │ │ └── use-theme.ts
│ │ │ ├── constants/
│ │ │ │ └── index.ts
│ │ │ ├── layouts/
│ │ │ │ └── ThemeLayout.vue
│ │ │ ├── module.ts
│ │ │ └── types/
│ │ │ └── index.ts
│ │ └── system/
│ │ ├── auth-providers/
│ │ │ ├── AuthProviderDetail.vue
│ │ │ ├── AuthProviders.vue
│ │ │ ├── components/
│ │ │ │ ├── AuthProviderListItem.vue
│ │ │ │ └── AuthProvidersSection.vue
│ │ │ └── module.ts
│ │ ├── backup/
│ │ │ ├── Backups.vue
│ │ │ ├── components/
│ │ │ │ └── BackupListItem.vue
│ │ │ ├── composables/
│ │ │ │ └── use-backup.ts
│ │ │ ├── module.ts
│ │ │ └── tabs/
│ │ │ ├── List.vue
│ │ │ └── Restore.vue
│ │ ├── overview/
│ │ │ ├── Overview.vue
│ │ │ ├── components/
│ │ │ │ ├── ExternalUrlForm.vue
│ │ │ │ └── ExternalUrlItem.vue
│ │ │ └── module.ts
│ │ ├── plugins/
│ │ │ ├── PluginDetail.vue
│ │ │ ├── PluginExtensionPointSettings.vue
│ │ │ ├── PluginList.vue
│ │ │ ├── components/
│ │ │ │ ├── PluginConditionsModal.vue
│ │ │ │ ├── PluginDetailModal.vue
│ │ │ │ ├── PluginInstallationModal.vue
│ │ │ │ ├── PluginListItem.vue
│ │ │ │ ├── entity-fields/
│ │ │ │ │ ├── AuthorField.vue
│ │ │ │ │ ├── LogoField.vue
│ │ │ │ │ ├── ReloadField.vue
│ │ │ │ │ ├── SwitchField.vue
│ │ │ │ │ └── TitleField.vue
│ │ │ │ ├── extension-points/
│ │ │ │ │ ├── ExtensionDefinitionListItem.vue
│ │ │ │ │ ├── ExtensionDefinitionMultiInstanceView.vue
│ │ │ │ │ └── ExtensionDefinitionSingletonView.vue
│ │ │ │ ├── installation-tabs/
│ │ │ │ │ ├── LocalUpload.vue
│ │ │ │ │ └── RemoteDownload.vue
│ │ │ │ └── tabs/
│ │ │ │ ├── Detail.vue
│ │ │ │ └── Setting.vue
│ │ │ ├── composables/
│ │ │ │ ├── use-extension-definition-fetch.ts
│ │ │ │ └── use-plugin.ts
│ │ │ ├── constants/
│ │ │ │ └── index.ts
│ │ │ ├── module.ts
│ │ │ └── types/
│ │ │ └── index.ts
│ │ ├── roles/
│ │ │ ├── RoleDetail.vue
│ │ │ ├── RoleList.vue
│ │ │ ├── components/
│ │ │ │ └── RoleEditingModal.vue
│ │ │ └── module.ts
│ │ ├── settings/
│ │ │ ├── SystemSettings.vue
│ │ │ ├── module.ts
│ │ │ └── tabs/
│ │ │ ├── NotificationSetting.vue
│ │ │ ├── Notifications.vue
│ │ │ └── Setting.vue
│ │ ├── tools/
│ │ │ ├── Tools.vue
│ │ │ └── module.ts
│ │ └── users/
│ │ ├── UserDetail.vue
│ │ ├── UserList.vue
│ │ ├── components/
│ │ │ ├── GrantPermissionModal.vue
│ │ │ ├── RolesView.vue
│ │ │ ├── UserCreationModal.vue
│ │ │ ├── UserEditingModal.vue
│ │ │ ├── UserListItem.vue
│ │ │ └── UserPasswordChangeModal.vue
│ │ ├── composables/
│ │ │ ├── use-role.ts
│ │ │ └── use-user.ts
│ │ ├── module.ts
│ │ └── tabs/
│ │ └── Detail.vue
│ ├── router/
│ │ ├── constant.ts
│ │ ├── guards/
│ │ │ ├── auth-check.ts
│ │ │ └── permission.ts
│ │ ├── index.ts
│ │ └── routes.config.ts
│ └── stores/
│ └── theme.ts
├── console.html
├── docs/
│ ├── components/
│ │ └── README.md
│ ├── custom-formkit-input/
│ │ └── README.md
│ ├── extension-points/
│ │ ├── backup.md
│ │ ├── comment-content.md
│ │ ├── comment-editor.md
│ │ ├── comment-subject-ref.md
│ │ ├── dashboard.md
│ │ ├── default-editor–extension.md
│ │ ├── editor.md
│ │ ├── entity-listitem-field.md
│ │ ├── entity-listitem-operation.md
│ │ ├── plugin-installation-tabs.md
│ │ ├── plugin-self-tabs.md
│ │ └── theme-list-tabs.md
│ ├── project-structure/
│ │ └── README.md
│ └── routes-generation/
│ └── README.md
├── env.d.ts
├── eslint.config.ts
├── package.json
├── packages/
│ ├── api-client/
│ │ ├── .openapi_config.yaml
│ │ ├── README.md
│ │ ├── entry/
│ │ │ ├── api-client.ts
│ │ │ ├── index.ts
│ │ │ └── utils/
│ │ │ ├── index.ts
│ │ │ └── paginate.ts
│ │ ├── openapitools.json
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── .gitignore
│ │ │ ├── .npmignore
│ │ │ ├── .openapi-generator/
│ │ │ │ ├── FILES
│ │ │ │ └── VERSION
│ │ │ ├── .openapi-generator-ignore
│ │ │ ├── api/
│ │ │ │ ├── annotation-setting-v1-alpha-uc-api.ts
│ │ │ │ ├── annotation-setting-v1alpha1-api.ts
│ │ │ │ ├── attachment-v1alpha1-api.ts
│ │ │ │ ├── attachment-v1alpha1-console-api.ts
│ │ │ │ ├── attachment-v1alpha1-uc-api.ts
│ │ │ │ ├── auth-provider-v1alpha1-api.ts
│ │ │ │ ├── auth-provider-v1alpha1-console-api.ts
│ │ │ │ ├── backup-v1alpha1-api.ts
│ │ │ │ ├── category-v1alpha1-api.ts
│ │ │ │ ├── category-v1alpha1-public-api.ts
│ │ │ │ ├── comment-v1alpha1-api.ts
│ │ │ │ ├── comment-v1alpha1-console-api.ts
│ │ │ │ ├── comment-v1alpha1-public-api.ts
│ │ │ │ ├── config-map-v1alpha1-api.ts
│ │ │ │ ├── counter-v1alpha1-api.ts
│ │ │ │ ├── device-v1alpha1-api.ts
│ │ │ │ ├── device-v1alpha1-uc-api.ts
│ │ │ │ ├── extension-definition-v1alpha1-api.ts
│ │ │ │ ├── extension-point-definition-v1alpha1-api.ts
│ │ │ │ ├── group-v1alpha1-api.ts
│ │ │ │ ├── index-v1alpha1-public-api.ts
│ │ │ │ ├── indices-v1alpha1-console-api.ts
│ │ │ │ ├── local-thumbnail-v1alpha1-api.ts
│ │ │ │ ├── menu-item-v1alpha1-api.ts
│ │ │ │ ├── menu-v1alpha1-api.ts
│ │ │ │ ├── menu-v1alpha1-public-api.ts
│ │ │ │ ├── metrics-v1alpha1-public-api.ts
│ │ │ │ ├── migration-v1alpha1-console-api.ts
│ │ │ │ ├── notification-template-v1alpha1-api.ts
│ │ │ │ ├── notification-v1alpha1-api.ts
│ │ │ │ ├── notification-v1alpha1-public-api.ts
│ │ │ │ ├── notification-v1alpha1-uc-api.ts
│ │ │ │ ├── notifier-descriptor-v1alpha1-api.ts
│ │ │ │ ├── notifier-v1alpha1-console-api.ts
│ │ │ │ ├── notifier-v1alpha1-uc-api.ts
│ │ │ │ ├── personal-access-token-v1alpha1-api.ts
│ │ │ │ ├── personal-access-token-v1alpha1-uc-api.ts
│ │ │ │ ├── plugin-v1alpha1-api.ts
│ │ │ │ ├── plugin-v1alpha1-console-api.ts
│ │ │ │ ├── plugin-v1alpha1-public-api.ts
│ │ │ │ ├── policy-alpha1-console-api.ts
│ │ │ │ ├── policy-template-v1alpha1-api.ts
│ │ │ │ ├── policy-v1alpha1-api.ts
│ │ │ │ ├── post-v1alpha1-api.ts
│ │ │ │ ├── post-v1alpha1-console-api.ts
│ │ │ │ ├── post-v1alpha1-public-api.ts
│ │ │ │ ├── post-v1alpha1-uc-api.ts
│ │ │ │ ├── reason-type-v1alpha1-api.ts
│ │ │ │ ├── reason-v1alpha1-api.ts
│ │ │ │ ├── remember-me-token-v1alpha1-api.ts
│ │ │ │ ├── reply-v1alpha1-api.ts
│ │ │ │ ├── reply-v1alpha1-console-api.ts
│ │ │ │ ├── reverse-proxy-v1alpha1-api.ts
│ │ │ │ ├── role-binding-v1alpha1-api.ts
│ │ │ │ ├── role-v1alpha1-api.ts
│ │ │ │ ├── secret-v1alpha1-api.ts
│ │ │ │ ├── setting-v1alpha1-api.ts
│ │ │ │ ├── single-page-v1alpha1-api.ts
│ │ │ │ ├── single-page-v1alpha1-console-api.ts
│ │ │ │ ├── single-page-v1alpha1-public-api.ts
│ │ │ │ ├── snapshot-v1alpha1-api.ts
│ │ │ │ ├── snapshot-v1alpha1-uc-api.ts
│ │ │ │ ├── subscription-v1alpha1-api.ts
│ │ │ │ ├── system-config-v1alpha1-console-api.ts
│ │ │ │ ├── system-v1alpha1-console-api.ts
│ │ │ │ ├── system-v1alpha1-public-api.ts
│ │ │ │ ├── tag-v1alpha1-api.ts
│ │ │ │ ├── tag-v1alpha1-console-api.ts
│ │ │ │ ├── tag-v1alpha1-public-api.ts
│ │ │ │ ├── theme-v1alpha1-api.ts
│ │ │ │ ├── theme-v1alpha1-console-api.ts
│ │ │ │ ├── thumbnail-v1alpha1-api.ts
│ │ │ │ ├── thumbnail-v1alpha1-public-api.ts
│ │ │ │ ├── two-factor-auth-v1alpha1-uc-api.ts
│ │ │ │ ├── user-connection-v1alpha1-api.ts
│ │ │ │ ├── user-connection-v1alpha1-uc-api.ts
│ │ │ │ ├── user-preference-v1alpha1-uc-api.ts
│ │ │ │ ├── user-v1alpha1-api.ts
│ │ │ │ └── user-v1alpha1-console-api.ts
│ │ │ ├── api.ts
│ │ │ ├── base.ts
│ │ │ ├── common.ts
│ │ │ ├── configuration.ts
│ │ │ ├── git_push.sh
│ │ │ ├── index.ts
│ │ │ └── models/
│ │ │ ├── add-operation.ts
│ │ │ ├── annotation-setting-list.ts
│ │ │ ├── annotation-setting-spec.ts
│ │ │ ├── annotation-setting.ts
│ │ │ ├── attachment-list.ts
│ │ │ ├── attachment-spec.ts
│ │ │ ├── attachment-status.ts
│ │ │ ├── attachment.ts
│ │ │ ├── auth-provider-list.ts
│ │ │ ├── auth-provider-spec.ts
│ │ │ ├── auth-provider.ts
│ │ │ ├── author.ts
│ │ │ ├── backup-file.ts
│ │ │ ├── backup-list.ts
│ │ │ ├── backup-spec.ts
│ │ │ ├── backup-status.ts
│ │ │ ├── backup.ts
│ │ │ ├── category-list.ts
│ │ │ ├── category-spec.ts
│ │ │ ├── category-status.ts
│ │ │ ├── category-vo-list.ts
│ │ │ ├── category-vo.ts
│ │ │ ├── category.ts
│ │ │ ├── change-own-password-request.ts
│ │ │ ├── change-password-request.ts
│ │ │ ├── comment-email-owner.ts
│ │ │ ├── comment-list.ts
│ │ │ ├── comment-owner.ts
│ │ │ ├── comment-request.ts
│ │ │ ├── comment-spec.ts
│ │ │ ├── comment-stats-vo.ts
│ │ │ ├── comment-stats.ts
│ │ │ ├── comment-status.ts
│ │ │ ├── comment-vo-list.ts
│ │ │ ├── comment-vo.ts
│ │ │ ├── comment-with-reply-vo-list.ts
│ │ │ ├── comment-with-reply-vo.ts
│ │ │ ├── comment.ts
│ │ │ ├── condition.ts
│ │ │ ├── config-map-list.ts
│ │ │ ├── config-map-ref.ts
│ │ │ ├── config-map.ts
│ │ │ ├── content-update-param.ts
│ │ │ ├── content-vo.ts
│ │ │ ├── content-wrapper.ts
│ │ │ ├── content.ts
│ │ │ ├── contributor-vo.ts
│ │ │ ├── contributor.ts
│ │ │ ├── copy-operation.ts
│ │ │ ├── counter-list.ts
│ │ │ ├── counter-request.ts
│ │ │ ├── counter.ts
│ │ │ ├── create-user-request.ts
│ │ │ ├── custom-templates.ts
│ │ │ ├── dashboard-stats.ts
│ │ │ ├── detailed-user.ts
│ │ │ ├── device-list.ts
│ │ │ ├── device-spec.ts
│ │ │ ├── device-status.ts
│ │ │ ├── device.ts
│ │ │ ├── email-config-validation-request.ts
│ │ │ ├── email-verify-request.ts
│ │ │ ├── excerpt.ts
│ │ │ ├── extension-definition-list.ts
│ │ │ ├── extension-definition.ts
│ │ │ ├── extension-point-definition-list.ts
│ │ │ ├── extension-point-definition.ts
│ │ │ ├── extension-point-spec.ts
│ │ │ ├── extension-spec.ts
│ │ │ ├── extension.ts
│ │ │ ├── file-reverse-proxy-provider.ts
│ │ │ ├── grant-request.ts
│ │ │ ├── group-kind.ts
│ │ │ ├── group-list.ts
│ │ │ ├── group-spec.ts
│ │ │ ├── group-status.ts
│ │ │ ├── group.ts
│ │ │ ├── halo-document.ts
│ │ │ ├── index.ts
│ │ │ ├── install-from-uri-request.ts
│ │ │ ├── interest-reason-subject.ts
│ │ │ ├── interest-reason.ts
│ │ │ ├── json-patch-inner.ts
│ │ │ ├── license.ts
│ │ │ ├── list-result-reply-vo.ts
│ │ │ ├── listed-auth-provider.ts
│ │ │ ├── listed-comment-list.ts
│ │ │ ├── listed-comment.ts
│ │ │ ├── listed-post-list.ts
│ │ │ ├── listed-post-vo-list.ts
│ │ │ ├── listed-post-vo.ts
│ │ │ ├── listed-post.ts
│ │ │ ├── listed-reply-list.ts
│ │ │ ├── listed-reply.ts
│ │ │ ├── listed-single-page-list.ts
│ │ │ ├── listed-single-page-vo-list.ts
│ │ │ ├── listed-single-page-vo.ts
│ │ │ ├── listed-single-page.ts
│ │ │ ├── listed-snapshot-dto.ts
│ │ │ ├── listed-snapshot-spec.ts
│ │ │ ├── listed-user.ts
│ │ │ ├── local-thumbnail-list.ts
│ │ │ ├── local-thumbnail-spec.ts
│ │ │ ├── local-thumbnail-status.ts
│ │ │ ├── local-thumbnail.ts
│ │ │ ├── mark-specified-request.ts
│ │ │ ├── menu-item-list.ts
│ │ │ ├── menu-item-spec.ts
│ │ │ ├── menu-item-status.ts
│ │ │ ├── menu-item-vo.ts
│ │ │ ├── menu-item.ts
│ │ │ ├── menu-list.ts
│ │ │ ├── menu-spec.ts
│ │ │ ├── menu-vo.ts
│ │ │ ├── menu.ts
│ │ │ ├── metadata.ts
│ │ │ ├── move-operation.ts
│ │ │ ├── navigation-post-vo.ts
│ │ │ ├── notification-list.ts
│ │ │ ├── notification-spec.ts
│ │ │ ├── notification-template-list.ts
│ │ │ ├── notification-template-spec.ts
│ │ │ ├── notification-template.ts
│ │ │ ├── notification.ts
│ │ │ ├── notifier-descriptor-list.ts
│ │ │ ├── notifier-descriptor-spec.ts
│ │ │ ├── notifier-descriptor.ts
│ │ │ ├── notifier-info.ts
│ │ │ ├── notifier-setting-ref.ts
│ │ │ ├── owner-info.ts
│ │ │ ├── password-request.ts
│ │ │ ├── pat-spec.ts
│ │ │ ├── personal-access-token-list.ts
│ │ │ ├── personal-access-token.ts
│ │ │ ├── plugin-author.ts
│ │ │ ├── plugin-list.ts
│ │ │ ├── plugin-running-state-request.ts
│ │ │ ├── plugin-spec.ts
│ │ │ ├── plugin-status.ts
│ │ │ ├── plugin.ts
│ │ │ ├── policy-list.ts
│ │ │ ├── policy-rule.ts
│ │ │ ├── policy-spec.ts
│ │ │ ├── policy-template-list.ts
│ │ │ ├── policy-template-spec.ts
│ │ │ ├── policy-template.ts
│ │ │ ├── policy.ts
│ │ │ ├── post-list.ts
│ │ │ ├── post-request.ts
│ │ │ ├── post-spec.ts
│ │ │ ├── post-status.ts
│ │ │ ├── post-vo.ts
│ │ │ ├── post.ts
│ │ │ ├── reason-attributes.ts
│ │ │ ├── reason-list.ts
│ │ │ ├── reason-property.ts
│ │ │ ├── reason-selector.ts
│ │ │ ├── reason-spec.ts
│ │ │ ├── reason-subject.ts
│ │ │ ├── reason-type-info.ts
│ │ │ ├── reason-type-list.ts
│ │ │ ├── reason-type-notifier-collection-request.ts
│ │ │ ├── reason-type-notifier-matrix.ts
│ │ │ ├── reason-type-notifier-request.ts
│ │ │ ├── reason-type-spec.ts
│ │ │ ├── reason-type.ts
│ │ │ ├── reason.ts
│ │ │ ├── ref.ts
│ │ │ ├── remember-me-token-list.ts
│ │ │ ├── remember-me-token-spec.ts
│ │ │ ├── remember-me-token.ts
│ │ │ ├── remove-operation.ts
│ │ │ ├── replace-operation.ts
│ │ │ ├── reply-list.ts
│ │ │ ├── reply-request.ts
│ │ │ ├── reply-spec.ts
│ │ │ ├── reply-status.ts
│ │ │ ├── reply-vo-list.ts
│ │ │ ├── reply-vo.ts
│ │ │ ├── reply.ts
│ │ │ ├── reverse-proxy-list.ts
│ │ │ ├── reverse-proxy-rule.ts
│ │ │ ├── reverse-proxy.ts
│ │ │ ├── revert-snapshot-for-post-param.ts
│ │ │ ├── revert-snapshot-for-single-param.ts
│ │ │ ├── role-binding-list.ts
│ │ │ ├── role-binding.ts
│ │ │ ├── role-list.ts
│ │ │ ├── role-ref.ts
│ │ │ ├── role.ts
│ │ │ ├── search-option.ts
│ │ │ ├── search-result.ts
│ │ │ ├── secret-list.ts
│ │ │ ├── secret.ts
│ │ │ ├── setting-form.ts
│ │ │ ├── setting-list.ts
│ │ │ ├── setting-ref.ts
│ │ │ ├── setting-spec.ts
│ │ │ ├── setting.ts
│ │ │ ├── setup-request.ts
│ │ │ ├── single-page-list.ts
│ │ │ ├── single-page-request.ts
│ │ │ ├── single-page-spec.ts
│ │ │ ├── single-page-status.ts
│ │ │ ├── single-page-vo.ts
│ │ │ ├── single-page.ts
│ │ │ ├── site-stats-vo.ts
│ │ │ ├── snap-shot-spec.ts
│ │ │ ├── snapshot-list.ts
│ │ │ ├── snapshot.ts
│ │ │ ├── stats-vo.ts
│ │ │ ├── stats.ts
│ │ │ ├── subject.ts
│ │ │ ├── subscription-list.ts
│ │ │ ├── subscription-spec.ts
│ │ │ ├── subscription-subscriber.ts
│ │ │ ├── subscription.ts
│ │ │ ├── tag-list.ts
│ │ │ ├── tag-spec.ts
│ │ │ ├── tag-status.ts
│ │ │ ├── tag-vo-list.ts
│ │ │ ├── tag-vo.ts
│ │ │ ├── tag.ts
│ │ │ ├── template-content.ts
│ │ │ ├── template-descriptor.ts
│ │ │ ├── test-operation.ts
│ │ │ ├── theme-list.ts
│ │ │ ├── theme-spec.ts
│ │ │ ├── theme-status.ts
│ │ │ ├── theme.ts
│ │ │ ├── thumbnail-list.ts
│ │ │ ├── thumbnail-spec.ts
│ │ │ ├── thumbnail.ts
│ │ │ ├── totp-auth-link-response.ts
│ │ │ ├── totp-request.ts
│ │ │ ├── two-factor-auth-settings.ts
│ │ │ ├── uc-upload-from-url-request.ts
│ │ │ ├── upgrade-from-uri-request.ts
│ │ │ ├── upload-from-url-request.ts
│ │ │ ├── user-connection-list.ts
│ │ │ ├── user-connection-spec.ts
│ │ │ ├── user-connection.ts
│ │ │ ├── user-device.ts
│ │ │ ├── user-endpoint-listed-user-list.ts
│ │ │ ├── user-list.ts
│ │ │ ├── user-permission.ts
│ │ │ ├── user-spec.ts
│ │ │ ├── user-status.ts
│ │ │ ├── user.ts
│ │ │ ├── verify-code-request.ts
│ │ │ └── vote-request.ts
│ │ ├── tsconfig.json
│ │ └── tsdown.config.ts
│ ├── components/
│ │ ├── .storybook/
│ │ │ ├── main.ts
│ │ │ └── preview.ts
│ │ ├── env.d.ts
│ │ ├── package.json
│ │ ├── postcss.config.cjs
│ │ ├── src/
│ │ │ ├── components/
│ │ │ │ ├── alert/
│ │ │ │ │ ├── Alert.stories.ts
│ │ │ │ │ ├── Alert.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── Alert.spec.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── avatar/
│ │ │ │ │ ├── Avatar.stories.ts
│ │ │ │ │ ├── Avatar.vue
│ │ │ │ │ ├── AvatarGroup.stories.ts
│ │ │ │ │ ├── AvatarGroup.vue
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── button/
│ │ │ │ │ ├── Button.stories.ts
│ │ │ │ │ ├── Button.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── Button.spec.ts
│ │ │ │ │ │ └── __snapshots__/
│ │ │ │ │ │ └── Button.spec.ts.snap
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── card/
│ │ │ │ │ ├── Card.stories.ts
│ │ │ │ │ ├── Card.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── Card.spec.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── description/
│ │ │ │ │ ├── Description.vue
│ │ │ │ │ ├── DescriptionItem.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── dialog/
│ │ │ │ │ ├── Dialog.stories.ts
│ │ │ │ │ ├── Dialog.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── Dialog.spec.ts
│ │ │ │ │ ├── dialog-manager.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── dropdown/
│ │ │ │ │ ├── Draopdown.stories.ts
│ │ │ │ │ ├── DropdownDivider.vue
│ │ │ │ │ ├── DropdownItem.vue
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── style.scss
│ │ │ │ ├── empty/
│ │ │ │ │ ├── Empty.stories.ts
│ │ │ │ │ ├── Empty.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── Empty.spec.ts
│ │ │ │ │ │ └── __snapshots__/
│ │ │ │ │ │ └── Empty.spec.ts.snap
│ │ │ │ │ └── index.ts
│ │ │ │ ├── entity/
│ │ │ │ │ ├── Entity.vue
│ │ │ │ │ ├── EntityContainer.vue
│ │ │ │ │ ├── EntityField.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── Entity.spec.ts
│ │ │ │ │ │ └── EntityField.spec.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── header/
│ │ │ │ │ ├── PageHeader.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── loading/
│ │ │ │ │ ├── Loading.stories.ts
│ │ │ │ │ ├── Loading.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── menu/
│ │ │ │ │ ├── Menu.stories.ts
│ │ │ │ │ ├── Menu.vue
│ │ │ │ │ ├── MenuItem.vue
│ │ │ │ │ ├── MenuLabel.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── Menu.spec.tsx
│ │ │ │ │ │ ├── MenuLabel.spec.ts
│ │ │ │ │ │ └── __snapshots__/
│ │ │ │ │ │ ├── Menu.spec.tsx.snap
│ │ │ │ │ │ └── MenuLabel.spec.ts.snap
│ │ │ │ │ └── index.ts
│ │ │ │ ├── modal/
│ │ │ │ │ ├── Modal.stories.ts
│ │ │ │ │ ├── Modal.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── Modal.spec.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── pagination/
│ │ │ │ │ ├── Pagination.stories.ts
│ │ │ │ │ ├── Pagination.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── Pagination.spec.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── space/
│ │ │ │ │ ├── Space.stories.ts
│ │ │ │ │ ├── Space.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── Space.spec.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── status/
│ │ │ │ │ ├── StatusDot.stories.ts
│ │ │ │ │ ├── StatusDot.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── StatusDot.spec.ts
│ │ │ │ │ │ └── __snapshots__/
│ │ │ │ │ │ └── StatusDot.spec.ts.snap
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── switch/
│ │ │ │ │ ├── Switch.stories.ts
│ │ │ │ │ ├── Switch.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── Switch.spec.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── tabs/
│ │ │ │ │ ├── TabItem.vue
│ │ │ │ │ ├── Tabbar.stories.ts
│ │ │ │ │ ├── Tabbar.vue
│ │ │ │ │ ├── Tabs.stories.ts
│ │ │ │ │ ├── Tabs.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── TabItem.spec.ts
│ │ │ │ │ │ ├── Tabbar.spec.ts
│ │ │ │ │ │ └── Tabs.spec.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── tag/
│ │ │ │ │ ├── Tag.stories.ts
│ │ │ │ │ ├── Tag.story.vue
│ │ │ │ │ ├── Tag.vue
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── Tag.spec.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── toast/
│ │ │ │ │ ├── Toast.story.vue
│ │ │ │ │ ├── Toast.vue
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── toast-manager.ts
│ │ │ │ │ └── types.ts
│ │ │ │ └── tooltip/
│ │ │ │ ├── index.ts
│ │ │ │ └── style.css
│ │ │ ├── components.ts
│ │ │ ├── icons/
│ │ │ │ └── icons.ts
│ │ │ ├── index.ts
│ │ │ ├── stories/
│ │ │ │ └── Introduction.mdx
│ │ │ └── styles/
│ │ │ └── tailwind.css
│ │ ├── tailwind.config.ts
│ │ ├── tsconfig.app.json
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ ├── tsconfig.vitest.json
│ │ └── vite.config.ts
│ ├── console-shared/
│ │ ├── README.md
│ │ ├── index.js
│ │ └── package.json
│ ├── editor/
│ │ ├── README.md
│ │ ├── docs/
│ │ │ └── extension.md
│ │ ├── env.d.ts
│ │ ├── package.json
│ │ ├── postcss.config.cjs
│ │ ├── src/
│ │ │ ├── components/
│ │ │ │ ├── Editor.vue
│ │ │ │ ├── EditorHeader.vue
│ │ │ │ ├── base/
│ │ │ │ │ ├── DropdownItem.vue
│ │ │ │ │ ├── Input.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── block/
│ │ │ │ │ ├── BlockActionButton.vue
│ │ │ │ │ ├── BlockActionHorizontalSeparator.vue
│ │ │ │ │ ├── BlockActionSeparator.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── bubble/
│ │ │ │ │ ├── BubbleButton.vue
│ │ │ │ │ ├── BubbleItem.vue
│ │ │ │ │ ├── EditorBubbleMenu.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── common/
│ │ │ │ │ └── ColorPickerDropdown.vue
│ │ │ │ ├── drag/
│ │ │ │ │ ├── EditorDragButtonItem.vue
│ │ │ │ │ ├── EditorDragHandle.vue
│ │ │ │ │ ├── EditorDragMenu.vue
│ │ │ │ │ ├── default-drag.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── icon/
│ │ │ │ │ └── MingcuteDelete2Line.vue
│ │ │ │ ├── index.ts
│ │ │ │ ├── toolbar/
│ │ │ │ │ ├── ToolbarItem.vue
│ │ │ │ │ ├── ToolbarSubItem.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── toolbox/
│ │ │ │ │ ├── ToolboxItem.vue
│ │ │ │ │ └── index.ts
│ │ │ │ └── upload/
│ │ │ │ ├── EditorLinkObtain.vue
│ │ │ │ ├── ResourceReplaceButton.vue
│ │ │ │ └── index.ts
│ │ │ ├── composables/
│ │ │ │ └── use-attachment.ts
│ │ │ ├── extensions/
│ │ │ │ ├── align/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── audio/
│ │ │ │ │ ├── AudioView.vue
│ │ │ │ │ ├── BubbleItemAudioLink.vue
│ │ │ │ │ ├── BubbleItemAudioPosition.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── block-position/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── blockquote/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── bold/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── bullet-list/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── character-count/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── clear-format/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── code/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── code-block/
│ │ │ │ │ ├── CodeBlockSelect.vue
│ │ │ │ │ ├── CodeBlockViewRenderer.vue
│ │ │ │ │ ├── code-block.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── color/
│ │ │ │ │ ├── ColorBubbleItem.vue
│ │ │ │ │ ├── ColorToolbarItem.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── columns/
│ │ │ │ │ ├── column.ts
│ │ │ │ │ ├── columns.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── commands-menu/
│ │ │ │ │ ├── CommandsView.vue
│ │ │ │ │ ├── commands.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── details/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── document/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── drop-cursor/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── extensions-kit.ts
│ │ │ │ ├── figure/
│ │ │ │ │ ├── FigureCaptionView.vue
│ │ │ │ │ ├── figure-caption.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── font-size/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── format-brush/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── util.ts
│ │ │ │ ├── gallery/
│ │ │ │ │ ├── BubbleItemAddImage.vue
│ │ │ │ │ ├── BubbleItemGap.vue
│ │ │ │ │ ├── BubbleItemGroupSize.vue
│ │ │ │ │ ├── BubbleItemLayout.vue
│ │ │ │ │ ├── GalleryView.vue
│ │ │ │ │ ├── gallery-bubble.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── useGalleryImages.ts
│ │ │ │ ├── gap-cursor/
│ │ │ │ │ ├── gap-cursor-selection.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── hard-break/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── heading/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── highlight/
│ │ │ │ │ ├── HighlightBubbleItem.vue
│ │ │ │ │ ├── HighlightToolbarItem.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── history/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── horizontal-rule/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── iframe/
│ │ │ │ │ ├── BubbleItemIframeAlign.vue
│ │ │ │ │ ├── BubbleItemIframeLink.vue
│ │ │ │ │ ├── BubbleItemIframeSize.vue
│ │ │ │ │ ├── IframeView.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── image/
│ │ │ │ │ ├── BubbleItemImageAlt.vue
│ │ │ │ │ ├── BubbleItemImageHref.vue
│ │ │ │ │ ├── BubbleItemImageLink.vue
│ │ │ │ │ ├── BubbleItemImagePosition.vue
│ │ │ │ │ ├── BubbleItemImageSize.vue
│ │ │ │ │ ├── ImageView.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── indent/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── italic/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── link/
│ │ │ │ │ ├── LinkBubbleButton.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── list-extra/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── list-keymap/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── node-selected/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── ordered-list/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── paragraph/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── placeholder/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── range-selection/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── range-selection.ts
│ │ │ │ ├── search-and-replace/
│ │ │ │ │ ├── IconButton.vue
│ │ │ │ │ ├── MatchToggleButton.vue
│ │ │ │ │ ├── SearchAndReplace.vue
│ │ │ │ │ ├── SearchAndReplacePlugin.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── smart-scroll/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── strike/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── subscript/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── superscript/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── table/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── table-cell.ts
│ │ │ │ │ ├── table-header.ts
│ │ │ │ │ ├── table-row.ts
│ │ │ │ │ └── util.ts
│ │ │ │ ├── task-list/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── text/
│ │ │ │ │ ├── BubbleItemTextType.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── text-align/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── text-style/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── trailing-node/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── underline/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── upload/
│ │ │ │ │ └── index.ts
│ │ │ │ └── video/
│ │ │ │ ├── BubbleItemVideoLink.vue
│ │ │ │ ├── BubbleItemVideoPosition.vue
│ │ │ │ ├── BubbleItemVideoSize.vue
│ │ │ │ ├── VideoView.vue
│ │ │ │ └── index.ts
│ │ │ ├── index.ts
│ │ │ ├── locales/
│ │ │ │ ├── en.json
│ │ │ │ ├── es.json
│ │ │ │ ├── index.ts
│ │ │ │ └── zh-CN.json
│ │ │ ├── styles/
│ │ │ │ ├── base.scss
│ │ │ │ ├── columns.scss
│ │ │ │ ├── details.scss
│ │ │ │ ├── draggable.scss
│ │ │ │ ├── figure.scss
│ │ │ │ ├── format-brush.scss
│ │ │ │ ├── gap-cursor.scss
│ │ │ │ ├── index.scss
│ │ │ │ ├── node-select.scss
│ │ │ │ ├── range-selection.scss
│ │ │ │ ├── resizer.scss
│ │ │ │ ├── search.scss
│ │ │ │ ├── table.scss
│ │ │ │ └── tailwind.css
│ │ │ ├── tiptap/
│ │ │ │ ├── core/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── pm/
│ │ │ │ │ └── index.ts
│ │ │ │ └── vue-3/
│ │ │ │ └── index.ts
│ │ │ ├── types/
│ │ │ │ └── index.ts
│ │ │ └── utils/
│ │ │ ├── anchor.ts
│ │ │ ├── attachment.ts
│ │ │ ├── clipboard.ts
│ │ │ ├── delete-node.ts
│ │ │ ├── filter-duplicate-extensions.ts
│ │ │ ├── index.ts
│ │ │ ├── is-allowed-uri.ts
│ │ │ ├── is-list-active.ts
│ │ │ ├── is-node-empty.ts
│ │ │ ├── keyboard.ts
│ │ │ └── upload.ts
│ │ ├── tailwind.config.ts
│ │ ├── tsconfig.app.json
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ ├── tsconfig.vitest.json
│ │ └── vite.config.ts
│ ├── shared/
│ │ ├── env.d.ts
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── events/
│ │ │ │ └── index.ts
│ │ │ ├── index.ts
│ │ │ ├── plugin/
│ │ │ │ ├── index.ts
│ │ │ │ └── types/
│ │ │ │ ├── attachment-selector.ts
│ │ │ │ ├── backup.ts
│ │ │ │ ├── comment.ts
│ │ │ │ ├── dashboard-widget.ts
│ │ │ │ ├── editor-provider.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── list-entity-field.ts
│ │ │ │ ├── list-operation.ts
│ │ │ │ ├── plugin-installation-tab.ts
│ │ │ │ ├── plugin-tab.ts
│ │ │ │ ├── theme-list-tab.ts
│ │ │ │ ├── ui-plugin-entry.ts
│ │ │ │ ├── ui-plugin-module.ts
│ │ │ │ └── user-tab.ts
│ │ │ ├── stores/
│ │ │ │ ├── index.ts
│ │ │ │ └── types/
│ │ │ │ ├── actuator.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── slug.ts
│ │ │ ├── types/
│ │ │ │ ├── index.ts
│ │ │ │ └── menus.ts
│ │ │ └── utils/
│ │ │ ├── attachment.ts
│ │ │ ├── date.ts
│ │ │ ├── id.ts
│ │ │ ├── index.ts
│ │ │ └── permission.ts
│ │ ├── tsconfig.app.json
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ └── tsdown.config.ts
│ └── ui-plugin-bundler-kit/
│ ├── README.md
│ ├── package.json
│ ├── src/
│ │ ├── constants/
│ │ │ ├── build.ts
│ │ │ ├── externals.ts
│ │ │ └── halo-plugin.ts
│ │ ├── index.ts
│ │ ├── legacy.ts
│ │ ├── rsbuild.ts
│ │ ├── utils/
│ │ │ └── halo-plugin.ts
│ │ └── vite.ts
│ ├── tsconfig.json
│ └── tsdown.config.ts
├── patches/
│ └── @tiptap__extension-drag-handle@3.17.1.patch
├── pnpm-workspace.yaml
├── postcss.config.cjs
├── scripts/
│ ├── apply_missing_translations.mjs
│ ├── find_missing_translations.mjs
│ └── fix_translations.mjs
├── src/
│ ├── components/
│ │ ├── alerts/
│ │ │ └── H2WarningAlert.vue
│ │ ├── attachment/
│ │ │ ├── AttachmentGridListItem.vue
│ │ │ ├── AttachmentImagePreview.vue
│ │ │ └── AttachmentPermalinkList.vue
│ │ ├── back-to-top/
│ │ │ └── BackToTop.vue
│ │ ├── base-app/
│ │ │ └── BaseApp.vue
│ │ ├── button/
│ │ │ └── SubmitButton.vue
│ │ ├── codemirror/
│ │ │ ├── Codemirror.vue
│ │ │ └── supports.ts
│ │ ├── common/
│ │ │ └── AppDownloadAlert.vue
│ │ ├── dropdown-selector/
│ │ │ └── EditorProviderSelector.vue
│ │ ├── editor/
│ │ │ └── DefaultEditor.vue
│ │ ├── entity/
│ │ │ └── EntityDropdownItems.vue
│ │ ├── entity-fields/
│ │ │ ├── EntityFieldItems.vue
│ │ │ └── StatusDotField.vue
│ │ ├── filter/
│ │ │ ├── CategoryFilterDropdown.vue
│ │ │ ├── FilterCleanButton.vue
│ │ │ ├── FilterDropdown.vue
│ │ │ ├── FilterTag.vue
│ │ │ ├── TagFilterDropdown.vue
│ │ │ └── UserFilterDropdown.vue
│ │ ├── form/
│ │ │ └── AnnotationsForm.vue
│ │ ├── global-search/
│ │ │ └── GlobalSearchModal.vue
│ │ ├── icon/
│ │ │ └── AttachmentFileTypeIcon.vue
│ │ ├── input/
│ │ │ └── SearchInput.vue
│ │ ├── menu/
│ │ │ ├── MenuLoading.vue
│ │ │ └── RoutesMenu.tsx
│ │ ├── permission/
│ │ │ └── HasPermission.vue
│ │ ├── preview/
│ │ │ └── UrlPreviewModal.vue
│ │ ├── sticky-block/
│ │ │ └── StickyBlock.vue
│ │ ├── upload/
│ │ │ └── UppyUpload.vue
│ │ ├── user/
│ │ │ └── PostContributorList.vue
│ │ ├── user-avatar/
│ │ │ ├── UserAvatar.vue
│ │ │ └── UserAvatarCropper.vue
│ │ └── video/
│ │ └── LazyVideo.vue
│ ├── composables/
│ │ ├── use-auto-save-content.ts
│ │ ├── use-content-cache.ts
│ │ ├── use-editor-extension-points.ts
│ │ ├── use-role.ts
│ │ ├── use-route-menu-generator.ts
│ │ ├── use-session-keep-alive.ts
│ │ └── use-title.ts
│ ├── constants/
│ │ ├── annotations.ts
│ │ ├── app.ts
│ │ ├── constants.ts
│ │ ├── error-types.ts
│ │ ├── finalizers.ts
│ │ ├── labels.ts
│ │ └── regex.ts
│ ├── formkit/
│ │ ├── formkit.config.ts
│ │ ├── inputs/
│ │ │ ├── array/
│ │ │ │ ├── ArrayFormModal.vue
│ │ │ │ ├── ArrayInput.vue
│ │ │ │ ├── index.ts
│ │ │ │ ├── labels/
│ │ │ │ │ ├── ColorLabel.vue
│ │ │ │ │ └── IconifyLabel.vue
│ │ │ │ ├── renderers/
│ │ │ │ │ ├── attachment.ts
│ │ │ │ │ ├── category-select.ts
│ │ │ │ │ ├── checkbox.ts
│ │ │ │ │ ├── helpers/
│ │ │ │ │ │ └── findOption.ts
│ │ │ │ │ ├── iconify.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── native-select.ts
│ │ │ │ │ ├── radio.ts
│ │ │ │ │ ├── select.ts
│ │ │ │ │ ├── tag-select.ts
│ │ │ │ │ ├── toggle.ts
│ │ │ │ │ └── types.ts
│ │ │ │ └── sections/
│ │ │ │ └── index.ts
│ │ │ ├── attachment/
│ │ │ │ ├── AttachmentDropdownItem.vue
│ │ │ │ ├── AttachmentInput.vue
│ │ │ │ ├── AttachmentPreview.vue
│ │ │ │ ├── CustomLinkDropdownItem.vue
│ │ │ │ ├── UploadDropdownItem.vue
│ │ │ │ ├── feature.ts
│ │ │ │ └── index.ts
│ │ │ ├── attachment-group-select.ts
│ │ │ ├── attachment-input/
│ │ │ │ ├── AttachmentInput.vue
│ │ │ │ └── index.ts
│ │ │ ├── attachment-policy-select.ts
│ │ │ ├── category-checkbox.ts
│ │ │ ├── category-select/
│ │ │ │ ├── CategorySelect.vue
│ │ │ │ ├── components/
│ │ │ │ │ ├── CategoryListItem.vue
│ │ │ │ │ ├── CategoryTag.vue
│ │ │ │ │ └── SearchResultListItem.vue
│ │ │ │ ├── index.ts
│ │ │ │ └── sections/
│ │ │ │ └── index.ts
│ │ │ ├── code/
│ │ │ │ ├── CodeInput.vue
│ │ │ │ └── index.ts
│ │ │ ├── color/
│ │ │ │ ├── ColorInput.vue
│ │ │ │ ├── index.ts
│ │ │ │ └── types.ts
│ │ │ ├── form.ts
│ │ │ ├── group.ts
│ │ │ ├── iconify/
│ │ │ │ ├── Collections.vue
│ │ │ │ ├── CollectionsView.vue
│ │ │ │ ├── Icon.vue
│ │ │ │ ├── IconConfirmPanel.vue
│ │ │ │ ├── IconifyInput.vue
│ │ │ │ ├── IconifyPicker.vue
│ │ │ │ ├── Icons.vue
│ │ │ │ ├── SearchView.vue
│ │ │ │ ├── api.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── types.ts
│ │ │ ├── list/
│ │ │ │ ├── AddButton.vue
│ │ │ │ ├── features/
│ │ │ │ │ └── lists.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── listSection.ts
│ │ │ │ └── sections/
│ │ │ │ └── index.ts
│ │ │ ├── menu-checkbox.ts
│ │ │ ├── menu-item-select.ts
│ │ │ ├── menu-radio.ts
│ │ │ ├── menu-select.ts
│ │ │ ├── password/
│ │ │ │ ├── RevealButton.vue
│ │ │ │ └── index.ts
│ │ │ ├── post-select.ts
│ │ │ ├── repeater/
│ │ │ │ ├── AddButton.vue
│ │ │ │ ├── features/
│ │ │ │ │ └── repeats.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── repeaterSection.ts
│ │ │ │ └── sections/
│ │ │ │ └── index.ts
│ │ │ ├── role-select.ts
│ │ │ ├── secret/
│ │ │ │ ├── SecretSelect.vue
│ │ │ │ ├── components/
│ │ │ │ │ ├── SecretCreationModal.vue
│ │ │ │ │ ├── SecretEditModal.vue
│ │ │ │ │ ├── SecretForm.vue
│ │ │ │ │ ├── SecretListItem.vue
│ │ │ │ │ └── SecretListModal.vue
│ │ │ │ ├── composables/
│ │ │ │ │ └── use-secrets-fetch.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── sections/
│ │ │ │ │ └── index.ts
│ │ │ │ └── types/
│ │ │ │ └── index.ts
│ │ │ ├── select/
│ │ │ │ ├── MultipleOverflow.vue
│ │ │ │ ├── MultipleOverflowItem.vue
│ │ │ │ ├── MultipleSelect.vue
│ │ │ │ ├── MultipleSelectItem.vue
│ │ │ │ ├── MultipleSelectSearchInput.vue
│ │ │ │ ├── MultipleSelectSelector.vue
│ │ │ │ ├── SelectContainer.vue
│ │ │ │ ├── SelectDropdownContainer.vue
│ │ │ │ ├── SelectMain.vue
│ │ │ │ ├── SelectOption.vue
│ │ │ │ ├── SelectOptionItem.vue
│ │ │ │ ├── SelectSearchInput.vue
│ │ │ │ ├── SelectSelector.vue
│ │ │ │ ├── index.ts
│ │ │ │ ├── isFalse.ts
│ │ │ │ └── sections/
│ │ │ │ └── index.ts
│ │ │ ├── singlePage-select.ts
│ │ │ ├── switch/
│ │ │ │ ├── SwitchInput.vue
│ │ │ │ ├── feature.ts
│ │ │ │ └── index.ts
│ │ │ ├── tag-checkbox.ts
│ │ │ ├── tag-select/
│ │ │ │ ├── TagSelect.vue
│ │ │ │ ├── index.ts
│ │ │ │ └── sections/
│ │ │ │ └── index.ts
│ │ │ ├── toggle/
│ │ │ │ ├── ToggleInput.vue
│ │ │ │ ├── feature.ts
│ │ │ │ └── index.ts
│ │ │ ├── user-select.ts
│ │ │ └── verify-form/
│ │ │ ├── VerificationButton.vue
│ │ │ ├── features/
│ │ │ │ └── index.ts
│ │ │ └── index.ts
│ │ ├── plugins/
│ │ │ ├── auto-scroll-to-errors.ts
│ │ │ ├── password-prevent-autocomplete.ts
│ │ │ ├── radio-alt.ts
│ │ │ ├── required-asterisk.ts
│ │ │ └── stop-implicit-submission.ts
│ │ ├── theme.ts
│ │ └── utils/
│ │ └── focus.ts
│ ├── layouts/
│ │ ├── MobileMenu.vue
│ │ └── UserProfileBanner.vue
│ ├── locales/
│ │ ├── en.json
│ │ ├── es.json
│ │ ├── index.ts
│ │ ├── zh-CN.json
│ │ └── zh-TW.json
│ ├── router/
│ │ └── process-bar.ts
│ ├── setup/
│ │ ├── setupApiClient.ts
│ │ ├── setupComponents.ts
│ │ ├── setupModules.ts
│ │ ├── setupStyles.ts
│ │ ├── setupUserPermissions.ts
│ │ └── setupVueQuery.ts
│ ├── stores/
│ │ ├── plugin.ts
│ │ └── role.ts
│ ├── styles/
│ │ ├── index.css
│ │ └── tailwind.css
│ ├── utils/
│ │ ├── __tests__/
│ │ │ └── media-type.spec.ts
│ │ ├── cookie.ts
│ │ ├── device.ts
│ │ ├── image.ts
│ │ ├── load-style.ts
│ │ ├── media-type.ts
│ │ ├── modal.ts
│ │ └── role.ts
│ ├── views/
│ │ └── exceptions/
│ │ ├── Forbidden.vue
│ │ ├── NotFound.vue
│ │ ├── __tests__/
│ │ │ └── NotFound.spec.ts
│ │ └── components/
│ │ └── Exception.vue
│ └── vite/
│ ├── library-external.ts
│ └── plugin-dev.ts
├── tailwind.config.ts
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.node.json
├── tsconfig.vitest.json
├── uc-src/
│ ├── App.vue
│ ├── layouts/
│ │ └── BasicLayout.vue
│ ├── main.ts
│ ├── modules/
│ │ ├── contents/
│ │ │ ├── attachments/
│ │ │ │ ├── components/
│ │ │ │ │ ├── AttachmentDetailModal.vue
│ │ │ │ │ ├── AttachmentSelectorModal.vue
│ │ │ │ │ └── selector-providers/
│ │ │ │ │ ├── AttachmentUploadModal.vue
│ │ │ │ │ ├── CoreSelectorProvider.vue
│ │ │ │ │ └── components/
│ │ │ │ │ └── AttachmentSelectorListItem.vue
│ │ │ │ └── module.ts
│ │ │ └── posts/
│ │ │ ├── PostEditor.vue
│ │ │ ├── PostList.vue
│ │ │ ├── components/
│ │ │ │ ├── PostCreationModal.vue
│ │ │ │ ├── PostListItem.vue
│ │ │ │ ├── PostSettingEditModal.vue
│ │ │ │ └── PostSettingForm.vue
│ │ │ ├── composables/
│ │ │ │ ├── use-post-publish-mutate.ts
│ │ │ │ └── use-post-update-mutate.ts
│ │ │ ├── module.ts
│ │ │ └── types/
│ │ │ └── index.ts
│ │ ├── index.ts
│ │ ├── notifications/
│ │ │ ├── Notifications.vue
│ │ │ ├── components/
│ │ │ │ ├── NotificationContent.vue
│ │ │ │ └── NotificationListItem.vue
│ │ │ └── module.ts
│ │ └── profile/
│ │ ├── Profile.vue
│ │ ├── components/
│ │ │ ├── EmailVerifyModal.vue
│ │ │ ├── PasswordChangeModal.vue
│ │ │ ├── PersonalAccessTokenCreationModal.vue
│ │ │ ├── PersonalAccessTokenListItem.vue
│ │ │ └── ProfileEditingModal.vue
│ │ ├── module.ts
│ │ └── tabs/
│ │ ├── Authentication.vue
│ │ ├── Detail.vue
│ │ ├── Devices.vue
│ │ ├── NotificationPreferences.vue
│ │ ├── PersonalAccessTokens.vue
│ │ ├── components/
│ │ │ ├── AuthProviders.vue
│ │ │ ├── DeviceDetailModal.vue
│ │ │ ├── DeviceListItem.vue
│ │ │ ├── PasswordValidationForm.vue
│ │ │ ├── TotpConfigureModal.vue
│ │ │ ├── TotpDeletionModal.vue
│ │ │ ├── TwoFactor.vue
│ │ │ ├── TwoFactorDisableModal.vue
│ │ │ └── TwoFactorEnableModal.vue
│ │ └── composables/
│ │ ├── use-user-agent.ts
│ │ └── use-user-device.ts
│ └── router/
│ ├── constant.ts
│ ├── guards/
│ │ ├── auth-check.ts
│ │ └── permission.ts
│ ├── index.ts
│ └── routes.config.ts
├── uc.html
└── vite.config.ts
Showing preview only (934K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (10096 symbols across 1795 files)
FILE: api/src/main/java/run/halo/app/content/ContentWrapper.java
class ContentWrapper (line 13) | @Data
method patchSnapshot (line 21) | public static ContentWrapper patchSnapshot(Snapshot patchSnapshot, Sna...
FILE: api/src/main/java/run/halo/app/content/ExcerptGenerator.java
type ExcerptGenerator (line 9) | public interface ExcerptGenerator extends ExtensionPoint {
method generate (line 11) | Mono<String> generate(ExcerptGenerator.Context context);
class Context (line 13) | @Data
FILE: api/src/main/java/run/halo/app/content/PatchUtils.java
class PatchUtils (line 24) | public class PatchUtils {
method create (line 28) | public static Patch<String> create(String deltasJson) {
method patchToJson (line 49) | public static String patchToJson(Patch<String> patch) {
method applyPatch (line 54) | public static String applyPatch(String original, String patchJson) {
method diffToJsonPatch (line 63) | public static String diffToJsonPatch(String original, String revised) {
method breakLine (line 68) | public static List<String> breakLine(String content) {
class Delta (line 75) | @Data
class StringChunk (line 82) | @Data
FILE: api/src/main/java/run/halo/app/content/PostContentService.java
type PostContentService (line 6) | public interface PostContentService {
method getHeadContent (line 8) | Mono<ContentWrapper> getHeadContent(String postName);
method getReleaseContent (line 10) | Mono<ContentWrapper> getReleaseContent(String postName);
method getSpecifiedContent (line 12) | Mono<ContentWrapper> getSpecifiedContent(String postName, String snaps...
method listSnapshots (line 14) | Flux<String> listSnapshots(String postName);
FILE: api/src/main/java/run/halo/app/content/comment/CommentSubject.java
type CommentSubject (line 14) | public interface CommentSubject<T extends Extension> extends ExtensionPo...
method get (line 16) | Mono<T> get(String name);
method getSubjectDisplay (line 18) | default Mono<SubjectDisplay> getSubjectDisplay(String name) {
method supports (line 22) | boolean supports(Ref ref);
FILE: api/src/main/java/run/halo/app/core/attachment/ThumbnailProvider.java
type ThumbnailProvider (line 18) | @Deprecated(forRemoval = true, since = "2.22.0")
method generate (line 27) | Mono<URI> generate(ThumbnailContext context);
method delete (line 34) | Mono<Void> delete(URL imageUrl);
method supports (line 41) | Mono<Boolean> supports(ThumbnailContext context);
class ThumbnailContext (line 43) | @Data
FILE: api/src/main/java/run/halo/app/core/attachment/ThumbnailSize.java
type ThumbnailSize (line 7) | @Getter
method ThumbnailSize (line 16) | ThumbnailSize(int width) {
method fromWidth (line 25) | public static ThumbnailSize fromWidth(String width) {
method fromName (line 37) | public static ThumbnailSize fromName(String name) {
method optionalValueOf (line 46) | public static Optional<ThumbnailSize> optionalValueOf(String name) {
method allowedWidths (line 55) | public static Integer[] allowedWidths() {
FILE: api/src/main/java/run/halo/app/core/endpoint/WebSocketEndpoint.java
type WebSocketEndpoint (line 11) | public interface WebSocketEndpoint {
method urlPath (line 18) | String urlPath();
method groupVersion (line 25) | GroupVersion groupVersion();
method handler (line 32) | WebSocketHandler handler();
FILE: api/src/main/java/run/halo/app/core/extension/AnnotationSetting.java
class AnnotationSetting (line 15) | @Data
class AnnotationSettingSpec (line 28) | @Data
FILE: api/src/main/java/run/halo/app/core/extension/AuthProvider.java
class AuthProvider (line 21) | @Data
class AuthProviderSpec (line 35) | @Data
method setAuthType (line 74) | public void setAuthType(AuthType authType) {
class SettingRef (line 79) | @Data
class ConfigMapRef (line 89) | @Data
type AuthType (line 96) | public enum AuthType {
FILE: api/src/main/java/run/halo/app/core/extension/Counter.java
class Counter (line 15) | @Data
method emptyCounter (line 31) | public static Counter emptyCounter(String name) {
FILE: api/src/main/java/run/halo/app/core/extension/Device.java
class Device (line 15) | @Data
method setStatus (line 30) | public void setStatus(Status status) {
class Spec (line 34) | @Data
class Status (line 58) | @Data
FILE: api/src/main/java/run/halo/app/core/extension/Menu.java
class Menu (line 14) | @Data
class Spec (line 23) | @Data
FILE: api/src/main/java/run/halo/app/core/extension/MenuItem.java
class MenuItem (line 17) | @Data
type Target (line 30) | public enum Target {
method Target (line 38) | @JsonCreator
method getValue (line 43) | @JsonValue
class MenuItemSpec (line 49) | @Data
class MenuItemStatus (line 75) | @Data
FILE: api/src/main/java/run/halo/app/core/extension/Plugin.java
class Plugin (line 28) | @Data
method statusNonNull (line 49) | @NonNull
class PluginSpec (line 58) | @Data
class License (line 107) | @Data
class PluginStatus (line 113) | @Data
method nullSafeConditions (line 133) | public static ConditionList nullSafeConditions(@NonNull PluginStatus...
type Phase (line 142) | public enum Phase {
class PluginAuthor (line 156) | @Data
FILE: api/src/main/java/run/halo/app/core/extension/RememberMeToken.java
class RememberMeToken (line 13) | @Data
class Spec (line 22) | @Data
FILE: api/src/main/java/run/halo/app/core/extension/ReverseProxy.java
class ReverseProxy (line 17) | @Data
FILE: api/src/main/java/run/halo/app/core/extension/Role.java
class Role (line 23) | @Data
class PolicyRule (line 60) | @Getter
method PolicyRule (line 101) | public PolicyRule() {
method PolicyRule (line 105) | public PolicyRule(String[] apiGroups, String[] resources,
method nullElseEmpty (line 115) | String[] nullElseEmpty(String... items) {
method compareTo (line 122) | @Override
class Builder (line 144) | public static class Builder {
method apiGroups (line 155) | public Builder apiGroups(String... apiGroups) {
method resources (line 160) | public Builder resources(String... resources) {
method resourceNames (line 165) | public Builder resourceNames(String... resourceNames) {
method nonResourceURLs (line 170) | public Builder nonResourceURLs(String... nonResourceURLs) {
method verbs (line 175) | public Builder verbs(String... verbs) {
method build (line 180) | public PolicyRule build() {
FILE: api/src/main/java/run/halo/app/core/extension/RoleBinding.java
class RoleBinding (line 30) | @Data
class RoleRef (line 64) | @Data
class Subject (line 87) | @Data
method isUser (line 111) | public static Predicate<Subject> isUser(String username) {
method containsUser (line 117) | public static Predicate<Subject> containsUser(Set<String> usernames) {
method toString (line 123) | @Override
method create (line 132) | public static RoleBinding create(String username, String roleName) {
method containsUser (line 158) | public static Predicate<RoleBinding> containsUser(String username) {
method containsUser (line 164) | public static Predicate<RoleBinding> containsUser(Set<String> username...
FILE: api/src/main/java/run/halo/app/core/extension/Setting.java
class Setting (line 20) | @Data
class SettingSpec (line 33) | @Data
class SettingForm (line 40) | @Data
FILE: api/src/main/java/run/halo/app/core/extension/Theme.java
class Theme (line 24) | @Data
class ThemeSpec (line 40) | @Data
class ThemeStatus (line 77) | @Data
method nullSafeConditionList (line 90) | public static ConditionList nullSafeConditionList(Theme theme) {
type ThemePhase (line 100) | public enum ThemePhase {
class Author (line 106) | @Data
class CustomTemplates (line 116) | @Data
class TemplateDescriptor (line 129) | @Data
FILE: api/src/main/java/run/halo/app/core/extension/User.java
class User (line 21) | @Data
class UserSpec (line 55) | @Data
class UserStatus (line 86) | @Data
FILE: api/src/main/java/run/halo/app/core/extension/UserConnection.java
class UserConnection (line 19) | @Data
class UserConnectionSpec (line 28) | @Data
FILE: api/src/main/java/run/halo/app/core/extension/attachment/Attachment.java
class Attachment (line 17) | @Data
class AttachmentSpec (line 31) | @Data
class AttachmentStatus (line 60) | @Data
FILE: api/src/main/java/run/halo/app/core/extension/attachment/Constant.java
type Constant (line 5) | public enum Constant {
FILE: api/src/main/java/run/halo/app/core/extension/attachment/Group.java
class Group (line 14) | @Data
class GroupSpec (line 29) | @Data
class GroupStatus (line 37) | @Data
FILE: api/src/main/java/run/halo/app/core/extension/attachment/Policy.java
class Policy (line 13) | @Data
class PolicySpec (line 26) | @Data
FILE: api/src/main/java/run/halo/app/core/extension/attachment/PolicyTemplate.java
class PolicyTemplate (line 13) | @Data
class PolicyTemplateSpec (line 24) | @Data
FILE: api/src/main/java/run/halo/app/core/extension/attachment/endpoint/AttachmentHandler.java
type AttachmentHandler (line 16) | public interface AttachmentHandler extends ExtensionPoint {
method upload (line 18) | Mono<Attachment> upload(UploadContext context);
method delete (line 20) | Mono<Attachment> delete(DeleteContext context);
method getSharedURL (line 35) | default Mono<URI> getSharedURL(Attachment attachment,
method getPermalink (line 54) | default Mono<URI> getPermalink(Attachment attachment,
method getThumbnailLinks (line 68) | default Mono<Map<ThumbnailSize, URI>> getThumbnailLinks(Attachment att...
type UploadContext (line 74) | interface UploadContext {
method file (line 76) | FilePart file();
method policy (line 78) | Policy policy();
method configMap (line 80) | ConfigMap configMap();
method group (line 87) | @Nullable
type DeleteContext (line 94) | interface DeleteContext {
method attachment (line 95) | Attachment attachment();
method policy (line 97) | Policy policy();
method configMap (line 99) | ConfigMap configMap();
FILE: api/src/main/java/run/halo/app/core/extension/attachment/endpoint/SimpleFilePart.java
method transferTo (line 24) | @Override
method name (line 29) | @Override
method headers (line 34) | @Override
FILE: api/src/main/java/run/halo/app/core/extension/attachment/endpoint/UploadOption.java
method from (line 19) | public static UploadOption from(String filename,
FILE: api/src/main/java/run/halo/app/core/extension/content/Category.java
class Category (line 22) | @Data
method isDeleted (line 40) | @JsonIgnore
class CategorySpec (line 45) | @Data
method getStatusOrDefault (line 94) | @JsonIgnore
class CategoryStatus (line 102) | @Data
FILE: api/src/main/java/run/halo/app/core/extension/content/Comment.java
class Comment (line 25) | @Data
method getStatusOrDefault (line 42) | @JsonIgnore
class CommentSpec (line 50) | @Data
class BaseCommentSpec (line 61) | @Data
class CommentOwner (line 100) | @Data
method getAnnotation (line 117) | @Nullable
method ownerIdentity (line 123) | public static String ownerIdentity(String kind, String name) {
class CommentStatus (line 128) | @Data
method toSubjectRefKey (line 144) | public static String toSubjectRefKey(Ref subjectRef) {
method getUnreadReplyCount (line 148) | public static int getUnreadReplyCount(List<Reply> replies, Instant las...
FILE: api/src/main/java/run/halo/app/core/extension/content/Constant.java
type Constant (line 3) | public enum Constant {
FILE: api/src/main/java/run/halo/app/core/extension/content/Post.java
class Post (line 28) | @Data
method getStatusOrDefault (line 72) | @JsonIgnore
method isDeleted (line 80) | @JsonIgnore
method isPublished (line 86) | @JsonIgnore
method isPublished (line 91) | public static boolean isPublished(MetadataOperator metadata) {
method isRecycled (line 96) | public static boolean isRecycled(MetadataOperator metadata) {
method isPublic (line 101) | public static boolean isPublic(PostSpec spec) {
class PostSpec (line 105) | @Data
class PostStatus (line 158) | @Data
method getConditionsOrDefault (line 184) | @JsonIgnore
class Excerpt (line 193) | @Data
type PostPhase (line 202) | public enum PostPhase {
method from (line 214) | public static PostPhase from(String value) {
type VisibleEnum (line 224) | public enum VisibleEnum {
method from (line 235) | public static VisibleEnum from(String value) {
FILE: api/src/main/java/run/halo/app/core/extension/content/Reply.java
class Reply (line 19) | @Data
class ReplySpec (line 37) | @Data
class Status (line 47) | @Data
method setStatus (line 53) | public void setStatus(Status status) {
FILE: api/src/main/java/run/halo/app/core/extension/content/SinglePage.java
class SinglePage (line 24) | @Data
method getStatusOrDefault (line 47) | @JsonIgnore
method isPublished (line 55) | @JsonIgnore
class SinglePageSpec (line 61) | @Data
class SinglePageStatus (line 110) | @Data
method changePublishedState (line 116) | public static void changePublishedState(SinglePage page, boolean value) {
FILE: api/src/main/java/run/halo/app/core/extension/content/Snapshot.java
class Snapshot (line 23) | @Data
class SnapShotSpec (line 37) | @Data
method addContributor (line 63) | public static void addContributor(Snapshot snapshot, String name) {
method isBaseSnapshot (line 79) | public static boolean isBaseSnapshot(@NonNull Snapshot snapshot) {
method toSubjectRefKey (line 87) | public static String toSubjectRefKey(Ref subjectRef) {
FILE: api/src/main/java/run/halo/app/core/extension/content/Tag.java
class Tag (line 19) | @Data
class TagSpec (line 38) | @Data
method getStatusOrDefault (line 68) | @JsonIgnore
class TagStatus (line 76) | @Data
FILE: api/src/main/java/run/halo/app/core/extension/endpoint/CustomEndpoint.java
type CustomEndpoint (line 12) | public interface CustomEndpoint {
method endpoint (line 14) | RouterFunction<ServerResponse> endpoint();
method groupVersion (line 16) | default GroupVersion groupVersion() {
FILE: api/src/main/java/run/halo/app/core/extension/endpoint/SortResolver.java
type SortResolver (line 10) | public interface SortResolver {
method resolve (line 14) | @NonNull
class DefaultSortResolver (line 17) | class DefaultSortResolver extends ReactiveSortHandlerMethodArgumentRes...
method getDefaultFromAnnotationOrFallback (line 20) | @Override
method resolve (line 26) | @Override
FILE: api/src/main/java/run/halo/app/core/extension/notification/Notification.java
class Notification (line 28) | @Data
class NotificationSpec (line 37) | @Data
FILE: api/src/main/java/run/halo/app/core/extension/notification/NotificationTemplate.java
class NotificationTemplate (line 21) | @Data
class Spec (line 30) | @Data
class Template (line 40) | @Data
class ReasonSelector (line 51) | @Data
FILE: api/src/main/java/run/halo/app/core/extension/notification/NotifierDescriptor.java
class NotifierDescriptor (line 20) | @Data
class Spec (line 29) | @Data
class SettingRef (line 45) | @Data
FILE: api/src/main/java/run/halo/app/core/extension/notification/Reason.java
class Reason (line 25) | @Data
class Spec (line 34) | @Data
class Subject (line 52) | @Data
FILE: api/src/main/java/run/halo/app/core/extension/notification/ReasonType.java
class ReasonType (line 21) | @Data
class Spec (line 32) | @Data
class ReasonProperty (line 45) | @Data
FILE: api/src/main/java/run/halo/app/core/extension/notification/Subscription.java
class Subscription (line 26) | @Data
class Spec (line 35) | @Data
class InterestReason (line 52) | @Data
method ensureSubjectHasValue (line 75) | public static void ensureSubjectHasValue(InterestReason interestReas...
method isFallbackSubject (line 84) | public static boolean isFallbackSubject(ReasonSubject reasonSubject) {
method createFallbackSubject (line 93) | static ReasonSubject createFallbackSubject() {
class ReasonSubject (line 101) | @Data
method toString (line 118) | @Override
class Subscriber (line 124) | @Data
method toString (line 130) | @Override
method generateUnsubscribeToken (line 141) | public static String generateUnsubscribeToken() {
FILE: api/src/main/java/run/halo/app/core/extension/service/AttachmentService.java
type AttachmentService (line 24) | public interface AttachmentService {
method upload (line 38) | Mono<Attachment> upload(
method upload (line 59) | Mono<Attachment> upload(@NonNull String policyName,
method delete (line 73) | Mono<Attachment> delete(Attachment attachment);
method getPermalink (line 83) | Mono<URI> getPermalink(Attachment attachment);
method getSharedURL (line 95) | Mono<URI> getSharedURL(Attachment attachment, Duration ttl);
method getThumbnailLinks (line 104) | Mono<Map<ThumbnailSize, URI>> getThumbnailLinks(Attachment attachment);
method uploadFromUrl (line 115) | Mono<Attachment> uploadFromUrl(@NonNull URL url, @NonNull String polic...
FILE: api/src/main/java/run/halo/app/core/user/service/RoleService.java
type RoleService (line 16) | public interface RoleService {
method listRoleBindings (line 18) | Flux<RoleBinding> listRoleBindings(Subject subject);
method getRolesByUsername (line 20) | Flux<String> getRolesByUsername(String username);
method getRolesByUsernames (line 22) | Mono<Map<String, Collection<String>>> getRolesByUsernames(Collection<S...
method contains (line 24) | Mono<Boolean> contains(Collection<String> source, Collection<String> c...
method listPermissions (line 33) | Flux<Role> listPermissions(Set<String> names);
method listDependenciesFlux (line 35) | Flux<Role> listDependenciesFlux(Set<String> names);
method list (line 43) | Flux<Role> list(Set<String> roleNames);
method list (line 52) | Flux<Role> list(Set<String> roleNames, boolean excludeHidden);
FILE: api/src/main/java/run/halo/app/core/user/service/SignUpData.java
class SignUpData (line 25) | @Data
class SignUpDataConstraintValidator (line 65) | private static class SignUpDataConstraintValidator
method isValid (line 68) | @Override
FILE: api/src/main/java/run/halo/app/core/user/service/UserPostCreatingHandler.java
type UserPostCreatingHandler (line 13) | public interface UserPostCreatingHandler extends ExtensionPoint {
method postCreating (line 21) | Mono<Void> postCreating(User user);
FILE: api/src/main/java/run/halo/app/core/user/service/UserPreCreatingHandler.java
type UserPreCreatingHandler (line 13) | public interface UserPreCreatingHandler extends ExtensionPoint {
method preCreating (line 21) | Mono<Void> preCreating(User user);
FILE: api/src/main/java/run/halo/app/core/user/service/UserService.java
type UserService (line 9) | public interface UserService {
method getUser (line 19) | Mono<User> getUser(String username);
method findUserByVerifiedEmail (line 27) | Mono<User> findUserByVerifiedEmail(String email);
method getUserOrGhost (line 29) | Mono<User> getUserOrGhost(String username);
method getUsersOrGhosts (line 31) | Flux<User> getUsersOrGhosts(Collection<String> names);
method updatePassword (line 33) | Mono<User> updatePassword(String username, String newPassword);
method updateWithRawPassword (line 35) | Mono<User> updateWithRawPassword(String username, String rawPassword);
method grantRoles (line 37) | Mono<User> grantRoles(String username, Set<String> roles);
method hasSufficientRoles (line 45) | Mono<Boolean> hasSufficientRoles(Collection<String> roles);
method signUp (line 47) | Mono<User> signUp(SignUpData signUpData);
method createUser (line 49) | Mono<User> createUser(User user, Set<String> roles);
method confirmPassword (line 51) | Mono<Boolean> confirmPassword(String username, String rawPassword);
method listByEmail (line 53) | Flux<User> listByEmail(String email);
method checkEmailAlreadyVerified (line 55) | Mono<Boolean> checkEmailAlreadyVerified(String email);
method encryptPassword (line 57) | String encryptPassword(String rawPassword);
method disable (line 59) | Mono<User> disable(String username);
method enable (line 61) | Mono<User> enable(String username);
FILE: api/src/main/java/run/halo/app/event/post/PostDeletedEvent.java
class PostDeletedEvent (line 6) | @SharedEvent
method PostDeletedEvent (line 11) | public PostDeletedEvent(Object source, Post post) {
method getPost (line 21) | public Post getPost() {
FILE: api/src/main/java/run/halo/app/event/post/PostEvent.java
class PostEvent (line 10) | public abstract class PostEvent extends ApplicationEvent {
method PostEvent (line 14) | public PostEvent(Object source, String name) {
method getName (line 24) | public String getName() {
FILE: api/src/main/java/run/halo/app/event/post/PostPublishedEvent.java
class PostPublishedEvent (line 5) | @SharedEvent
method PostPublishedEvent (line 8) | public PostPublishedEvent(Object source, String postName) {
FILE: api/src/main/java/run/halo/app/event/post/PostUnpublishedEvent.java
class PostUnpublishedEvent (line 5) | @SharedEvent
method PostUnpublishedEvent (line 8) | public PostUnpublishedEvent(Object source, String postName) {
FILE: api/src/main/java/run/halo/app/event/post/PostUpdatedEvent.java
class PostUpdatedEvent (line 5) | @SharedEvent
method PostUpdatedEvent (line 8) | public PostUpdatedEvent(Object source, String postName) {
FILE: api/src/main/java/run/halo/app/event/post/PostVisibleChangedEvent.java
class PostVisibleChangedEvent (line 7) | @SharedEvent
method PostVisibleChangedEvent (line 15) | public PostVisibleChangedEvent(Object source, String postName,
method getOldVisible (line 22) | @Nullable
method getNewVisible (line 27) | public Post.VisibleEnum getNewVisible() {
FILE: api/src/main/java/run/halo/app/event/user/UserConnectionDisconnectedEvent.java
class UserConnectionDisconnectedEvent (line 14) | @SharedEvent
method UserConnectionDisconnectedEvent (line 20) | public UserConnectionDisconnectedEvent(Object source, UserConnection u...
FILE: api/src/main/java/run/halo/app/event/user/UserLoginEvent.java
class UserLoginEvent (line 13) | @SharedEvent
method UserLoginEvent (line 19) | public UserLoginEvent(Object source, User user) {
FILE: api/src/main/java/run/halo/app/event/user/UserLogoutEvent.java
class UserLogoutEvent (line 13) | @SharedEvent
method UserLogoutEvent (line 19) | public UserLogoutEvent(Object source, User user) {
FILE: api/src/main/java/run/halo/app/extension/AbstractExtension.java
class AbstractExtension (line 10) | @Data
method getApiVersion (line 19) | @Override
method getKind (line 25) | @Override
FILE: api/src/main/java/run/halo/app/extension/Comparators.java
type Comparators (line 6) | public enum Comparators {
method compareCreationTimestamp (line 9) | public static <E extends Extension> Comparator<E> compareCreationTimes...
method compareName (line 15) | public static <E extends Extension> Comparator<E> compareName(boolean ...
method defaultComparator (line 20) | public static <T extends Extension> Comparator<T> defaultComparator() {
method nullsComparator (line 32) | public static Comparator<Object> nullsComparator(boolean isAscending) {
FILE: api/src/main/java/run/halo/app/extension/ConfigMap.java
class ConfigMap (line 16) | @Data
method putDataItem (line 28) | public ConfigMap putDataItem(String key, String dataItem) {
FILE: api/src/main/java/run/halo/app/extension/DefaultExtensionMatcher.java
class DefaultExtensionMatcher (line 12) | @Getter
method builder (line 21) | public static DefaultExtensionMatcherBuilder builder(ExtensionClient c...
method match (line 32) | @Override
method hasFieldSelector (line 50) | boolean hasFieldSelector() {
method hasLabelSelector (line 54) | boolean hasLabelSelector() {
FILE: api/src/main/java/run/halo/app/extension/Extension.java
type Extension (line 10) | public interface Extension extends ExtensionOperator, Comparable<Extensi...
method compareTo (line 12) | @Override
FILE: api/src/main/java/run/halo/app/extension/ExtensionClient.java
type ExtensionClient (line 19) | public interface ExtensionClient {
method list (line 30) | <E extends Extension> List<E> list(Class<E> type, Predicate<E> predicate,
method list (line 45) | @Deprecated
method listAll (line 49) | <E extends Extension> List<E> listAll(Class<E> type, ListOptions optio...
method listAllNames (line 51) | <E extends Extension> List<String> listAllNames(Class<E> type, ListOpt...
method listTopNames (line 53) | <E extends Extension> List<String> listTopNames(Class<E> type, ListOpt...
method listBy (line 56) | <E extends Extension> ListResult<E> listBy(Class<E> type, ListOptions ...
method listNamesBy (line 59) | <E extends Extension> ListResult<String> listNamesBy(Class<E> type, Li...
method countBy (line 62) | <E extends Extension> long countBy(Class<E> type, ListOptions options);
method fetch (line 72) | <E extends Extension> Optional<E> fetch(Class<E> type, String name);
method fetch (line 74) | Optional<Unstructured> fetch(GroupVersionKind gvk, String name);
method create (line 84) | <E extends Extension> void create(E extension);
method update (line 93) | <E extends Extension> void update(E extension);
method delete (line 102) | <E extends Extension> void delete(E extension);
method indexedQueryEngine (line 104) | @Deprecated(forRemoval = true, since = "2.22.0")
method watch (line 107) | void watch(Watcher watcher);
FILE: api/src/main/java/run/halo/app/extension/ExtensionMatcher.java
type ExtensionMatcher (line 3) | @FunctionalInterface
method match (line 6) | boolean match(Extension extension);
FILE: api/src/main/java/run/halo/app/extension/ExtensionOperator.java
type ExtensionOperator (line 16) | public interface ExtensionOperator {
method getApiVersion (line 18) | @Schema(requiredMode = REQUIRED)
method getKind (line 32) | @Schema(requiredMode = REQUIRED)
method getMetadata (line 43) | @Schema(requiredMode = REQUIRED, implementation = Metadata.class)
method setApiVersion (line 47) | void setApiVersion(String apiVersion);
method setKind (line 49) | void setKind(String kind);
method setMetadata (line 51) | void setMetadata(MetadataOperator metadata);
method groupVersionKind (line 58) | default void groupVersionKind(GroupVersionKind gvk) {
method groupVersionKind (line 68) | @JsonIgnore
method isNotDeleted (line 73) | static <T extends ExtensionOperator> Predicate<T> isNotDeleted() {
method isDeleted (line 77) | static boolean isDeleted(ExtensionOperator extension) {
FILE: api/src/main/java/run/halo/app/extension/ExtensionUtil.java
type ExtensionUtil (line 13) | public enum ExtensionUtil {
method hasDoNotOverwriteLabel (line 28) | public static boolean hasDoNotOverwriteLabel(ExtensionOperator extensi...
method isDeleted (line 36) | public static boolean isDeleted(ExtensionOperator extension) {
method addFinalizers (line 41) | public static boolean addFinalizers(MetadataOperator metadata, Set<Str...
method removeFinalizers (line 51) | public static boolean removeFinalizers(MetadataOperator metadata, Set<...
method notDeleting (line 68) | public static Query notDeleting() {
method defaultSort (line 77) | public static Sort defaultSort() {
FILE: api/src/main/java/run/halo/app/extension/GroupVersion.java
method toString (line 15) | @Override
method parseAPIVersion (line 29) | public static GroupVersion parseAPIVersion(String apiVersion) {
FILE: api/src/main/java/run/halo/app/extension/GroupVersionKind.java
method groupVersion (line 26) | public GroupVersion groupVersion() {
method groupKind (line 30) | public GroupKind groupKind() {
method hasGroup (line 34) | public boolean hasGroup() {
method fromAPIVersionAndKind (line 45) | public static GroupVersionKind fromAPIVersionAndKind(String apiVersion, ...
method fromExtension (line 52) | public static <T extends Extension> GroupVersionKind fromExtension(Class...
method toString (line 57) | @Override
FILE: api/src/main/java/run/halo/app/extension/JsonExtension.java
class JsonExtension (line 29) | @JsonSerialize(using = JsonExtension.ObjectNodeExtensionSerializer.class)
method JsonExtension (line 38) | public JsonExtension(ObjectMapper objectMapper) {
method JsonExtension (line 42) | public JsonExtension(ObjectMapper objectMapper, ObjectNode objectNode) {
method JsonExtension (line 47) | public JsonExtension(ObjectMapper objectMapper, Extension e) {
method getMetadata (line 51) | @Override
method getApiVersion (line 60) | @Override
method getKind (line 66) | @Override
method setApiVersion (line 71) | @Override
method setKind (line 76) | @Override
method setMetadata (line 81) | @Override
class ObjectNodeExtensionSerializer (line 86) | public static class ObjectNodeExtensionSerializer extends JsonSerializ...
method serialize (line 88) | @Override
class ObjectNodeExtensionDeSerializer (line 95) | public static class ObjectNodeExtensionDeSerializer
method deserialize (line 98) | @Override
method getInternal (line 112) | public ObjectNode getInternal() {
method getObjectMapper (line 121) | public ObjectMapper getObjectMapper() {
method getMetadataOrCreate (line 125) | public MetadataOperator getMetadataOrCreate() {
method equals (line 131) | @Override
method hashCode (line 143) | @Override
class ObjectNodeMetadata (line 148) | class ObjectNodeMetadata implements MetadataOperator {
method ObjectNodeMetadata (line 152) | public ObjectNodeMetadata(ObjectNode objectNode) {
method getName (line 156) | @Override
method getGenerateName (line 162) | @Override
method getLabels (line 168) | @Override
method getAnnotations (line 175) | @Override
method getVersion (line 182) | @Override
method getCreationTimestamp (line 188) | @Override
method getDeletionTimestamp (line 193) | @Override
method getFinalizers (line 198) | @Override
method setName (line 204) | @Override
method setGenerateName (line 211) | @Override
method setLabels (line 218) | @Override
method setAnnotations (line 225) | @Override
method setVersion (line 232) | @Override
method setCreationTimestamp (line 239) | @Override
method setDeletionTimestamp (line 246) | @Override
method setFinalizers (line 253) | @Override
method equals (line 260) | @Override
method hashCode (line 270) | @Override
FILE: api/src/main/java/run/halo/app/extension/ListOptions.java
class ListOptions (line 14) | @Data
method toString (line 22) | @Override
method toCondition (line 32) | @NonNull
method builder (line 60) | public static ListOptionsBuilder builder() {
method builder (line 64) | public static ListOptionsBuilder builder(ListOptions listOptions) {
class ListOptionsBuilder (line 68) | public static class ListOptionsBuilder {
method ListOptionsBuilder (line 72) | public ListOptionsBuilder() {
method ListOptionsBuilder (line 78) | public ListOptionsBuilder(ListOptions listOptions) {
method labelSelector (line 91) | public LabelSelectorBuilder labelSelector() {
method fieldQuery (line 98) | public ListOptionsBuilder fieldQuery(Query query) {
method andQuery (line 106) | public ListOptionsBuilder andQuery(Query query) {
method orQuery (line 126) | public ListOptionsBuilder orQuery(Query query) {
method build (line 146) | public ListOptions build() {
class LabelSelectorBuilder (line 158) | public static class LabelSelectorBuilder
method LabelSelectorBuilder (line 162) | public LabelSelectorBuilder(List<LabelCondition> conditions,
method LabelSelectorBuilder (line 168) | public LabelSelectorBuilder(ListOptionsBuilder listOptionsBuilder) {
method end (line 172) | public ListOptionsBuilder end() {
FILE: api/src/main/java/run/halo/app/extension/ListResult.java
class ListResult (line 19) | @Data
method ListResult (line 36) | @JsonCreator
method ListResult (line 58) | public ListResult(List<T> items) {
method isFirst (line 62) | @Schema(description = "Indicates whether current page is the first pag...
method isLast (line 68) | @Schema(description = "Indicates whether current page is the last page.",
method hasNext (line 74) | @Schema(description = "Indicates whether current page has previous pag...
method hasPrevious (line 84) | @Schema(description = "Indicates whether current page has previous pag...
method iterator (line 91) | @Override
method getTotalPages (line 96) | @Schema(description = "Indicates total pages.", requiredMode = REQUIRED)
method generateGenericClass (line 109) | public static Class<?> generateGenericClass(Scheme scheme) {
method generateGenericClass (line 125) | public static <T> Class<?> generateGenericClass(Class<T> type) {
method emptyResult (line 130) | public static <T> ListResult<T> emptyResult() {
method subList (line 137) | public static <T> List<T> subList(List<T> list, int page, int size) {
method first (line 157) | public static <T> Optional<T> first(ListResult<T> listResult) {
method get (line 163) | @Override
FILE: api/src/main/java/run/halo/app/extension/Metadata.java
class Metadata (line 14) | @Data
FILE: api/src/main/java/run/halo/app/extension/MetadataOperator.java
type MetadataOperator (line 18) | @JsonDeserialize(as = Metadata.class)
method getName (line 23) | @Schema(name = "name", description = "Metadata name", requiredMode = R...
method getGenerateName (line 27) | @Schema(name = "generateName", description = "The name field will be g...
method getLabels (line 31) | @Schema(name = "labels")
method getAnnotations (line 35) | @Schema(name = "annotations")
method getVersion (line 39) | @Schema(name = "version", nullable = true)
method getCreationTimestamp (line 43) | @Schema(name = "creationTimestamp", nullable = true)
method getDeletionTimestamp (line 47) | @Schema(name = "deletionTimestamp", nullable = true)
method getFinalizers (line 51) | @Schema(name = "finalizers", nullable = true)
method setName (line 54) | void setName(String name);
method setGenerateName (line 56) | void setGenerateName(String generateName);
method setLabels (line 58) | void setLabels(Map<String, String> labels);
method setAnnotations (line 60) | void setAnnotations(Map<String, String> annotations);
method setVersion (line 62) | void setVersion(Long version);
method setCreationTimestamp (line 64) | void setCreationTimestamp(Instant creationTimestamp);
method setDeletionTimestamp (line 66) | void setDeletionTimestamp(Instant deletionTimestamp);
method setFinalizers (line 68) | void setFinalizers(Set<String> finalizers);
method equals (line 77) | static boolean equals(MetadataOperator left, MetadataOperator right) {
method hashCode (line 100) | static int hashCode(MetadataOperator metadata) {
FILE: api/src/main/java/run/halo/app/extension/MetadataUtil.java
type MetadataUtil (line 7) | public enum MetadataUtil {
method nullSafeLabels (line 19) | public static Map<String, String> nullSafeLabels(AbstractExtension ext...
method nullSafeAnnotations (line 36) | public static Map<String, String> nullSafeAnnotations(AbstractExtensio...
FILE: api/src/main/java/run/halo/app/extension/PageRequest.java
type PageRequest (line 15) | public interface PageRequest {
method getPageNumber (line 16) | int getPageNumber();
method getPageSize (line 18) | int getPageSize();
method previous (line 20) | PageRequest previous();
method next (line 22) | PageRequest next();
method previousOrFirst (line 31) | PageRequest previousOrFirst();
method first (line 39) | PageRequest first();
method withPage (line 47) | PageRequest withPage(int pageNumber);
method withSort (line 49) | PageRequestImpl withSort(Sort sort);
method hasPrevious (line 51) | boolean hasPrevious();
method getSort (line 53) | Sort getSort();
method getSortOr (line 61) | default Sort getSortOr(Sort sort) {
FILE: api/src/main/java/run/halo/app/extension/PageRequestImpl.java
class PageRequestImpl (line 9) | @Slf4j
method PageRequestImpl (line 18) | public PageRequestImpl(int pageNumber, int pageSize, Sort sort) {
method of (line 36) | public static PageRequestImpl of(int pageNumber, int pageSize) {
method of (line 40) | public static PageRequestImpl of(int pageNumber, int pageSize, Sort so...
method ofSize (line 44) | public static PageRequestImpl ofSize(int pageSize) {
method getPageNumber (line 48) | @Override
method getPageSize (line 53) | @Override
method previous (line 58) | @Override
method getSort (line 64) | @Override
method next (line 69) | @Override
method previousOrFirst (line 74) | @Override
method first (line 79) | @Override
method withPage (line 84) | @Override
method withSort (line 89) | @Override
method hasPrevious (line 95) | @Override
FILE: api/src/main/java/run/halo/app/extension/ReactiveExtensionClient.java
type ReactiveExtensionClient (line 16) | public interface ReactiveExtensionClient {
method list (line 27) | <E extends Extension> Flux<E> list(Class<E> type, Predicate<E> predicate,
method list (line 41) | @Deprecated
method listAll (line 45) | <E extends Extension> Flux<E> listAll(Class<E> type, ListOptions optio...
method listAllNames (line 47) | <E extends Extension> Flux<String> listAllNames(Class<E> type, ListOpt...
method listTopNames (line 49) | <E extends Extension> Flux<String> listTopNames(Class<E> type, ListOpt...
method listBy (line 52) | <E extends Extension> Mono<ListResult<E>> listBy(Class<E> type, ListOp...
method listNamesBy (line 55) | <E extends Extension> Mono<ListResult<String>> listNamesBy(Class<E> ty...
method countBy (line 58) | <E extends Extension> Mono<Long> countBy(Class<E> type, ListOptions op...
method fetch (line 68) | <E extends Extension> Mono<E> fetch(Class<E> type, String name);
method fetch (line 70) | Mono<Unstructured> fetch(GroupVersionKind gvk, String name);
method get (line 72) | <E extends Extension> Mono<E> get(Class<E> type, String name);
method getJsonExtension (line 74) | @Deprecated(forRemoval = true, since = "2.23.0")
method create (line 84) | <E extends Extension> Mono<E> create(E extension);
method update (line 93) | <E extends Extension> Mono<E> update(E extension);
method delete (line 102) | <E extends Extension> Mono<E> delete(E extension);
method indexedQueryEngine (line 104) | @Deprecated(forRemoval = true, since = "2.22.0")
method watch (line 107) | void watch(Watcher watcher);
FILE: api/src/main/java/run/halo/app/extension/Ref.java
class Ref (line 11) | @Data
method of (line 28) | public static Ref of(String name) {
method of (line 34) | public static Ref of(String name, GroupVersionKind gvk) {
method of (line 43) | public static Ref of(Extension extension) {
method groupKindEquals (line 61) | public static boolean groupKindEquals(Ref ref, GroupVersionKind gvk) {
method equals (line 73) | public static boolean equals(@NonNull Ref ref, @NonNull ExtensionOpera...
FILE: api/src/main/java/run/halo/app/extension/Scheme.java
method buildFromType (line 41) | public static Scheme buildFromType(Class<? extends Extension> type) {
method getGvkFromType (line 69) | @NonNull
method equals (line 77) | @Override
method hashCode (line 89) | @Override
FILE: api/src/main/java/run/halo/app/extension/SchemeManager.java
type SchemeManager (line 12) | public interface SchemeManager {
method register (line 20) | default <E extends Extension> void register(Class<E> type) {
method register (line 24) | default void register(Scheme scheme) {
method register (line 28) | <E extends Extension> void register(
method unregister (line 32) | void unregister(@NonNull Scheme scheme);
method size (line 34) | default int size() {
method schemes (line 38) | @NonNull
method fetch (line 41) | @NonNull
method get (line 48) | @NonNull
method get (line 54) | @NonNull
method get (line 60) | @NonNull
FILE: api/src/main/java/run/halo/app/extension/Secret.java
class Secret (line 16) | @Data
FILE: api/src/main/java/run/halo/app/extension/Unstructured.java
class Unstructured (line 37) | @JsonSerialize(using = Unstructured.UnstructuredSerializer.class)
method Unstructured (line 57) | public Unstructured() {
method Unstructured (line 61) | public Unstructured(Map data) {
method getData (line 65) | public Map getData() {
method getApiVersion (line 69) | @Override
method getKind (line 74) | @Override
method getMetadata (line 79) | @Override
class UnstructuredMetadata (line 86) | static class UnstructuredMetadata implements MetadataOperator {
method UnstructuredMetadata (line 91) | UnstructuredMetadata(@NonNull Map<String, Object> metadata) {
method getName (line 95) | @Override
method getGenerateName (line 100) | @Override
method getLabels (line 105) | @Override
method getAnnotations (line 110) | @Override
method getVersion (line 115) | @Override
method getCreationTimestamp (line 120) | @Override
method getDeletionTimestamp (line 125) | @Override
method getFinalizers (line 130) | @Override
method setName (line 135) | @Override
method setGenerateName (line 140) | @Override
method setLabels (line 145) | @Override
method setAnnotations (line 150) | @Override
method setVersion (line 155) | @Override
method setCreationTimestamp (line 160) | @Override
method setDeletionTimestamp (line 165) | @Override
method setFinalizers (line 170) | @Override
method equals (line 175) | @Override
method hashCode (line 184) | @Override
method setApiVersion (line 191) | @Override
method setKind (line 196) | @Override
method setMetadata (line 201) | @Override
method getNestedValue (line 208) | public static Optional<Object> getNestedValue(Map map, String... field...
method getNestedStringList (line 223) | @SuppressWarnings("unchecked")
method getNestedStringSet (line 228) | public static Optional<Set<String>> getNestedStringSet(Map map, String...
method setNestedValue (line 238) | @SuppressWarnings("unchecked")
method getNestedMap (line 252) | public static Optional<Map> getNestedMap(Map map, String... fields) {
method getNestedStringStringMap (line 256) | @SuppressWarnings("unchecked")
method getNestedInstant (line 263) | public static Optional<Instant> getNestedInstant(Map map, String... fi...
method getNestedLong (line 274) | public static Optional<Long> getNestedLong(Map map, String... fields) {
class UnstructuredSerializer (line 284) | public static class UnstructuredSerializer extends JsonSerializer<Unst...
method serialize (line 286) | @Override
class UnstructuredValueSerializer (line 294) | static class UnstructuredValueSerializer extends ValueSerializer<Unstr...
method serialize (line 296) | @Override
method handledType (line 303) | @Override
class UnstructuredValueDeserializer (line 309) | static class UnstructuredValueDeserializer extends ValueDeserializer<U...
method deserialize (line 311) | @Override
class UnstructuredDeserializer (line 319) | public static class UnstructuredDeserializer extends JsonDeserializer<...
method deserialize (line 321) | @Override
method equals (line 329) | @Override
method hashCode (line 341) | @Override
FILE: api/src/main/java/run/halo/app/extension/Watcher.java
type Watcher (line 8) | public interface Watcher extends Disposable {
method onAdd (line 10) | default void onAdd(Reconciler.Request request) {
method onAdd (line 14) | default void onAdd(Extension extension) {
method onUpdate (line 18) | default void onUpdate(Extension oldExtension, Extension newExtension) {
method onDelete (line 22) | default void onDelete(Extension extension) {
method registerDisposeHook (line 26) | default void registerDisposeHook(Runnable dispose) {
class WatcherComposite (line 29) | class WatcherComposite implements Watcher {
method WatcherComposite (line 37) | public WatcherComposite() {
method onAdd (line 41) | @Override
method onUpdate (line 47) | @Override
method onDelete (line 53) | @Override
method addWatcher (line 59) | public void addWatcher(Watcher watcher) {
method removeWatcher (line 66) | public void removeWatcher(Watcher watcher) {
method registerDisposeHook (line 70) | @Override
method dispose (line 75) | @Override
method isDisposed (line 84) | @Override
FILE: api/src/main/java/run/halo/app/extension/WatcherExtensionMatchers.java
class WatcherExtensionMatchers (line 8) | public class WatcherExtensionMatchers {
method WatcherExtensionMatchers (line 20) | @Builder(builderMethodName = "internalBuilder")
method getGroupVersionKind (line 36) | public GroupVersionKind getGroupVersionKind() {
method onAddMatcher (line 40) | public ExtensionMatcher onAddMatcher() {
method onUpdateMatcher (line 44) | public ExtensionMatcher onUpdateMatcher() {
method onDeleteMatcher (line 48) | public ExtensionMatcher onDeleteMatcher() {
method builder (line 52) | public static WatcherExtensionMatchersBuilder builder(ExtensionClient ...
method emptyMatcher (line 57) | static ExtensionMatcher emptyMatcher(ExtensionClient client,
method delegateExtensionMatcher (line 62) | ExtensionMatcher delegateExtensionMatcher(ExtensionMatcher matcher) {
FILE: api/src/main/java/run/halo/app/extension/WatcherPredicates.java
class WatcherPredicates (line 6) | public class WatcherPredicates {
method WatcherPredicates (line 15) | public WatcherPredicates(Predicate<Extension> onAddPredicate,
method onAddPredicate (line 23) | public Predicate<Extension> onAddPredicate() {
method onUpdatePredicate (line 30) | public BiPredicate<Extension, Extension> onUpdatePredicate() {
method onDeletePredicate (line 37) | public Predicate<Extension> onDeletePredicate() {
class Builder (line 44) | public static final class Builder {
method withGroupVersionKind (line 52) | public Builder withGroupVersionKind(GroupVersionKind gvk) {
method onAddPredicate (line 57) | public Builder onAddPredicate(Predicate<Extension> onAddPredicate) {
method onUpdatePredicate (line 62) | public Builder onUpdatePredicate(
method onDeletePredicate (line 68) | public Builder onDeletePredicate(Predicate<Extension> onDeletePredic...
method build (line 73) | public WatcherPredicates build() {
FILE: api/src/main/java/run/halo/app/extension/controller/Controller.java
type Controller (line 5) | public interface Controller extends Disposable {
method getName (line 7) | String getName();
method start (line 9) | void start();
FILE: api/src/main/java/run/halo/app/extension/controller/ControllerBuilder.java
class ControllerBuilder (line 14) | public class ControllerBuilder {
method ControllerBuilder (line 42) | public ControllerBuilder(Reconciler<Request> reconciler, ExtensionClie...
method minDelay (line 50) | public ControllerBuilder minDelay(Duration minDelay) {
method maxDelay (line 55) | public ControllerBuilder maxDelay(Duration maxDelay) {
method nowSupplier (line 60) | public ControllerBuilder nowSupplier(Supplier<Instant> nowSupplier) {
method extension (line 65) | public ControllerBuilder extension(Extension extension) {
method onAddMatcher (line 70) | public ControllerBuilder onAddMatcher(ExtensionMatcher onAddMatcher) {
method onDeleteMatcher (line 75) | public ControllerBuilder onDeleteMatcher(ExtensionMatcher onDeleteMatc...
method onUpdateMatcher (line 80) | public ControllerBuilder onUpdateMatcher(ExtensionMatcher extensionMat...
method syncAllOnStart (line 85) | public ControllerBuilder syncAllOnStart(boolean syncAllAtStart) {
method syncAllListOptions (line 90) | public ControllerBuilder syncAllListOptions(ListOptions syncAllListOpt...
method workerCount (line 95) | public ControllerBuilder workerCount(int workerCount) {
method build (line 100) | public Controller build() {
method determineSyncAllListOptions (line 132) | ListOptions determineSyncAllListOptions() {
FILE: api/src/main/java/run/halo/app/extension/controller/DefaultController.java
class DefaultController (line 19) | @Slf4j
method DefaultController (line 47) | public DefaultController(String name,
method DefaultController (line 59) | public DefaultController(String name,
method DefaultController (line 80) | public DefaultController(String name,
method DefaultController (line 89) | public DefaultController(String name,
method DefaultController (line 98) | public DefaultController(String name,
method executor (line 109) | private static Executor executor(String name) {
method getName (line 119) | @Override
method getWorkerCount (line 124) | public int getWorkerCount() {
method start (line 128) | @Override
class Worker (line 149) | class Worker implements Runnable {
method Worker (line 153) | Worker() {
method getName (line 158) | public String getName() {
method run (line 162) | @Override
method dispose (line 234) | @Override
method isDisposed (line 263) | @Override
method isStarted (line 268) | public boolean isStarted() {
method closeExecutorService (line 277) | private static void closeExecutorService(ExecutorService executorServi...
FILE: api/src/main/java/run/halo/app/extension/controller/DefaultQueue.java
class DefaultQueue (line 14) | @Slf4j
method DefaultQueue (line 31) | public DefaultQueue(Supplier<Instant> nowSupplier) {
method DefaultQueue (line 35) | public DefaultQueue(Supplier<Instant> nowSupplier, Duration minDelay) {
method addImmediately (line 44) | @Override
method add (line 51) | @Override
method take (line 88) | @Override
method done (line 106) | @Override
method size (line 122) | @Override
method peek (line 127) | @Override
method dispose (line 132) | @Override
method isDisposed (line 145) | @Override
method findOldEntry (line 150) | private Optional<DelayedEntry<R>> findOldEntry(DelayedEntry<R> entry) {
FILE: api/src/main/java/run/halo/app/extension/controller/ExtensionWatcher.java
class ExtensionWatcher (line 8) | public class ExtensionWatcher implements Watcher {
method ExtensionWatcher (line 18) | public ExtensionWatcher(RequestQueue<Request> queue, WatcherExtensionM...
method onAdd (line 23) | @Override
method onAdd (line 31) | @Override
method onUpdate (line 40) | @Override
method onDelete (line 49) | @Override
method registerDisposeHook (line 58) | @Override
method dispose (line 63) | @Override
method isDisposed (line 71) | @Override
FILE: api/src/main/java/run/halo/app/extension/controller/Reconciler.java
type Reconciler (line 5) | public interface Reconciler<R> {
method reconcile (line 7) | Result reconcile(R request);
method setupWith (line 9) | Controller setupWith(ControllerBuilder builder);
method doNotRetry (line 16) | public static Result doNotRetry() {
method requeue (line 20) | public static Result requeue(Duration retryAfter) {
FILE: api/src/main/java/run/halo/app/extension/controller/RequestQueue.java
type RequestQueue (line 11) | public interface RequestQueue<E> extends Disposable {
method addImmediately (line 13) | boolean addImmediately(E request);
method add (line 15) | boolean add(DelayedEntry<E> entry);
method take (line 17) | DelayedEntry<E> take() throws InterruptedException;
method done (line 19) | void done(E request);
method size (line 21) | long size();
method peek (line 23) | DelayedEntry<E> peek();
class DelayedEntry (line 25) | class DelayedEntry<E> implements Delayed {
method DelayedEntry (line 35) | DelayedEntry(E entry, Duration retryAfter, Supplier<Instant> nowSupp...
method DelayedEntry (line 42) | public DelayedEntry(E entry, Instant readyAt, Supplier<Instant> nowS...
method getDelay (line 49) | @Override
method getRetryAfter (line 55) | public Duration getRetryAfter() {
method getReadyAt (line 59) | public Instant getReadyAt() {
method compareTo (line 63) | @Override
method getEntry (line 68) | public E getEntry() {
method equals (line 72) | @Override
method hashCode (line 84) | @Override
FILE: api/src/main/java/run/halo/app/extension/controller/RequestSynchronizer.java
class RequestSynchronizer (line 15) | @Slf4j
method RequestSynchronizer (line 38) | public RequestSynchronizer(boolean syncAllOnStart,
method start (line 50) | @Override
method dispose (line 78) | @Override
method isDisposed (line 84) | @Override
FILE: api/src/main/java/run/halo/app/extension/controller/RequeueException.java
class RequeueException (line 11) | public class RequeueException extends RuntimeException {
method RequeueException (line 15) | public RequeueException(Result result) {
method RequeueException (line 19) | public RequeueException(Result result, String reason) {
method RequeueException (line 23) | public RequeueException(Result result, String reason, Throwable t) {
method getResult (line 28) | public Result getResult() {
FILE: api/src/main/java/run/halo/app/extension/controller/Synchronizer.java
type Synchronizer (line 5) | public interface Synchronizer<R> extends Disposable {
method start (line 7) | void start();
FILE: api/src/main/java/run/halo/app/extension/exception/ExtensionException.java
class ExtensionException (line 12) | public class ExtensionException extends ResponseStatusException {
method ExtensionException (line 14) | public ExtensionException(String reason) {
method ExtensionException (line 18) | public ExtensionException(String reason, Throwable cause) {
method ExtensionException (line 22) | protected ExtensionException(HttpStatusCode status, String reason, Thr...
FILE: api/src/main/java/run/halo/app/extension/exception/NotImplementedException.java
class NotImplementedException (line 8) | public class NotImplementedException extends UnsupportedOperationExcepti...
method NotImplementedException (line 10) | public NotImplementedException() {
method NotImplementedException (line 14) | public NotImplementedException(String message) {
FILE: api/src/main/java/run/halo/app/extension/exception/SchemeNotFoundException.java
class SchemeNotFoundException (line 11) | public class SchemeNotFoundException extends ExtensionException {
method SchemeNotFoundException (line 13) | public SchemeNotFoundException(GroupVersionKind gvk) {
FILE: api/src/main/java/run/halo/app/extension/index/AbstractValueIndexSpecBuilder.java
class AbstractValueIndexSpecBuilder (line 15) | abstract class AbstractValueIndexSpecBuilder<
method AbstractValueIndexSpecBuilder (line 29) | protected AbstractValueIndexSpecBuilder(String name, Class<K> keyType) {
method unique (line 36) | public B unique(boolean unique) {
method nullable (line 41) | public B nullable(boolean nullable) {
FILE: api/src/main/java/run/halo/app/extension/index/DefaultIndexAttribute.java
class DefaultIndexAttribute (line 9) | @Deprecated(forRemoval = true, since = "2.22.0")
method DefaultIndexAttribute (line 21) | public DefaultIndexAttribute(
method getObjectType (line 36) | @Override
method getKeyType (line 41) | @Override
method getValues (line 46) | @Override
method checkType (line 54) | private boolean checkType(Extension object) {
method singleValue (line 58) | @Override
FILE: api/src/main/java/run/halo/app/extension/index/IndexAttribute.java
type IndexAttribute (line 14) | @Deprecated(forRemoval = true, since = "2.22.0")
method getObjectType (line 22) | Class<E> getObjectType();
method getKeyType (line 29) | Class<K> getKeyType();
method getValues (line 38) | Set<K> getValues(E e);
method singleValue (line 45) | boolean singleValue();
FILE: api/src/main/java/run/halo/app/extension/index/IndexAttributeFactory.java
class IndexAttributeFactory (line 15) | @Deprecated(forRemoval = true, since = "2.22.0")
method simpleAttribute (line 19) | public static <E extends Extension> IndexAttribute<E, UnknownKey> simp...
method multiValueAttribute (line 26) | public static <E extends Extension> IndexAttribute<E, UnknownKey> mult...
method attributes (line 37) | private static <E extends Extension, K extends Comparable<K>> IndexAtt...
method attribute (line 43) | private static <E extends Extension, K extends Comparable<K>> IndexAtt...
FILE: api/src/main/java/run/halo/app/extension/index/IndexSpec.java
class IndexSpec (line 17) | @Data
method getValues (line 31) | public Set<K> getValues(E extension) {
type OrderType (line 35) | public enum OrderType {
method isNullable (line 40) | @Override
method getKeyType (line 45) | @Override
method equals (line 50) | @Override
method hashCode (line 62) | @Override
method normalize (line 72) | public ValueIndexSpec<E, K> normalize() {
FILE: api/src/main/java/run/halo/app/extension/index/IndexSpecBuilder.java
type IndexSpecBuilder (line 13) | public interface IndexSpecBuilder<
method unique (line 25) | B unique(boolean unique);
method nullable (line 33) | B nullable(boolean nullable);
method build (line 40) | ValueIndexSpec<E, K> build();
FILE: api/src/main/java/run/halo/app/extension/index/IndexSpecs.java
type IndexSpecs (line 13) | public interface IndexSpecs<E extends Extension> {
method add (line 22) | default <K extends Comparable<K>> void add(IndexSpec<E, K> indexSpec) {
method add (line 26) | <K extends Comparable<K>> void add(ValueIndexSpec<E, K> indexSpec);
method add (line 28) | default <K extends Comparable<K>> void add(IndexSpecBuilder<E, K, ?> b...
method getIndexSpecs (line 37) | List<ValueIndexSpec<E, ?>> getIndexSpecs();
method multi (line 48) | static <E extends Extension, K extends Comparable<K>> MultiValueIndexS...
method single (line 64) | static <E extends Extension, K extends Comparable<K>> SingleValueIndex...
FILE: api/src/main/java/run/halo/app/extension/index/IndexedQueryEngine.java
type IndexedQueryEngine (line 24) | @Deprecated(forRemoval = true, since = "2.22.0")
method retrieve (line 37) | ListResult<String> retrieve(GroupVersionKind type, ListOptions options...
method retrieveAll (line 48) | List<String> retrieveAll(GroupVersionKind type, ListOptions options, S...
FILE: api/src/main/java/run/halo/app/extension/index/KeyComparator.java
class KeyComparator (line 6) | @Deprecated(forRemoval = true, since = "2.22.0")
method compare (line 10) | @Override
method compareStrings (line 24) | private int compareStrings(String a, String b) {
method compareNumbers (line 60) | private int compareNumbers(String a, String b, int startA, int startB) {
method compareDecimalNumbers (line 90) | private int compareDecimalNumbers(String a, String b, int startA, int ...
method compareIntegerPart (line 105) | private int compareIntegerPart(String a, String b, int startA, int sta...
method compareFractionalPart (line 129) | private int compareFractionalPart(String a, String b, int i, int j) {
method countDigits (line 156) | private int countDigits(String s, int start) {
method moveIndexToNextNonDigit (line 165) | private int moveIndexToNextNonDigit(String s, int index) {
FILE: api/src/main/java/run/halo/app/extension/index/MultiValueBuilder.java
class MultiValueBuilder (line 16) | class MultiValueBuilder<E extends Extension, K extends Comparable<K>>
method MultiValueBuilder (line 22) | MultiValueBuilder(String name, Class<K> keyType) {
method indexFunc (line 26) | @Override
method build (line 32) | @Override
FILE: api/src/main/java/run/halo/app/extension/index/MultiValueIndexSpec.java
type MultiValueIndexSpec (line 15) | interface MultiValueIndexSpec<E extends Extension, K extends Comparable<K>>
method getValues (line 18) | @Nullable
method builder (line 21) | static <E extends Extension, K extends Comparable<K>> MultiValueBuilde...
FILE: api/src/main/java/run/halo/app/extension/index/MultiValueIndexSpecBuilder.java
type MultiValueIndexSpecBuilder (line 15) | public interface MultiValueIndexSpecBuilder<E extends Extension, K exten...
method indexFunc (line 24) | MultiValueIndexSpecBuilder<E, K> indexFunc(Function<E, Set<K>> indexFu...
FILE: api/src/main/java/run/halo/app/extension/index/SingleValueBuilder.java
class SingleValueBuilder (line 15) | class SingleValueBuilder<E extends Extension, K extends Comparable<K>>
method SingleValueBuilder (line 21) | SingleValueBuilder(String name, Class<K> keyType) {
method indexFunc (line 25) | @Override
method build (line 31) | @Override
FILE: api/src/main/java/run/halo/app/extension/index/SingleValueIndexSpec.java
type SingleValueIndexSpec (line 14) | interface SingleValueIndexSpec<E extends Extension, K extends Comparable...
method getValue (line 17) | @Nullable
method builder (line 20) | static <E extends Extension, K extends Comparable<K>> SingleValueBuild...
FILE: api/src/main/java/run/halo/app/extension/index/SingleValueIndexSpecBuilder.java
type SingleValueIndexSpecBuilder (line 14) | public interface SingleValueIndexSpecBuilder<E extends Extension, K exte...
method indexFunc (line 23) | SingleValueIndexSpecBuilder<E, K> indexFunc(Function<E, K> indexFunc);
FILE: api/src/main/java/run/halo/app/extension/index/UnknownKey.java
method compareTo (line 17) | @Override
method equals (line 22) | @Override
method toString (line 32) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/ValueIndexSpec.java
type ValueIndexSpec (line 13) | public interface ValueIndexSpec<E extends Extension, K extends Comparabl...
method getName (line 20) | String getName();
method isUnique (line 27) | boolean isUnique();
method isNullable (line 34) | boolean isNullable();
method getKeyType (line 41) | Class<K> getKeyType();
FILE: api/src/main/java/run/halo/app/extension/index/query/AllCondition.java
method not (line 7) | @Override
method toString (line 12) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/And.java
method not (line 15) | @Override
method toString (line 20) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/AndCondition.java
method not (line 13) | @Override
method toString (line 18) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/BetweenCondition.java
method not (line 9) | @Override
method toString (line 14) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/Condition.java
type Condition (line 12) | public interface Condition extends Visitable, Query {
method and (line 20) | default Condition and(Condition another) {
method or (line 30) | default Condition or(Condition another) {
method not (line 39) | default Condition not() {
method empty (line 48) | static Condition empty() {
FILE: api/src/main/java/run/halo/app/extension/index/query/EmptyCondition.java
method toString (line 7) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/EqualCondition.java
method not (line 12) | @Override
method toString (line 17) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/GreaterThanCondition.java
method not (line 8) | @Override
method toString (line 13) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/InCondition.java
method not (line 14) | @Override
method toString (line 19) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/IndexCondition.java
type IndexCondition (line 9) | public interface IndexCondition extends Condition {
method indexName (line 16) | String indexName();
FILE: api/src/main/java/run/halo/app/extension/index/query/IsNotNullCondition.java
method not (line 7) | @Override
method toString (line 12) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/IsNullCondition.java
method not (line 7) | @Override
method toString (line 12) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/LabelCondition.java
type LabelCondition (line 9) | public interface LabelCondition extends Condition {
method labelKey (line 18) | String labelKey();
method not (line 20) | @Override
FILE: api/src/main/java/run/halo/app/extension/index/query/LabelEqualsCondition.java
method not (line 7) | @Override
method toString (line 12) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/LabelExistsCondition.java
method not (line 7) | @Override
method toString (line 12) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/LabelInCondition.java
method not (line 13) | @Override
method toString (line 18) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/LabelNotEqualsCondition.java
method not (line 7) | @Override
method toString (line 12) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/LabelNotExistsCondition.java
method not (line 7) | @Override
method toString (line 12) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/LabelNotInCondition.java
method not (line 14) | @Override
method toString (line 19) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/LessThanCondition.java
method not (line 8) | @Override
method toString (line 13) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/NoneCondition.java
method not (line 7) | @Override
method toString (line 12) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/NotBetweenCondition.java
method not (line 9) | @Override
method toString (line 14) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/NotCondition.java
method not (line 12) | @Override
method toString (line 17) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/NotEqualCondition.java
method not (line 13) | @Override
method toString (line 18) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/NotInCondition.java
method not (line 14) | @Override
method toString (line 19) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/OrCondition.java
method not (line 13) | @Override
method toString (line 18) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/Queries.java
type Queries (line 17) | public enum Queries {
method and (line 27) | public static Condition and(Condition condition, Condition... addition...
method or (line 40) | public static Condition or(Condition condition, Condition... additiona...
method not (line 52) | public static Condition not(Condition condition) {
method between (line 67) | public static Condition between(String fieldName,
method empty (line 77) | public static Condition empty() {
method all (line 87) | public static Condition all(String fieldName) {
method isNull (line 97) | public static Condition isNull(String fieldName) {
method equal (line 108) | public static Condition equal(String fieldName, Object attributeValue) {
method greaterThan (line 123) | public static Condition greaterThan(
method greaterThan (line 135) | public static Condition greaterThan(String fieldName, Object attribute...
method in (line 148) | @SuppressWarnings("unchecked")
method in (line 174) | public static Condition in(String fieldName, Collection<Object> values) {
method lessThan (line 191) | public static Condition lessThan(String fieldName, Object attributeVal...
method lessThan (line 202) | public static Condition lessThan(String fieldName, Object attributeVal...
method notEqual (line 213) | public static Condition notEqual(String fieldName, Object attributeVal...
method startsWith (line 224) | public static Condition startsWith(String fieldName, String prefix) {
method endsWith (line 235) | public static Condition endsWith(String fieldName, String suffix) {
method contains (line 246) | public static Condition contains(String fieldName, String substring) {
method labelExists (line 256) | public static LabelCondition labelExists(String labelKey) {
method labelEqual (line 268) | public static LabelCondition labelEqual(String labelKey, String labelV...
method labelIn (line 280) | public static LabelCondition labelIn(String labelKey, Collection<Strin...
FILE: api/src/main/java/run/halo/app/extension/index/query/Query.java
type Query (line 13) | @Deprecated(since = "2.22.0", forRemoval = true)
FILE: api/src/main/java/run/halo/app/extension/index/query/QueryFactory.java
class QueryFactory (line 17) | @Deprecated(since = "2.22.0", forRemoval = true)
method all (line 21) | public static Query all() {
method all (line 25) | public static Query all(String fieldName) {
method isNull (line 29) | public static Query isNull(String fieldName) {
method isNotNull (line 33) | public static Query isNotNull(String fieldName) {
method notEqual (line 37) | public static Query notEqual(String fieldName, String attributeValue) {
method equal (line 41) | public static Query equal(String fieldName, String attributeValue) {
method lessThan (line 45) | public static Query lessThan(String fieldName, String attributeValue) {
method lessThanOrEqual (line 49) | public static Query lessThanOrEqual(String fieldName, String attribute...
method greaterThan (line 53) | public static Query greaterThan(String fieldName, String attributeValu...
method greaterThanOrEqual (line 57) | public static Query greaterThanOrEqual(String fieldName, String attrib...
method in (line 61) | public static Query in(String fieldName, String... attributeValues) {
method in (line 65) | public static Query in(String fieldName, Collection<String> values) {
method and (line 72) | public static Query and(Collection<Query> queries) {
method and (line 89) | public static And and(Query left, Query right) {
method and (line 97) | public static Query and(Query left, Query right, Query... additionalQu...
method and (line 105) | public static Query and(Query left, Query right, Collection<Query> add...
method or (line 113) | private static Query or(Collection<Query> queries) {
method or (line 130) | public static Query or(Query left, Query right) {
method or (line 134) | public static Query or(Query query1, Query query2, Query... additional...
method or (line 142) | public static Query or(Query query1, Query query2, Collection<Query> a...
method not (line 150) | public static Query not(Query query) {
method betweenLowerExclusive (line 156) | public static Query betweenLowerExclusive(String fieldName, String low...
method betweenUpperExclusive (line 161) | public static Query betweenUpperExclusive(String fieldName, String low...
method betweenExclusive (line 166) | public static Query betweenExclusive(String fieldName, String lowerValue,
method between (line 171) | public static Query between(String fieldName, String lowerValue, Strin...
method startsWith (line 175) | public static Query startsWith(String fieldName, String value) {
method endsWith (line 179) | public static Query endsWith(String fieldName, String value) {
method contains (line 183) | public static Query contains(String fieldName, String value) {
FILE: api/src/main/java/run/halo/app/extension/index/query/StringContainsCondition.java
method not (line 7) | @Override
method toString (line 12) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/StringEndsWithCondition.java
method not (line 7) | @Override
method toString (line 12) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/StringNotContainsCondition.java
method not (line 7) | @Override
method toString (line 12) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/StringNotEndsWithCondition.java
method not (line 7) | @Override
method toString (line 12) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/StringNotStartsWithCondition.java
method not (line 7) | @Override
method toString (line 12) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/index/query/StringStartsWithCondition.java
method not (line 7) | @Override
method toString (line 12) | @NotNull
FILE: api/src/main/java/run/halo/app/extension/router/IListRequest.java
type IListRequest (line 16) | public interface IListRequest {
method getPage (line 18) | @Schema(description = "The page number. Zero indicates no page.")
method getSize (line 21) | @Schema(description = "Size of one page. Zero indicates no limit.")
method getLabelSelector (line 24) | @Schema(description = "Label selector for filtering.")
method getFieldSelector (line 27) | @Schema(description = "Field selector for filtering.")
class QueryListRequest (line 30) | class QueryListRequest implements IListRequest {
method QueryListRequest (line 37) | public QueryListRequest(MultiValueMap<String, String> queryParams) {
method getPage (line 41) | @Override
method getSize (line 50) | @Override
method getLabelSelector (line 59) | @Override
method getFieldSelector (line 64) | @Override
method buildParameters (line 70) | static void buildParameters(Builder builder) {
FILE: api/src/main/java/run/halo/app/extension/router/QueryParamBuildUtil.java
class QueryParamBuildUtil (line 11) | @Slf4j
method sortParameter (line 15) | public static org.springdoc.core.fn.builders.parameter.Builder sortPar...
FILE: api/src/main/java/run/halo/app/extension/router/SortableRequest.java
class SortableRequest (line 25) | public class SortableRequest extends IListRequest.QueryListRequest {
method SortableRequest (line 29) | public SortableRequest(ServerWebExchange exchange) {
method getSort (line 34) | @ArraySchema(uniqueItems = true,
method toListOptions (line 51) | public ListOptions toListOptions() {
method toPageRequest (line 55) | public PageRequest toPageRequest() {
method toComparator (line 65) | public <T extends Extension> Comparator<T> toComparator() {
method buildParameters (line 90) | public static void buildParameters(Builder builder) {
FILE: api/src/main/java/run/halo/app/extension/router/selector/FieldSelector.java
method FieldSelector (line 12) | public FieldSelector(Query query) {
method of (line 16) | public static FieldSelector of(Query query) {
method all (line 20) | public static FieldSelector all() {
method andQuery (line 24) | public FieldSelector andQuery(Query other) {
FILE: api/src/main/java/run/halo/app/extension/router/selector/FieldSelectorConverter.java
class FieldSelectorConverter (line 12) | public class FieldSelectorConverter implements Converter<SelectorCriteri...
method convert (line 14) | @NonNull
method getSingleValue (line 39) | String getSingleValue(SelectorCriteria criteria) {
FILE: api/src/main/java/run/halo/app/extension/router/selector/LabelSelector.java
class LabelSelector (line 13) | @Data
method toString (line 19) | @Override
method and (line 38) | public LabelSelector and(LabelSelector other) {
method builder (line 47) | public static LabelSelectorBuilder<?> builder() {
class LabelSelectorBuilder (line 51) | public static class LabelSelectorBuilder<T extends LabelSelectorBuilde...
method LabelSelectorBuilder (line 54) | public LabelSelectorBuilder() {
method LabelSelectorBuilder (line 60) | public LabelSelectorBuilder(List<LabelCondition> conditions) {
method self (line 66) | @SuppressWarnings("unchecked")
method eq (line 71) | public T eq(String key, String value) {
method notEq (line 76) | public T notEq(String key, String value) {
method in (line 81) | public T in(String key, String... values) {
method notIn (line 86) | public T notIn(String key, String... values) {
method exists (line 91) | public T exists(String key) {
method notExists (line 96) | public T notExists(String key) {
method build (line 104) | public LabelSelector build() {
FILE: api/src/main/java/run/halo/app/extension/router/selector/LabelSelectorConverter.java
class LabelSelectorConverter (line 12) | public class LabelSelectorConverter implements Converter<SelectorCriteri...
method convert (line 14) | @NonNull
method getSingleValue (line 38) | String getSingleValue(SelectorCriteria criteria) {
FILE: api/src/main/java/run/halo/app/extension/router/selector/Operator.java
type Operator (line 7) | public enum Operator implements Converter<String, SelectorCriteria> {
method convert (line 10) | @Override
method convert (line 25) | @Override
method convert (line 42) | @Override
method convert (line 57) | @Override
method convert (line 69) | @Override
method Operator (line 85) | Operator(String operator, int order) {
method getOperator (line 90) | public String getOperator() {
method getOrder (line 94) | public int getOrder() {
method preFlightCheck (line 98) | protected boolean preFlightCheck(String selector, int minLength) {
FILE: api/src/main/java/run/halo/app/extension/router/selector/SelectorConverter.java
class SelectorConverter (line 10) | @Slf4j
method convert (line 13) | @Override
FILE: api/src/main/java/run/halo/app/extension/router/selector/SelectorUtil.java
class SelectorUtil (line 9) | public final class SelectorUtil {
method SelectorUtil (line 11) | private SelectorUtil() {
method labelAndFieldSelectorToListOptions (line 21) | public static ListOptions labelAndFieldSelectorToListOptions(
FILE: api/src/main/java/run/halo/app/infra/AnonymousUserConst.java
type AnonymousUserConst (line 3) | public interface AnonymousUserConst {
method isAnonymousUser (line 8) | static boolean isAnonymousUser(String principal) {
FILE: api/src/main/java/run/halo/app/infra/BackupRootGetter.java
type BackupRootGetter (line 12) | public interface BackupRootGetter extends Supplier<Path> {
FILE: api/src/main/java/run/halo/app/infra/Condition.java
class Condition (line 22) | @Data
FILE: api/src/main/java/run/halo/app/infra/ConditionList.java
class ConditionList (line 21) | public class ConditionList extends AbstractCollection<Condition> {
method add (line 25) | @Override
method addFirst (line 33) | public boolean addFirst(@NonNull Condition condition) {
method addAndEvictFIFO (line 47) | public boolean addAndEvictFIFO(@NonNull Condition condition) {
method addAndEvictFIFO (line 57) | public boolean addAndEvictFIFO(@NonNull Condition condition, int evict...
method getCondition (line 75) | private Condition getCondition(String type) {
method remove (line 85) | public void remove(Condition condition) {
method peek (line 99) | public Condition peek() {
method peekFirst (line 103) | public Condition peekFirst() {
method removeLast (line 107) | public Condition removeLast() {
method clear (line 111) | @Override
method size (line 116) | public int size() {
method isSame (line 120) | private boolean isSame(Condition a, Condition b) {
method iterator (line 130) | @Override
method forEach (line 135) | @Override
method equals (line 140) | @Override
method hashCode (line 152) | @Override
FILE: api/src/main/java/run/halo/app/infra/ConditionStatus.java
type ConditionStatus (line 7) | public enum ConditionStatus {
FILE: api/src/main/java/run/halo/app/infra/ExternalLinkProcessor.java
type ExternalLinkProcessor (line 14) | public interface ExternalLinkProcessor {
method processLink (line 23) | String processLink(String link);
method processLink (line 36) | Mono<URI> processLink(URI uri);
FILE: api/src/main/java/run/halo/app/infra/ExternalUrlSupplier.java
type ExternalUrlSupplier (line 14) | public interface ExternalUrlSupplier extends Supplier<URI> {
method get (line 22) | @Override
method getURL (line 32) | URL getURL(HttpRequest request);
method getRaw (line 39) | @Nullable
FILE: api/src/main/java/run/halo/app/infra/FileCategoryMatcher.java
type FileCategoryMatcher (line 23) | public enum FileCategoryMatcher {
method match (line 25) | @Override
method match (line 31) | @Override
method match (line 37) | @Override
method match (line 43) | @Override
method match (line 49) | @Override
method match (line 65) | @Override
method match (line 88) | @Override
method match (line 94) | public abstract boolean match(String mimeType);
method of (line 99) | public static FileCategoryMatcher of(String name) {
FILE: api/src/main/java/run/halo/app/infra/SystemInfo.java
class SystemInfo (line 10) | @Data
class SeoProp (line 33) | @Data
FILE: api/src/main/java/run/halo/app/infra/SystemInfoGetter.java
type SystemInfoGetter (line 6) | public interface SystemInfoGetter extends Supplier<Mono<SystemInfo>> {
FILE: api/src/main/java/run/halo/app/infra/SystemSetting.java
class SystemSetting (line 25) | public class SystemSetting {
class Theme (line 62) | @Data
class ThemeRouteRules (line 69) | @Data
method empty (line 79) | public static ThemeRouteRules empty() {
class CodeInjection (line 89) | @Data
class Basic (line 100) | @Data
method useSystemLocale (line 110) | @JsonIgnore
class User (line 118) | @Data
class Post (line 140) | @Data
class Seo (line 155) | @Data
class Comment (line 163) | @Data
class Menu (line 171) | @Data
class AuthProvider (line 177) | @Data
class AuthProviderState (line 185) | @Data
class ExtensionPointEnabled (line 197) | public static class ExtensionPointEnabled extends LinkedHashMap<String...
method get (line 203) | @Nullable
FILE: api/src/main/java/run/halo/app/infra/SystemVersionSupplier.java
type SystemVersionSupplier (line 14) | public interface SystemVersionSupplier extends Supplier<Version> {
FILE: api/src/main/java/run/halo/app/infra/ValidationUtils.java
class ValidationUtils (line 11) | @UtilityClass
method validate (line 27) | public static BindingResult validate(Object target, String objectName,
method validate (line 39) | public static BindingResult validate(Object target, Validator validator,
FILE: api/src/main/java/run/halo/app/infra/model/License.java
class License (line 8) | @Data
FILE: api/src/main/java/run/halo/app/infra/utils/FileTypeDetectUtils.java
class FileTypeDetectUtils (line 17) | @UtilityClass
method detectMimeType (line 30) | public static String detectMimeType(InputStream inputStream, String na...
method detectMimeType (line 42) | public static String detectMimeType(InputStream inputStream) throws IO...
method doDetectMimeType (line 46) | private static String doDetectMimeType(InputStream inputStream, Metada...
method detectFileExtension (line 55) | public static String detectFileExtension(String mimeType) throws MimeT...
method detectFileExtensions (line 60) | public static List<String> detectFileExtensions(String mimeType) throw...
method getFileExtension (line 69) | @NonNull
method isValidExtensionForMime (line 90) | public boolean isValidExtensionForMime(String mimeType, String fileNam...
FILE: api/src/main/java/run/halo/app/infra/utils/GenericClassUtils.java
type GenericClassUtils (line 7) | public enum GenericClassUtils {
method generateConcreteClass (line 18) | public static <T> Class<?> generateConcreteClass(Class<?> rawClass, Cl...
method generateConcreteClass (line 32) | public static <T> Class<?> generateConcreteClass(Class<?> rawClass, Cl...
FILE: api/src/main/java/run/halo/app/infra/utils/JsonParseException.java
class JsonParseException (line 9) | public class JsonParseException extends RuntimeException {
method JsonParseException (line 10) | public JsonParseException() {
method JsonParseException (line 14) | public JsonParseException(String message) {
method JsonParseException (line 18) | public JsonParseException(String message, Throwable cause) {
method JsonParseException (line 22) | public JsonParseException(Throwable cause) {
method JsonParseException (line 26) | protected JsonParseException(String message, Throwable cause, boolean ...
FILE: api/src/main/java/run/halo/app/infra/utils/JsonUtils.java
class JsonUtils (line 20) | @Deprecated(forRemoval = true, since = "2.23.0")
method JsonUtils (line 24) | private JsonUtils() {
method mapper (line 27) | public static ObjectMapper mapper() {
method mapToObject (line 39) | @NonNull
method objectToJson (line 50) | @NonNull
method jsonToObject (line 68) | public static <T> T jsonToObject(String json, Class<T> toValueType) {
method jsonToObject (line 84) | public static <T> T jsonToObject(String json, TypeReference<T> typeRef...
method deepCopy (line 99) | @SuppressWarnings("unchecked")
FILE: api/src/main/java/run/halo/app/infra/utils/PathUtils.java
class PathUtils (line 15) | @Slf4j
method isAbsoluteUri (line 39) | public static boolean isAbsoluteUri(final String uriString) {
method combinePath (line 61) | public static String combinePath(String... pathSegments) {
method appendPathSeparatorIfMissing (line 87) | public static String appendPathSeparatorIfMissing(String path) {
method simplifyPathPattern (line 104) | public static String simplifyPathPattern(String pattern) {
FILE: api/src/main/java/run/halo/app/migration/Backup.java
class Backup (line 11) | @Data
class Spec (line 22) | @Data
class Status (line 33) | @Data
type Phase (line 58) | public enum Phase {
FILE: api/src/main/java/run/halo/app/migration/Constant.java
type Constant (line 3) | public enum Constant {
FILE: api/src/main/java/run/halo/app/notification/NotificationCenter.java
type NotificationCenter (line 13) | public interface NotificationCenter {
method notify (line 20) | Mono<Void> notify(Reason reason);
method subscribe (line 29) | Mono<Subscription> subscribe(Subscription.Subscriber subscriber,
method unsubscribe (line 37) | Mono<Void> unsubscribe(Subscription.Subscriber subscriber);
method unsubscribe (line 45) | Mono<Void> unsubscribe(Subscription.Subscriber subscriber, Subscriptio...
FILE: api/src/main/java/run/halo/app/notification/NotificationContext.java
class NotificationContext (line 8) | @Data
class Message (line 17) | @Data
class Subject (line 28) | @Data
class MessagePayload (line 38) | @Data
FILE: api/src/main/java/run/halo/app/notification/NotificationReasonEmitter.java
type NotificationReasonEmitter (line 13) | public interface NotificationReasonEmitter {
method emit (line 21) | Mono<Void> emit(String reasonType, Consumer<ReasonPayload.ReasonPayloa...
FILE: api/src/main/java/run/halo/app/notification/ReactiveNotifier.java
type ReactiveNotifier (line 12) | public interface ReactiveNotifier extends ExtensionPoint {
method notify (line 19) | Mono<Void> notify(NotificationContext context);
FILE: api/src/main/java/run/halo/app/notification/ReasonAttributes.java
class ReasonAttributes (line 11) | public class ReasonAttributes extends HashMap<String, Object> {
FILE: api/src/main/java/run/halo/app/notification/ReasonPayload.java
class ReasonPayload (line 16) | @Data
method builder (line 23) | public static ReasonPayloadBuilder builder() {
class ReasonPayloadBuilder (line 27) | public static class ReasonPayloadBuilder {
method ReasonPayloadBuilder (line 32) | ReasonPayloadBuilder() {
method subject (line 36) | public ReasonPayloadBuilder subject(Reason.Subject subject) {
method attribute (line 41) | public ReasonPayloadBuilder attribute(String key, Object value) {
method attributes (line 46) | public ReasonPayloadBuilder attributes(Map<String, Object> attribute...
method author (line 51) | public ReasonPayloadBuilder author(UserIdentity author) {
method build (line 56) | public ReasonPayload build() {
FILE: api/src/main/java/run/halo/app/notification/UserIdentity.java
method of (line 23) | public static UserIdentity of(String username) {
method anonymousWithEmail (line 35) | public static UserIdentity anonymousWithEmail(String email) {
method isAnonymous (line 41) | public boolean isAnonymous() {
method getEmail (line 50) | public Optional<String> getEmail() {
FILE: api/src/main/java/run/halo/app/plugin/BasePlugin.java
class BasePlugin (line 14) | @Getter
method BasePlugin (line 25) | public BasePlugin(PluginContext pluginContext) {
method BasePlugin (line 29) | public BasePlugin() {
FILE: api/src/main/java/run/halo/app/plugin/PluginConfigUpdatedEvent.java
class PluginConfigUpdatedEvent (line 20) | @Getter
method PluginConfigUpdatedEvent (line 49) | @Builder
FILE: api/src/main/java/run/halo/app/plugin/PluginContext.java
class PluginContext (line 20) | @Getter
FILE: api/src/main/java/run/halo/app/plugin/PluginsRootGetter.java
type PluginsRootGetter (line 12) | public interface PluginsRootGetter extends Supplier<Path> {
FILE: api/src/main/java/run/halo/app/plugin/ReactiveSettingFetcher.java
type ReactiveSettingFetcher (line 13) | public interface ReactiveSettingFetcher {
method fetch (line 15) | <T> Mono<T> fetch(String group, Class<T> clazz);
method get (line 17) | @Deprecated(forRemoval = true, since = "2.23.0")
method getSettingValue (line 26) | Mono<JsonNode> getSettingValue(String group);
method getValues (line 28) | @Deprecated(forRemoval = true, since = "2.23.0")
method getSettingValues (line 36) | Mono<Map<String, JsonNode>> getSettingValues();
FILE: api/src/main/java/run/halo/app/plugin/SettingFetcher.java
type SettingFetcher (line 13) | public interface SettingFetcher {
method fetch (line 15) | <T> Optional<T> fetch(String group, Class<T> clazz);
method get (line 24) | @Deprecated(forRemoval = true, since = "2.23.0")
method getSettingValue (line 33) | JsonNode getSettingValue(String group);
method getValues (line 41) | @Deprecated(forRemoval = true, since = "2.23.0")
method getSettingValues (line 49) | Map<String, JsonNode> getSettingValues();
FILE: api/src/main/java/run/halo/app/plugin/event/PluginStartedEvent.java
class PluginStartedEvent (line 11) | public class PluginStartedEvent extends ApplicationEvent {
method PluginStartedEvent (line 13) | public PluginStartedEvent(Object source) {
FILE: api/src/main/java/run/halo/app/plugin/extensionpoint/ExtensionGetter.java
type ExtensionGetter (line 8) | public interface ExtensionGetter {
method getEnabledExtension (line 17) | <T extends ExtensionPoint> Mono<T> getEnabledExtension(Class<T> extens...
method getEnabledExtensions (line 28) | <T extends ExtensionPoint> Flux<T> getEnabledExtensions(Class<T> exten...
method getExtensions (line 37) | <T extends ExtensionPoint> Flux<T> getExtensions(Class<T> extensionPoi...
method getExtensionList (line 46) | <T extends ExtensionPoint> List<T> getExtensionList(Class<T> extension...
FILE: api/src/main/java/run/halo/app/search/HaloDocument.java
class HaloDocument (line 13) | @Data
FILE: api/src/main/java/run/halo/app/search/HaloDocumentsProvider.java
type HaloDocumentsProvider (line 11) | public interface HaloDocumentsProvider extends ExtensionPoint {
method fetchAll (line 18) | Flux<HaloDocument> fetchAll();
method getType (line 25) | String getType();
FILE: api/src/main/java/run/halo/app/search/SearchEngine.java
type SearchEngine (line 11) | public interface SearchEngine extends ExtensionPoint {
method available (line 18) | boolean available();
method addOrUpdate (line 25) | void addOrUpdate(Iterable<HaloDocument> haloDocuments);
method deleteDocument (line 32) | void deleteDocument(Iterable<String> haloDocIds);
method deleteAll (line 37) | void deleteAll();
method search (line 45) | SearchResult search(SearchOption option);
FILE: api/src/main/java/run/halo/app/search/SearchOption.java
class SearchOption (line 15) | @Data
FILE: api/src/main/java/run/halo/app/search/SearchResult.java
class SearchResult (line 6) | @Data
FILE: api/src/main/java/run/halo/app/search/SearchService.java
type SearchService (line 11) | public interface SearchService {
method search (line 19) | Mono<SearchResult> search(SearchOption option);
FILE: api/src/main/java/run/halo/app/search/event/HaloDocumentAddRequestEvent.java
class HaloDocumentAddRequestEvent (line 7) | @SharedEvent
method HaloDocumentAddRequestEvent (line 12) | public HaloDocumentAddRequestEvent(Object source, Iterable<HaloDocumen...
method getDocuments (line 17) | public Iterable<HaloDocument> getDocuments() {
FILE: api/src/main/java/run/halo/app/search/event/HaloDocumentDeleteRequestEvent.java
class HaloDocumentDeleteRequestEvent (line 7) | @SharedEvent
method HaloDocumentDeleteRequestEvent (line 18) | public HaloDocumentDeleteRequestEvent(Object source, @Nullable Iterabl...
method getDocIds (line 23) | public Iterable<String> getDocIds() {
FILE: api/src/main/java/run/halo/app/search/event/HaloDocumentRebuildRequestEvent.java
class HaloDocumentRebuildRequestEvent (line 6) | @SharedEvent
method HaloDocumentRebuildRequestEvent (line 9) | public HaloDocumentRebuildRequestEvent(Object source) {
FILE: api/src/main/java/run/halo/app/security/AdditionalWebFilter.java
type AdditionalWebFilter (line 15) | public interface AdditionalWebFilter extends WebFilter, ExtensionPoint, ...
method getOrder (line 22) | default int getOrder() {
FILE: api/src/main/java/run/halo/app/security/AfterSecurityWebFilter.java
type AfterSecurityWebFilter (line 12) | public interface AfterSecurityWebFilter extends WebFilter, ExtensionPoint {
FILE: api/src/main/java/run/halo/app/security/AnonymousAuthenticationSecurityWebFilter.java
type AnonymousAuthenticationSecurityWebFilter (line 11) | public interface AnonymousAuthenticationSecurityWebFilter extends WebFil...
FILE: api/src/main/java/run/halo/app/security/AuthenticationSecurityWebFilter.java
type AuthenticationSecurityWebFilter (line 11) | public interface AuthenticationSecurityWebFilter extends WebFilter, Exte...
FILE: api/src/main/java/run/halo/app/security/BeforeSecurityWebFilter.java
type BeforeSecurityWebFilter (line 12) | public interface BeforeSecurityWebFilter extends WebFilter, ExtensionPoi...
FILE: api/src/main/java/run/halo/app/security/FormLoginSecurityWebFilter.java
type FormLoginSecurityWebFilter (line 11) | public interface FormLoginSecurityWebFilter extends WebFilter, Extension...
FILE: api/src/main/java/run/halo/app/security/HttpBasicSecurityWebFilter.java
type HttpBasicSecurityWebFilter (line 12) | public interface HttpBasicSecurityWebFilter extends WebFilter, Extension...
FILE: api/src/main/java/run/halo/app/security/LoginHandlerEnhancer.java
type LoginHandlerEnhancer (line 17) | public interface LoginHandlerEnhancer {
method onLoginSuccess (line 25) | Mono<Void> onLoginSuccess(ServerWebExchange exchange, Authentication s...
method onLoginFailure (line 33) | Mono<Void> onLoginFailure(ServerWebExchange exchange, AuthenticationEx...
FILE: api/src/main/java/run/halo/app/security/OAuth2AuthorizationCodeSecurityWebFilter.java
type OAuth2AuthorizationCodeSecurityWebFilter (line 12) | public interface OAuth2AuthorizationCodeSecurityWebFilter extends WebFil...
FILE: api/src/main/java/run/halo/app/security/PersonalAccessToken.java
class PersonalAccessToken (line 14) | @Data
class Spec (line 27) | @Data
FILE: api/src/main/java/run/halo/app/security/authentication/CryptoService.java
type CryptoService (line 6) | public interface CryptoService {
method decrypt (line 14) | Mono<byte[]> decrypt(byte[] encryptedMessage);
method readPublicKey (line 21) | Mono<byte[]> readPublicKey();
method getKeyId (line 28) | String getKeyId();
method getJwk (line 35) | JWK getJwk();
FILE: api/src/main/java/run/halo/app/security/authentication/login/UsernamePasswordAuthenticationManager.java
type UsernamePasswordAuthenticationManager (line 15) | public interface UsernamePasswordAuthenticationManager
FILE: api/src/main/java/run/halo/app/security/authentication/oauth2/HaloOAuth2AuthenticationToken.java
class HaloOAuth2AuthenticationToken (line 20) | public class HaloOAuth2AuthenticationToken extends AbstractAuthenticatio...
method HaloOAuth2AuthenticationToken (line 35) | public HaloOAuth2AuthenticationToken(UserDetails userDetails,
method getName (line 43) | @Override
method getAuthorities (line 48) | @Override
method getCredentials (line 60) | @Override
method getPrincipal (line 65) | @Override
method authenticated (line 78) | public static HaloOAuth2AuthenticationToken authenticated(
method combineAuthorities (line 84) | private static Collection<? extends GrantedAuthority> combineAuthorities(
FILE: api/src/main/java/run/halo/app/security/device/DeviceService.java
type DeviceService (line 7) | public interface DeviceService {
method loginSuccess (line 9) | Mono<Void> loginSuccess(ServerWebExchange exchange, Authentication suc...
method changeSessionId (line 11) | Mono<Void> changeSessionId(ServerWebExchange exchange);
method revoke (line 13) | Mono<Void> revoke(String principalName, String deviceId);
method revoke (line 15) | Mono<Void> revoke(String username);
FILE: api/src/main/java/run/halo/app/theme/Constant.java
type Constant (line 8) | public enum Constant {
FILE: api/src/main/java/run/halo/app/theme/ReactivePostContentHandler.java
type ReactivePostContentHandler (line 20) | public interface ReactivePostContentHandler extends ExtensionPoint {
method handle (line 30) | Mono<PostContentContext> handle(@NonNull PostContentContext postContent);
class PostContentContext (line 32) | @Data
FILE: api/src/main/java/run/halo/app/theme/ReactiveSinglePageContentHandler.java
type ReactiveSinglePageContentHandler (line 18) | public interface ReactiveSinglePageContentHandler extends ExtensionPoint {
method handle (line 28) | Mono<SinglePageContentContext> handle(@NonNull SinglePageContentContex...
class SinglePageContentContext (line 30) | @Data
FILE: api/src/main/java/run/halo/app/theme/TemplateNameResolver.java
type TemplateNameResolver (line 15) | public interface TemplateNameResolver {
method resolveTemplateNameOrDefault (line 24) | Mono<String> resolveTemplateNameOrDefault(ServerWebExchange exchange, ...
method resolveTemplateNameOrDefault (line 34) | Mono<String> resolveTemplateNameOrDefault(ServerWebExchange exchange, ...
method isTemplateAvailableInTheme (line 44) | Mono<Boolean> isTemplateAvailableInTheme(ServerWebExchange exchange, S...
FILE: api/src/main/java/run/halo/app/theme/dialect/CommentWidget.java
type CommentWidget (line 14) | public interface CommentWidget extends ExtensionPoint {
method render (line 18) | void render(ITemplateContext context, IProcessableElementTag tag,
FILE: api/src/main/java/run/halo/app/theme/dialect/ElementTagPostProcessor.java
type ElementTagPostProcessor (line 14) | public interface ElementTagPostProcessor extends ExtensionPoint {
method process (line 36) | Mono<IProcessableElementTag> process(
FILE: api/src/main/java/run/halo/app/theme/dialect/TemplateFooterProcessor.java
type TemplateFooterProcessor (line 16) | public interface TemplateFooterProcessor extends ExtensionPoint {
method process (line 18) | Mono<Void> process(ITemplateContext context, IProcessableElementTag tag,
FILE: api/src/main/java/run/halo/app/theme/dialect/TemplateHeadProcessor.java
type TemplateHeadProcessor (line 18) | @FunctionalInterface
method process (line 21) | Mono<Void> process(ITemplateContext context, IModel model,
FILE: api/src/main/java/run/halo/app/theme/finders/vo/ExtensionVoOperator.java
type ExtensionVoOperator (line 12) | public interface ExtensionVoOperator {
method getMetadata (line 14) | @NonNull
FILE: api/src/main/java/run/halo/app/theme/router/ModelConst.java
type ModelConst (line 9) | public enum ModelConst {
FILE: api/src/main/java/run/halo/app/theme/router/PageUrlUtils.java
class PageUrlUtils (line 17) | public class PageUrlUtils {
method pageNum (line 20) | public static int pageNum(ServerRequest request) {
method isPageUrl (line 28) | public static boolean isPageUrl(String path) {
method totalPage (line 37) | public static long totalPage(ListResult<?> list) {
method nextPageUrl (line 47) | public static String nextPageUrl(String path, long total) {
method prevPageUrl (line 69) | public static String prevPageUrl(String path) {
method appendPagePart (line 90) | private static String appendPagePart(String path, long page) {
method toNextPage (line 94) | private static String toNextPage(String pageStr, long total) {
method toPrevPage (line 99) | private static int toPrevPage(String pageStr) {
method parseInt (line 103) | private static int parseInt(String pageStr) {
FILE: api/src/main/java/run/halo/app/theme/router/UrlContextListResult.java
class UrlContextListResult (line 15) | @Getter
method UrlContextListResult (line 21) | public UrlContextListResult(int page, int size, long total, List<T> it...
class Builder (line 28) | public static class Builder<T> {
method page (line 36) | public Builder<T> page(int page) {
method size (line 41) | public Builder<T> size(int size) {
method total (line 46) | public Builder<T> total(long total) {
method items (line 51) | public Builder<T> items(List<T> items) {
method nextUrl (line 56) | public Builder<T> nextUrl(String nextUrl) {
method prevUrl (line 61) | public Builder<T> prevUrl(String prevUrl) {
method listResult (line 72) | public Builder<T> listResult(ListResult<T> listResult) {
method build (line 80) | public UrlContextListResult<T> build() {
FILE: api/src/test/java/run/halo/app/core/extension/content/PostTest.java
class PostTest (line 14) | class PostTest {
method isRecycledTest (line 16) | @ParameterizedTest
method isRecycledProvider (line 22) | static Stream<Arguments> isRecycledProvider() {
FILE: api/src/test/java/run/halo/app/core/extension/notification/SubscriptionTest.java
class SubscriptionTest (line 14) | class SubscriptionTest {
method reasonSubjectToStringTest (line 16) | @Test
FILE: api/src/test/java/run/halo/app/extension/ExtensionUtilTest.java
class ExtensionUtilTest (line 16) | class ExtensionUtilTest {
method testIsNotDeleted (line 18) | @Test
method addFinalizers (line 34) | @Test
method removeFinalizers (line 49) | @Test
method hasDoNotOverwriteLabelTests (line 60) | @Test
FILE: api/src/test/java/run/halo/app/extension/FakeExtension.java
class FakeExtension (line 3) | @GVK(group = "fake.halo.run",
method createFake (line 10) | public static FakeExtension createFake(String name) {
FILE: api/src/test/java/run/halo/app/extension/ListOptionsTest.java
class ListOptionsTest (line 15) | class ListOptionsTest {
class ListOptionsBuilderTest (line 17) | @Nested
method shouldBuildWithFieldAndLabelSelectors (line 20) | @Test
method shouldBuildLabelSelectorOnly (line 39) | @Test
method shouldBuildFieldSelectorOnly (line 51) | @Test
FILE: api/src/test/java/run/halo/app/extension/PageRequestImplTest.java
class PageRequestImplTest (line 9) | class PageRequestImplTest {
method shouldBeCompatibleZeroAndNegativePageNumber (line 11) | @ParameterizedTest
method shouldBeCompatibleNegativePageSize (line 21) | @ParameterizedTest
FILE: api/src/test/java/run/halo/app/extension/SecretTest.java
class SecretTest (line 19) | class SecretTest {
method serialize (line 21) | @Test
method deserialize (line 32) | @Test
method deserializeWithUnstructured (line 42) | @Test
method deserializeYamlWithStringData (line 50) | @Test
method testJsonString (line 69) | private String testJsonString() {
FILE: api/src/test/java/run/halo/app/extension/controller/ControllerBuilderTest.java
class ControllerBuilderTest (line 15) | @ExtendWith(MockitoExtension.class)
method buildWithNullReconciler (line 21) | @Test
method buildWithNullClient (line 27) | @Test
method buildTest (line 33) | @Test
method invalidMinDelayAndMaxDelay (line 60) | @Test
method fakeBuilder (line 88) | ControllerBuilder fakeBuilder() {
class FakeReconciler (line 93) | static class FakeReconciler implements Reconciler<Reconciler.Request> {
method reconcile (line 95) | @Override
method setupWith (line 100) | @Override
FILE: api/src/test/java/run/halo/app/extension/controller/DefaultControllerTest.java
class DefaultControllerTest (line 31) | @ExtendWith(MockitoExtension.class)
method setUp (line 54) | @BeforeEach
method createController (line 62) | DefaultController<Request> createController(int workerCount) {
method shouldReturnRightName (line 67) | @Test
class WorkerTest (line 72) | @Nested
method shouldCreateCorrectName (line 75) | @Test
method shouldRunCorrectlyIfReconcilerReturnsNoReEnqueue (line 85) | @Test
method shouldRunCorrectlyIfReconcilerReturnsReEnqueue (line 102) | @Test
method shouldReRunIfReconcilerThrowException (line 122) | @Test
method canReRunIfReconcilerThrowRequeueException (line 142) | @Test
method doNotReRunIfReconcilerThrowsRequeueExceptionWithoutRequeue (line 163) | @Test
method shouldSetMinRetryAfterWhenTakeZeroDelayedEntry (line 183) | @Test
method shouldSetMaxRetryAfterWhenTakeGreaterThanMaxRetryAfterDelayedEntry (line 203) | @Test
method shouldDisposeCorrectlyIfShutdownInTime (line 226) | @Test
method shouldDisposeCorrectlyIfNotShutdownInTime (line 242) | @Test
method shouldDisposeCorrectlyEvenIfTimeoutAwaitTermination (line 260) | @Test
method shouldStartCorrectly (line 278) | @Test
method shouldNotStartWhenDisposed (line 297) | @Test
method shouldCreateMultiWorkers (line 308) | @Test
method shouldFailToCreateControllerDueToInvalidWorkerCount (line 315) | @Test
FILE: api/src/test/java/run/halo/app/extension/controller/DefaultDelayQueueTest.java
class DefaultDelayQueueTest (line 16) | class DefaultDelayQueueTest {
method setUp (line 24) | @BeforeEach
method addImmediatelyTest (line 29) | @Test
method addWithDelaySmallerThanMinDelay (line 42) | @Test
method addWithDelayGreaterThanMinDelay (line 55) | @Test
method shouldNotAddAfterDisposing (line 69) | @Test
method shouldNotAddRepeatedlyIfNotDone (line 80) | @Test
method shouldNotAddIfHavingEarlierEntryInQueue (line 101) | @Test
method shouldAddIfHavingLaterEntryInQueue (line 117) | @Test
method newRequest (line 133) | Request newRequest(String name) {
FILE: api/src/test/java/run/halo/app/extension/controller/DelayedEntryTest.java
class DelayedEntryTest (line 12) | class DelayedEntryTest {
method createDelayedEntry (line 16) | @Test
method compareWithGreaterDelay (line 29) | @Test
method compareWithSameDelay (line 37) | @Test
method compareWithLessDelay (line 45) | @Test
method shouldBeEqualWithNameOnly (line 53) | @Test
FILE: api/src/test/java/run/halo/app/extension/controller/ExtensionWatcherTest.java
class ExtensionWatcherTest (line 23) | @ExtendWith(MockitoExtension.class)
method getEmptyMatcher (line 38) | private DefaultExtensionMatcher getEmptyMatcher() {
method shouldAddExtensionWhenAddPredicateAlwaysTrue (line 44) | @Test
method shouldNotAddExtensionWhenAddPredicateAlwaysFalse (line 55) | @Test
method shouldNotAddExtensionWhenWatcherIsDisposed (line 67) | @Test
method shouldUpdateExtensionWhenUpdatePredicateAlwaysTrue (line 77) | @Test
method shouldUpdateExtensionWhenUpdatePredicateAlwaysFalse (line 88) | @Test
method shouldNotUpdateExtensionWhenWatcherIsDisposed (line 100) | @Test
method shouldDeleteExtensionWhenDeletePredicateAlwaysTrue (line 110) | @Test
method shouldDeleteExtensionWhenDeletePredicateAlwaysFalse (line 121) | @Test
method shouldNotDeleteExtensionWhenWatcherIsDisposed (line 133) | @Test
method shouldInvokeDisposeHookIfRegistered (line 143) | @Test
FILE: api/src/test/java/run/halo/app/extension/controller/RequestSynchronizerTest.java
class RequestSynchronizerTest (line 25) | @ExtendWith(MockitoExtension.class)
method setUp (line 36) | @BeforeEach
method shouldStartCorrectlyWhenSyncingAllOnStart (line 44) | @Test
method shouldStartCorrectlyWhenNotSyncingAllOnStart (line 58) | @Test
method shouldDisposeCorrectly (line 75) | @Test
method shouldNotStartAfterDisposing (line 88) | @Test
FILE: api/src/test/java/run/halo/app/extension/index/IndexAttributeFactoryTest.java
class IndexAttributeFactoryTest (line 20) | class IndexAttributeFactoryTest {
method shouldCreateMultiValueAttribute (line 22) | @Test
method shouldCreateSingleValueAttribute (line 38) | @Test
class FakeExtension (line 54) | @Data
FILE: api/src/test/java/run/halo/app/extension/index/IndexSpecTest.java
class IndexSpecTest (line 22) | class IndexSpecTest {
method equalsVerifier (line 24) | @Test
method equalAnotherObject (line 68) | @Test
method shouldNormalizeToSingleValueIndexSpec (line 75) | @Test
method shouldNormalizeToMultiValueIndexSpec (line 93) | @Test
class FakeExtension (line 110) | @Data
FILE: api/src/test/java/run/halo/app/extension/index/KeyComparatorTest.java
class KeyComparatorTest (line 20) | class KeyComparatorTest {
method keyComparator (line 23) | @Test
method keyComparator2 (line 40) | @Test
method complexStringTest (line 84) | @Test
method complexButSkewedStringTest (line 115) | @Test
method mixLetterCaseStringTest (line 150) | @Test
method mixLetterCaseAndNumberTest (line 163) | @Test
method sortingWithComplexStringsTest (line 219) | @Test
method sortingWithDecimalStringsTest (line 226) | @Test
method treeSetWithComparatorTest (line 235) | @Test
method testTreeMap_WithComparator (line 246) | @Test
method integerPartDifferentTest (line 257) | @Test
method integerPartDifferentWithDecimalTest (line 268) | @Test
class ComparatorCharacteristicTest (line 296) | @Nested
method reflexiveTest (line 298) | @Test
method symmetricTest (line 307) | @Test
method transitiveTest (line 317) | @Test
method consistencyTest (line 325) | @RepeatedTest(50)
method withNumbersTest (line 334) | @Test
method mixedContentTest (line 342) | @Test
method nullHandlingTest (line 350) | @Test
method lengthDifferenceTest (line 358) | @Test
method specialCharactersTest (line 365) | @Test
method emptyStringsTest (line 373) | @Test
class ComparatorEdgeTest (line 382) | @Nested
method pureNumbersTest (line 384) | @Test
method mumbersWithOverflowTest (line 400) | @Test
method decimalStringsTest (line 433) | @Test
method lettersAndNumbersTest (line 443) | @Test
method pureLettersTest (line 451) | @Test
method dateStringsTest (line 460) | @Test
method booleanStringsTest (line 489) | @Test
method complexMixedStringsTest (line 497) | @Test
FILE: api/src/test/java/run/halo/app/extension/index/MultiValueBuilderTest.java
class MultiValueBuilderTest (line 14) | class MultiValueBuilderTest {
method throwIfNoNameProvided (line 16) | @Test
method throwIfNoKeyTypeProvided (line 23) | @Test
method throwIfNoIndexFuncProvided (line 30) | @Test
method shouldBuildCorrectly (line 36) | @Test
FILE: api/src/test/java/run/halo/app/extension/index/SingleValueBuilderTest.java
class SingleValueBuilderTest (line 13) | class SingleValueBuilderTest {
method throwIfNoNameProvided (line 15) | @Test
method throwIfNoKeyTypeProvided (line 22) | @Test
method throwIfNoIndexFuncProvided (line 29) | @Test
method shouldBuildCorrectly (line 35) | @Test
FILE: api/src/test/java/run/halo/app/extension/index/UnknownKeyTest.java
class UnknownKeyTest (line 10) | class UnknownKeyTest {
method shouldEqualsWorkCorrectly (line 12) | @ParameterizedTest
method shouldCompareCorrectly (line 28) | @ParameterizedTest
FILE: api/src/test/java/run/halo/app/extension/index/query/QueriesTest.java
class QueriesTest (line 8) | class QueriesTest {
method shouldBuildAndConditionStaticMethod (line 10) | @Test
method shouldBuildOrConditionStaticMethod (line 19) | @Test
method shouldBuildNotConditionStaticMethod (line 28) | @Test
method shouldBuildBetweenCondition (line 34) | @Test
method shouldBuildEqualCondition (line 40) | @Test
method shouldBuildInCondition (line 46) | @Test
method shouldRefineInConditionWithSingleValueToEqualCondition (line 55) | @Test
method shouldBuildGreaterThanCondition (line 61) | @Test
method shouldBuildLessThanCondition (line 67) | @Test
method shouldBuildLessThanConditionExclusive (line 73) | @Test
method shouldBuildEmptyCondition (line 79) | @Test
method shouldBuildAllCondition (line 85) | @Test
method shouldBuildNotEqualCondition (line 91) | @Test
method shouldBuildNotBetweenCondition (line 97) | @Test
method shouldBuildNotInCondition (line 103) | @Test
method shouldBuildNotAllCondition (line 109) | @Test
method shouldBuildStartsWithCondition (line 115) | @Test
method shouldBuildNotStartsWithCondition (line 121) | @Test
method shouldBuildEndsWithCondition (line 127) | @Test
method shouldBuildNotEndsWithCondition (line 133) | @Test
method shouldBuildContainsCondition (line 139) | @Test
method shouldBuildNotContainsCondition (line 145) | @Test
method shouldBuildAndCondition (line 151) | @Test
method shouldBuildOrCondition (line 158) | @Test
method shouldBuildNotCondition (line 166) | @Test
method shouldBuildLabelExistsCondition (line 172) | @Test
method shouldBuildLabelNotExistsCondition (line 178) | @Test
method shouldBuildLabelEqualCondition (line 184) | @Test
method shouldBuildLabelNotEqualCondition (line 190) | @Test
method shouldBuildLabelInCondition (line 196) | @Test
method shouldBuildLabelNotInCondition (line 202) | @Test
method shouldBuildChainedConditions (line 208) | @Test
method shouldBuildComplexCondition (line 218) | @Test
FILE: api/src/test/java/run/halo/app/extension/indexer/DefaultIndexEngineTest.java
class DefaultIndexEngineTest (line 9) | class DefaultIndexEngineTest {
method priorityQueueTest (line 11) | @Test
FILE: api/src/test/java/run/halo/app/extension/indexer/LabelIndexImplTest.java
class LabelIndexImplTest (line 6) | class LabelIndexImplTest {
method stringPrefixTest (line 8) | @Test
FILE: api/src/test/java/run/halo/app/extension/router/selector/LabelSelectorTest.java
class LabelSelectorTest (line 13) | class LabelSelectorTest {
method builderTest (line 15) | @Test
FILE: api/src/test/java/run/halo/app/extension/router/selector/OperatorTest.java
class OperatorTest (line 15) | @Slf4j
method shouldConvertCorrectly (line 18) | @Test
FILE: api/src/test/java/run/halo/app/extension/router/selector/SelectorConverterTest.java
class SelectorConverterTest (line 11) | @Slf4j
method shouldConvertCorrectly (line 16) | @Test
FILE: api/src/test/java/run/halo/app/infra/utils/GenericClassUtilsTest.java
class GenericClassUtilsTest (line 9) | class GenericClassUtilsTest {
method generateConcreteClass (line 11) | @Test
FILE: api/src/test/java/run/halo/app/infra/utils/JsonUtilsTest.java
class JsonUtilsTest (line 16) | public class JsonUtilsTest {
method serializerTime (line 18) | @Test
method deserializerArrayString (line 28) | @Test
FILE: api/src/test/java/run/halo/app/infra/utils/PathUtilsTest.java
class PathUtilsTest (line 15) | class PathUtilsTest {
method combinePath (line 17) | @Test
method getCombinePathCases (line 29) | private Map<String, String> getCombinePathCases() {
method appendPathSeparatorIfMissing (line 38) | @Test
method simplifyPathPattern (line 50) | @Test
method isAbsoluteUri (line 63) | @Test
FILE: application/src/main/java/run/halo/app/Application.java
class Application (line 18) | @EnableScheduling
method main (line 24) | public static void main(String[] args) {
FILE: application/src/main/java/run/halo/app/content/AbstractContentService.java
class AbstractContentService (line 33) | @Slf4j
method getContent (line 39) | public Mono<ContentWrapper> getContent(String snapshotName, String bas...
method checkBaseSnapshot (line 61) | protected void checkBaseSnapshot(Snapshot snapshot) {
method draftContent (line 70) | protected Mono<ContentWrapper> draftContent(@Nullable String baseSnaps...
method draftContent (line 81) | protected Mono<ContentWrapper> draftContent(String baseSnapshotName, C...
method create (line 85) | private Mono<Snapshot> create(@Nullable String baseSnapshotName,
method updateContent (line 108) | protected Mono<ContentWrapper> updateContent(String baseSnapshotName,
method listSnapshotsBy (line 139) | protected Flux<Snapshot> listSnapshotsBy(Ref ref) {
method hasConflict (line 148) | boolean hasConflict(Long oldVersion, Long newVersion) {
method restoredContent (line 152) | protected Mono<ContentWrapper> restoredContent(String baseSnapshotName...
method determineRawAndContentPatch (line 158) | protected Snapshot determineRawAndContentPatch(Snapshot snapshotToUse,
method getContextUsername (line 186) | protected Mono<String> getContextUsername() {
FILE: application/src/main/java/run/halo/app/content/AbstractEventReconciler.java
class AbstractEventReconciler (line 20) | public abstract class AbstractEventReconciler<E> implements Reconciler<E...
method AbstractEventReconciler (line 29) | protected AbstractEventReconciler(String controllerName) {
method setupWith (line 35) | @Override
method start (line 47) | @Override
method stop (line 53) | @Override
method isRunning (line 59) | @Override
method getPhase (line 64) | @Override
FILE: application/src/main/java/run/halo/app/content/CategoryPostCountUpdater.java
class CategoryPostCountUpdater (line 35) | @Component
method CategoryPostCountUpdater (line 42) | public CategoryPostCountUpdater(ExtensionClient client) {
method reconcile (line 48) | @Override
class CategoryPostCountService (line 68) | static class CategoryPostCountService {
method CategoryPostCountService (line 72) | public CategoryPostCountService(ExtensionClient client) {
method recalculatePostCount (line 76) | public void recalculatePostCount(Collection<String> categoryNames) {
method recalculatePostCount (line 82) | public void recalculatePostCount(String categoryName) {
method countTotalPosts (line 93) | private int countTotalPosts(String categoryName) {
method countVisiblePosts (line 102) | private int countVisiblePosts(String categoryName) {
method basePostQuery (line 115) | private static Condition basePostQuery(String categoryName) {
method onPostUpdated (line 125) | @EventListener(PostUpdatedEvent.class)
method onPostDeleted (line 132) | @EventListener(PostDeletedEvent.class)
method calcCategoriesToUpdate (line 140) | private Set<String> calcCategoriesToUpdate(String postName) {
FILE: application/src/main/java/run/halo/app/content/CategoryService.java
type CategoryService (line 8) | public interface CategoryService {
method listChildren (line 10) | Flux<Category> listChildren(@NonNull String categoryName);
method getParentByName (line 12) | Mono<Category> getParentByName(@NonNull String categoryName);
method isCategoryHidden (line 14) | Mono<Boolean> isCategoryHidden(@NonNull String categoryName);
FILE: application/src/main/java/run/halo/app/content/ContentRequest.java
method toSnapshot (line 26) | public Snapshot toSnapshot() {
method rawPatchFrom (line 44) | public String rawPatchFrom(String originalRaw) {
method contentPatchFrom (line 49) | public String contentPatchFrom(String originalContent) {
FILE: application/src/main/java/run/halo/app/content/ContentUpdateParam.java
method from (line 11) | public static ContentUpdateParam from(Content content) {
FILE: application/src/main/java/run/halo/app/content/Contributor.java
class Contributor (line 11) | @Data
FILE: application/src/main/java/run/halo/app/content/ListedPost.java
class ListedPost (line 20) | @Data
FILE: application/src/main/java/run/halo/app/content/ListedSinglePage.java
class ListedSinglePage (line 18) | @Data
FILE: application/src/main/java/run/halo/app/content/ListedSnapshotDto.java
class ListedSnapshotDto (line 12) | @Data
class Spec (line 21) | @Data
method from (line 34) | public static ListedSnapshotDto from(Snapshot snapshot) {
FILE: application/src/main/java/run/halo/app/content/NotificationReasonConst.java
type NotificationReasonConst (line 9) | public enum NotificationReasonConst {
FILE: application/src/main/java/run/halo/app/content/PostContentServiceImpl.java
class PostContentServiceImpl (line 16) | @Component
method PostContentServiceImpl (line 20) | public PostContentServiceImpl(ReactiveExtensionClient client) {
method getHeadContent (line 25) | @Override
method getReleaseContent (line 34) | @Override
method getSpecifiedContent (line 43) | @Override
method listSnapshots (line 52) | @Override
FILE: application/src/main/java/run/halo/app/content/PostHideFromListStateUpdater.java
class PostHideFromListStateUpdater (line 23) | @Component
method PostHideFromListStateUpdater (line 30) | protected PostHideFromListStateUpdater(ReactiveExtensionClient client,
method reconcile (line 37) | @Override
method onApplicationEvent (line 54) | @EventListener(CategoryHiddenStateChangeEvent.class)
FILE: application/src/main/java/run/halo/app/content/PostQuery.java
class PostQuery (line 28) | public class PostQuery extends SortableRequest {
method PostQuery (line 32) | public PostQuery(ServerRequest request) {
method PostQuery (line 36) | public PostQuery(ServerRequest request, @Nullable String username) {
method getPublishPhase (line 41) | @Nullable
method getCategoryWithChildren (line 46) | @Nullable
method getKeyword (line 52) | @Nullable
method toListOptions (line 62) | @Override
method buildParameters (line 97) | public static void buildParameters(Builder builder) {
FILE: application/src/main/java/run/halo/app/content/PostRequest.java
method contentRequest (line 19) | public ContentRequest contentRequest() {
FILE: application/src/main/java/run/halo/app/content/PostService.java
type PostService (line 17) | public interface PostService {
method listPost (line 19) | Mono<ListResult<ListedPost>> listPost(PostQuery query);
method draftPost (line 21) | Mono<Post> draftPost(PostRequest postRequest);
method updatePost (line 23) | Mono<Post> updatePost(PostRequest postRequest);
method updateBy (line 25) | Mono<Post> updateBy(@NonNull Post post);
method getHeadContent (line 27) | Mono<ContentWrapper> getHeadContent(String postName);
method getHeadContent (line 29) | Mono<ContentWrapper> getHeadContent(Post post);
method getReleaseContent (line 31) | Mono<ContentWrapper> getReleaseContent(String postName);
method getReleaseContent (line 33) | Mono<ContentWrapper> getReleaseContent(Post post);
method getContent (line 35) | Mono<ContentWrapper> getContent(String snapshotName, String baseSnapsh...
method listSnapshots (line 37) | Flux<ListedSnapshotDto> listSnapshots(String name);
method publish (line 39) | Mono<Post> publish(Post post);
method unpublish (line 41) | Mono<Post> unpublish(Post post);
method getByUsername (line 50) | Mono<Post> getByUsername(String postName, String username);
method revertToSpecifiedSnapshot (line 52) | Mono<Post> revertToSpecifiedSnapshot(String postName, String snapshotN...
method deleteContent (line 54) | Mono<ContentWrapper> deleteContent(String postName, String snapshotName);
method recycleBy (line 56) | Mono<Post> recycleBy(String postName, String username);
method listCategories (line 58) | Flux<Category> listCategories(List<String> categories);
FILE: application/src/main/java/run/halo/app/content/PostSorter.java
type PostSorter (line 16) | public enum PostSorter {
method from (line 29) | public static Comparator<Post> from(PostSorter sorter, Boolean ascendi...
method from (line 42) | public static Comparator<Post> from(PostSorter sorter) {
method convertFrom (line 63) | static PostSorter convertFrom(String sort) {
method defaultComparator (line 72) | static Comparator<Post> defaultComparator() {
FILE: application/src/main/java/run/halo/app/content/SinglePageQuery.java
class SinglePageQuery (line 30) | public class SinglePageQuery extends SortableRequest {
method SinglePageQuery (line 32) | public SinglePageQuery(ServerRequest request) {
method toListOptions (line 36) | @Override
method getSort (line 76) | @Override
method buildParameters (line 93) | public static void buildParameters(Builder builder) {
FILE: application/src/main/java/run/halo/app/content/SinglePageRequest.java
method contentRequest (line 18) | public ContentRequest contentRequest() {
FILE: application/src/main/java/run/halo/app/content/SinglePageService.java
type SinglePageService (line 14) | public interface SinglePageService {
method getHeadContent (line 16) | Mono<ContentWrapper> getHeadContent(String singlePageName);
method getReleaseContent (line 18) | Mono<ContentWrapper> getReleaseContent(String singlePageName);
method getContent (line 20) | Mono<ContentWrapper> getContent(String snapshotName, String baseSnapsh...
method listSnapshots (line 22) | Flux<ListedSnapshotDto> listSnapshots(String pageName);
method list (line 24) | Mono<ListResult<ListedSinglePage>> list(SinglePageQuery listRequest);
method draft (line 26) | Mono<SinglePage> draft(SinglePageRequest pageRequest);
method update (line 28) | Mono<SinglePage> update(SinglePageRequest pageRequest);
method revertToSpecifiedSnapshot (line 30) | Mono<SinglePage> revertToSpecifiedSnapshot(String pageName, String sna...
method deleteContent (line 32) | Mono<ContentWrapper> deleteContent(String postName, String snapshotName);
FILE: application/src/main/java/run/halo/app/content/SnapshotService.java
type SnapshotService (line 8) | public interface SnapshotService {
method getBy (line 10) | Mono<Snapshot> getBy(String snapshotName);
method getPatchedBy (line 12) | Mono<Snapshot> getPatchedBy(String snapshotName, String baseSnapshotNa...
method patchAndCreate (line 14) | Mono<Snapshot> patchAndCreate(@NonNull Snapshot snapshot,
method patchAndUpdate (line 18) | Mono<Snapshot> patchAndUpdate(@NonNull Snapshot snapshot,
FILE: application/src/main/java/run/halo/app/content/Stats.java
class Stats (line 12) | @Data
method Stats (line 23) | public Stats() {
method Stats (line 26) | @Builder
method empty (line 34) | public static Stats empty() {
FILE: application/src/main/java/run/halo/app/content/comment/AbstractCommentService.java
class AbstractCommentService (line 21) | @RequiredArgsConstructor
method fetchCurrentUser (line 36) | protected Mono<User> fetchCurrentUser() {
method hasCommentManagePermission (line 42) | Mono<Boolean> hasCommentManagePermission() {
method toCommentOwner (line 52) | protected Comment.CommentOwner toCommentOwner(User user) {
method getOwnerInfo (line 60) | protected Mono<OwnerInfo> getOwnerInfo(Comment.CommentOwner owner) {
method fetchCommentStats (line 71) | protected Mono<CommentStats> fetchCommentStats(String commentName) {
method fetchReplyStats (line 75) | protected Mono<CommentStats> fetchReplyStats(String replyName) {
method fetchStats (line 79) | private Mono<CommentStats> fetchStats(String meterName) {
method isSafeHtml (line 95) | protected boolean isSafeHtml(@NonNull String html) {
FILE: application/src/main/java/run/halo/app/content/comment/CommentEmailOwner.java
method toCommentOwner (line 30) | public Comment.CommentOwner toCommentOwner() {
FILE: application/src/main/java/run/halo/app/content/comment/CommentNotificationReasonPublisher.java
class CommentNotificationReasonPublisher (line 45) | @Component
method onNewComment (line 61) | @Async
method onNewReply (line 75) | @Async
method isPostComment (line 84) | boolean isPostComment(Comment comment) {
method isPageComment (line 88) | boolean isPageComment(Comment comment) {
class CommentContentConverter (line 95) | @Component
method convertRelativeLinks (line 106) | public String convertRelativeLinks(String content) {
class NewCommentOnPostReasonPublisher (line 116) | @Component
method publishReasonBy (line 125) | public void publishReasonBy(Comment comment) {
method doNotEmitReason (line 160) | boolean doNotEmitReason(Comment comment, Post post) {
method isPostOwner (line 165) | boolean isPostOwner(Post post, Comment.CommentOwner commentOwner) {
class NewCommentOnPageReasonPublisher (line 184) | @Component
method publishReasonBy (line 192) | public void publishReasonBy(Comment comment) {
method doNotEmitReason (line 230) | public boolean doNotEmitReason(Comment comment, SinglePage page) {
method isPageOwner (line 235) | boolean isPageOwner(SinglePage page, Comment.CommentOwner commentOwn...
class ReasonDataConverter (line 254) | @UtilityClass
method toAttributeMap (line 256) | public static <T> Map<String, Object> toAttributeMap(T data) {
class NewReplyReasonPublisher (line 263) | @Component
method publishReasonBy (line 271) | public void publishReasonBy(Reply reply, Comment comment) {
method getCommentSubjectDisplay (line 346) | @SuppressWarnings("unchecked")
method doNotEmitReason (line 355) | boolean doNotEmitReason(Reply currentReply, Reply quoteReply, Commen...
FILE: application/src/main/java/run/halo/app/content/comment/CommentQuery.java
class CommentQuery (line 28) | public class CommentQuery extends SortableRequest {
method CommentQuery (line 30) | public CommentQuery(ServerRequest request) {
method getKeyword (line 34) | @Nullable
method getOwnerKind (line 39) | @Nullable
method getOwnerName (line 44) | @Nullable
method getSort (line 49) | @Override
method toListOptions (line 58) | @Override
method buildParameters (line 80) | public static void buildParameters(Builder builder) {
FILE: application/src/main/java/run/halo/app/content/comment/CommentRequest.java
class CommentRequest (line 18) | @Data
method toComment (line 43) | public Comment toComment() {
FILE: application/src/main/java/run/halo/app/content/comment/CommentService.java
type CommentService (line 15) | public interface CommentService {
method listComment (line 17) | Mono<ListResult<ListedComment>> listComment(CommentQuery query);
method create (line 19) | Mono<Comment> create(Comment comment);
method removeBySubject (line 21) | Mono<Void> removeBySubject(@NonNull Ref subjectRef);
FILE: application/src/main/java/run/halo/app/content/comment/CommentServiceImpl.java
class CommentServiceImpl (line 42) | @Component
method CommentServiceImpl (line 48) | public CommentServiceImpl(RoleService roleService, ReactiveExtensionCl...
method listComment (line 56) | @Override
method create (line 70) | @Override
method populateApproveState (line 123) | private Mono<Void> populateApproveState(Comment comment) {
method populateOwner (line 133) | Mono<Void> populateOwner(Comment comment) {
method removeBySubject (line 144) | @Override
method cleanupComments (line 150) | private Mono<Void> cleanupComments(Ref subjectRef, int batchSize) {
method deleteWithRetry (line 162) | private Mono<Comment> deleteWithRetry(Comment item) {
method attemptToDelete (line 168) | private Mono<Comment> attemptToDelete(String name) {
method listCommentsByRef (line 176) | Mono<ListResult<Comment>> listCommentsByRef(Ref subjectRef, PageReques...
method checkCommentOwner (line 187) | private boolean checkCommentOwner(Comment comment, Boolean onlySystemU...
method toListedComment (line 195) | private Mono<ListedComment> toListedComment(Comment comment) {
method getCommentSubject (line 208) | @SuppressWarnings("unchecked")
FILE: application/src/main/java/run/halo/app/content/comment/CommentStats.java
class CommentStats (line 12) | @Value
method empty (line 18) | public static CommentStats empty() {
FILE: application/src/main/java/run/halo/app/content/comment/ListedComment.java
class ListedComment (line 17) | @Data
FILE: application/src/main/java/run/halo/app/content/comment/ListedReply.java
class ListedReply (line 16) | @Data
FILE: application/src/main/java/run/halo/app/content/comment/OwnerInfo.java
class OwnerInfo (line 14) | @Value
method from (line 34) | public static OwnerInfo from(Comment.CommentOwner owner) {
method from (line 53) | public static OwnerInfo from(User user) {
FILE: application/src/main/java/run/halo/app/content/comment/PostCommentSubject.java
class PostCommentSubject (line 19) | @Component
method get (line 26) | @Override
method getSubjectDisplay (line 31) | @Override
method supports (line 41) | @Override
FILE: application/src/main/java/run/halo/app/content/comment/ReplyNotificationSubscriptionHelper.java
class ReplyNotificationSubscriptionHelper (line 22) | @Component
method subscribeNewReplyReasonForComment (line 35) | public void subscribeNewReplyReasonForComment(Comment comment) {
method subscribeNewReplyReasonForReply (line 44) | public void subscribeNewReplyReasonForReply(Reply reply) {
method subscribeReply (line 49) | void subscribeReply(UserIdentity identity) {
method createSubscriber (line 60) | @Nullable
method identityFrom (line 71) | public static UserIdentity identityFrom(Comment.CommentOwner owner) {
FILE: application/src/main/java/run/halo/app/content/comment/ReplyQuery.java
class ReplyQuery (line 26) | public class ReplyQuery extends SortableRequest {
method ReplyQuery (line 28) | public ReplyQuery(ServerWebExchange exchange) {
method getCommentName (line 32) | @Schema(description = "Replies filtered by commentName.")
method toListOptions (line 44) | public ListOptions toListOptions() {
method toPageRequest (line 53) | public PageRequest toPageRequest() {
method buildParameters (line 58) | public static void buildParameters(Builder builder) {
FILE: application/src/main/java/run/halo/app/content/comment/ReplyRequest.java
class ReplyRequest (line 17) | @Data
method toReply (line 41) | public Reply toReply() {
FILE: application/src/main/java/run/halo/app/content/comment/ReplyService.java
type ReplyService (line 13) | public interface ReplyService {
method create (line 15) | Mono<Reply> create(String commentName, Reply reply);
method list (line 17) | Mono<ListResult<ListedReply>> list(ReplyQuery query);
method removeAllByComment (line 19) | Mono<Void> removeAllByComment(String commentName);
FILE: application/src/main/java/run/halo/app/content/comment/ReplyServiceImpl.java
class ReplyServiceImpl (line 43) | @Service
method ReplyServiceImpl (line 49) | public ReplyServiceImpl(RoleService roleService, ReactiveExtensionClie...
method create (line 54) | @Override
method doCreateReply (line 71) | private Mono<Reply> doCreateReply(Reply prepared) {
method approveComment (line 85) | private Mono<Comment> approveComment(Comment comment) {
method doApproveComment (line 95) | private Mono<Comment> doApproveComment(Comment comment) {
method approveReply (line 106) | private Mono<Reply> approveReply(String replyName) {
method doApproveReply (line 116) | private Mono<Reply> doApproveReply(String replyName) {
method updateCommentWithRetry (line 128) | private Mono<Comment> updateCommentWithRetry(String name, UnaryOperato...
method prepareReply (line 137) | private Mono<Reply> prepareReply(Comment comment, Reply reply) {
method list (line 176) | @Override
method removeAllByComment (line 188) | @Override
method cleanupComments (line 194) | private Mono<Void> cleanupComments(String commentName, int batchSize) {
method deleteWithRetry (line 206) | private Mono<Reply> deleteWithRetry(Reply item) {
method attemptToDelete (line 212) | private Mono<Reply> attemptToDelete(String name) {
method listRepliesByComment (line 220) | Mono<ListResult<Reply>> listRepliesByComment(String commentName, PageR...
method toListedReply (line 231) | private Mono<ListedReply> toListedReply(Reply reply) {
FILE: application/src/main/java/run/halo/app/content/comment/SinglePageCommentSubject.java
class SinglePageCommentSubject (line 19) | @Component
method get (line 27) | @Override
method getSubjectDisplay (line 32) | @Override
method supports (line 42) | @Override
FILE: application/src/main/java/run/halo/app/content/impl/CategoryServiceImpl.java
class CategoryServiceImpl (line 20) | @Component
method listChildren (line 25) | @Override
method getParentByName (line 39) | @Override
method isCategoryHidden (line 54) | @Override
method defaultSort (line 62) | static Sort defaultSort() {
method isNotIndependent (line 68) | private boolean isNotIndependent(Category category) {
FILE: application/src/main/java/run/halo/app/content/impl/PostServiceImpl.java
class PostServiceImpl (line 58) | @Slf4j
method PostServiceImpl (line 66) | public PostServiceImpl(ReactiveExtensionClient client, CounterService ...
method listPost (line 75) | @Override
method buildListOptions (line 92) | Mono<ListOptions> buildListOptions(PostQuery query) {
method fetchStats (line 112) | Mono<Stats> fetchStats(Post post) {
method getListedPost (line 126) | private Mono<ListedPost> getListedPost(Post post) {
method listTags (line 158) | private Flux<Tag> listTags(List<String> tagNames) {
method listCategories (line 167) | @Override
method listContributors (line 180) | private Flux<Contributor> listContributors(List<String> usernames) {
method draftPost (line 195) | @Override
method waitForPostToDraftConcludingWork (line 224) | private Mono<Post> waitForPostToDraftConcludingWork(String postName,
method updatePost (line 249) | @Override
method updateBy (line 271) | @Override
method getHeadContent (line 276) | @Override
method getHeadContent (line 282) | @Override
method getReleaseContent (line 288) | @Override
method getReleaseContent (line 294) | @Override
method listSnapshots (line 300) | @Override
method publish (line 307) | @Override
method unpublish (line 318) | @Override
method getByUsername (line 324) | @Override
method revertToSpecifiedSnapshot (line 331) | @Override
method deleteContent (line 357) | @Override
method recycleBy (line 389) | @Override
method updatePostWithRetry (line 398) | private Mono<Post> updatePostWithRetry(Post post, UnaryOperator<Post> ...
method publishPostWithRetry (line 410) | Mono<Post> publishPostWithRetry(Post post) {
FILE: application/src/main/java/run/halo/app/content/impl/SinglePageServiceImpl.java
class SinglePageServiceImpl (line 46) | @Slf4j
method SinglePageServiceImpl (line 54) | public SinglePageServiceImpl(ReactiveExtensionClient client, CounterSe...
method getHeadContent (line 62) | @Override
method getReleaseContent (line 71) | @Override
method listSnapshots (line 80) | @Override
method list (line 87) | @Override
method draft (line 102) | @Override
method waitForPageToDraftConcludingWork (line 129) | private Mono<SinglePage> waitForPageToDraftConcludingWork(String pageN...
method update (line 155) | @Override
method revertToSpecifiedSnapshot (line 177) | @Override
method deleteContent (line 203) | @Override
method updatePageWithRetry (line 235) | private Mono<SinglePage> updatePageWithRetry(SinglePage page, UnaryOpe...
method publish (line 247) | private Mono<SinglePage> publish(SinglePage singlePage) {
method publishPageWithRetry (line 257) | Mono<SinglePage> publishPageWithRetry(SinglePage page) {
method getListedSinglePage (line 267) | private Mono<ListedSinglePage> getListedSinglePage(SinglePage singlePa...
method fetchStats (line 292) | Mono<Stats> fetchStats(SinglePage singlePage) {
method listContributors (line 306) | private Flux<Contributor> listContributors(List<String> usernames) {
FILE: application/src/main/java/run/halo/app/content/impl/SnapshotServiceImpl.java
class SnapshotServiceImpl (line 17) | @Service
method SnapshotServiceImpl (line 24) | public SnapshotServiceImpl(ReactiveExtensionClient client) {
method getBy (line 29) | @Override
method getPatchedBy (line 34) | @Override
method patchAndCreate (line 76) | @Override
method patchAndUpdate (line 85) | @Override
method patch (line 94) | private void patch(@NonNull Snapshot snapshot,
FILE: application/src/main/java/run/halo/app/content/permalinks/CategoryPermalinkPolicy.java
class CategoryPermalinkPolicy (line 24) | @Component
method permalink (line 34) | @Override
method pattern (line 46) | public String pattern() {
FILE: application/src/main/java/run/halo/app/content/permalinks/ExtensionLocator.java
method equals (line 28) | @Override
method hashCode (line 40) | @Override
FILE: application/src/main/java/run/halo/app/content/permalinks/PermalinkPolicy.java
type PermalinkPolicy (line 10) | public interface PermalinkPolicy<T extends AbstractExtension> {
method permalink (line 15) | String permalink(T extension);
FILE: application/src/main/java/run/halo/app/content/permalinks/PostPermalinkPolicy.java
class PostPermalinkPolicy (line 31) | @Component
method permalink (line 46) | @Override
method pattern (line 54) | public String pattern() {
method createPermalink (line 61) | private String createPermalink(Post post, String pattern) {
FILE: application/src/main/java/run/halo/app/content/permalinks/TagPermalinkPolicy.java
class TagPermalinkPolicy (line 23) | @Component
method permalink (line 34) | @Override
method pattern (line 47) | public String pattern() {
FILE: application/src/main/java/run/halo/app/content/stats/PostStatsUpdater.java
class PostStatsUpdater (line 22) | @Component
method PostStatsUpdater (line 32) | public PostStatsUpdater(ExtensionClient client) {
method reconcile (line 38) | @Override
method setupWith (line 48) | @Override
method start (line 59) | @Override
method stop (line 65) | @Override
method isRunning (line 71) | @Override
method getPhase (line 76) | @Override
method onReplyEvent (line 81) | @EventListener(PostStatsChangedEvent.class)
FILE: application/src/main/java/run/halo/app/content/stats/ReplyEventReconciler.java
class ReplyEventReconciler (line 41) | @Slf4j
method ReplyEventReconciler (line 51) | public ReplyEventReconciler(ExtensionClient client) {
method reconcile (line 57) | @Override
method of (line 115) | public static CommentName of(String name) {
method listOptionsWithFieldQuery (line 120) | static ListOptions listOptionsWithFieldQuery(Condition query) {
method setupWith (line 126) | @Override
method start (line 137) | @Override
method stop (line 143) | @Override
method isRunning (line 149) | @Override
method getPhase (line 154) | @Override
method onReplyEvent (line 159) | @EventListener(ReplyEvent.class)
method onUnreadReplyCountChangedEvent (line 165) | @EventListener(CommentUnreadReplyCountChangedEvent.class)
FILE: application/src/main/java/run/halo/app/content/stats/TagPostCountUpdater.java
class TagPostCountUpdater (line 36) | @Component
method TagPostCountUpdater (line 41) | public TagPostCountUpdater(ExtensionClient client) {
method reconcile (line 46) | @Override
method onPostUpdated (line 70) | @EventListener(PostEvent.class)
method calcTagsToUpdate (line 86) | private Set<String> calcTagsToUpdate(String postName) {
method updateTagRelatedPostCount (line 105) | private void updateTagRelatedPostCount(String tagName) {
FILE: application/src/main/java/run/halo/app/content/stats/VisitedEventReconciler.java
class VisitedEventReconciler (line 39) | @Slf4j
method VisitedEventReconciler (line 50) | public VisitedEventReconciler(ExtensionClient client) {
method reconcile (line 56) | @Override
method createOrUpdateVisits (line 62) | private void createOrUpdateVisits(String name, Integer visits) {
method queuedVisitBucketTask (line 78) | @Scheduled(cron = "0 0/1 * * * ?")
method setupWith (line 88) | @Override
method start (line 99) | @Override
method stop (line 105) | @Override
method isRunning (line 122) | @Override
method getPhase (line 127) | @Override
class VisitedEventListener (line 135) | @Component
method onVisited (line 140) | @Async
method mergeVisits (line 146) | private void mergeVisits(VisitedEvent event) {
method checkVisitSubject (line 163) | private boolean checkVisitSubject(GroupPluralName groupPluralName) {
FILE: application/src/main/java/run/halo/app/content/stats/VotedEventReconciler.java
class VotedEventReconciler (line 36) | @Slf4j
method VotedEventReconciler (line 45) | public VotedEventReconciler(ExtensionClient client) {
method reconcile (line 51) | @Override
method setupWith (line 77) | @Override
method start (line 88) | @Override
method stop (line 94) | @Override
method isRunning (line 100) | @Override
method getPhase (line 105) | @Override
class VotedEventListener (line 110) | @Component
method onVoted (line 118) | @Async
method checkSubject (line 129) | private boolean checkSubject(
FILE: application/src/main/java/run/halo/app/core/attachment/AttachmentChangedEvent.java
class AttachmentChangedEvent (line 12) | public class AttachmentChangedEvent extends ApplicationEvent {
method AttachmentChangedEvent (line 17) | public AttachmentChangedEvent(Object source, Attachment attachment) {
FILE: application/src/main/java/run/halo/app/core/attachment/AttachmentLister.java
type AttachmentLister (line 7) | public interface AttachmentLister {
method listBy (line 9) | Mono<ListResult<Attachment>> listBy(SearchRequest searchRequest);
FILE: application/src/main/java/run/halo/app/core/attachment/AttachmentRootGetter.java
type AttachmentRootGetter (line 9) | public interface AttachmentRootGetter extends Supplier<Path> {
FILE: application/src/main/java/run/halo/app/core/attachment/PolicyConfigChangeDetector.java
class PolicyConfigChangeDetector (line 37) | @Component
method reconcile (line 45) | @Override
method setupWith (line 66) | @Override
class AttachmentUpdateTrigger (line 82) | @Component
method AttachmentUpdateTrigger (line 92) | public AttachmentUpdateTrigger(ExtensionClient client) {
method reconcile (line 98) | @Override
method addAll (line 108) | void addAll(List<String> names) {
method setupWith (line 114) | @Override
method start (line 126) | @Override
method stop (line 132) | @Override
method isRunning (line 138) | @Override
FILE: application/src/main/java/run/halo/app/core/attachment/SearchRequest.java
class SearchRequest (line 27) | public class SearchRequest extends SortableRequest {
method SearchRequest (line 29) | public SearchRequest(ServerRequest request) {
method getKeyword (line 33) | public Optional<String> getKeyword() {
method getUngrouped (line 38) | public Optional<Boolean> getUngrouped() {
method getAccepts (line 43) | public Optional<List<String>> getAccepts() {
method toListOptions (line 51) | public ListOptions toListOptions(List<String> hiddenGroups) {
method buildParameters (line 78) | public static void buildParameters(Builder builder) {
FILE: application/src/main/java/run/halo/app/core/attachment/endpoint/AttachmentEndpoint.java
class AttachmentEndpoint (line 36) | @Slf4j
method endpoint (line 45) | @Override
method search (line 111) | Mono<ServerResponse> search(ServerRequest request) {
type IUploadRequest (line 137) | @Schema(types = "object")
method getFile (line 140) | @Schema(requiredMode = REQUIRED, description = "Attachment file")
method getPolicyName (line 143) | @Schema(requiredMode = REQUIRED, description = "Storage policy name")
method getGroupName (line 146) | @Schema(description = "The name of the group to which the attachment...
method getFile (line 153) | public FilePart getFile() {
method getPolicyName (line 160) | public String getPolicyName() {
method getGroupName (line 167) | @Override
FILE: application/src/main/java/run/halo/app/core/attachment/endpoint/LocalAttachmentUploadHandler.java
class LocalAttachmentUploadHandler (line 66) | @Slf4j
method setClock (line 84) | void setClock(Clock clock) {
method upload (line 88) | @Override
method validateFile (line 176) | private Mono<Void> validateFile(FilePart file, PolicySetting setting) {
method handleFileTypeError (line 216) | private static void handleFileTypeError(SynchronousSink<Object> sink, ...
method detectMimeType (line 224) | @NonNull
method delete (line 234) | @Override
method getPermalink (line 256) | @Override
method getSharedURL (line 264) | @Override
method getThumbnailLinks (line 272) | @Override
method doGetPermalink (line 282) | protected Optional<URI> doGetPermalink(Attachment attachment) {
method doGetThumbnailLinks (line 292) | private Map<ThumbnailSize, URI> doGetThumbnailLinks(Attachment attachm...
method deleteAttachmentFile (line 318) | private void deleteAttachmentFile(Path attachmentPath) {
method deleteThumbnails (line 329) | private void deleteThumbnails(Path attachmentPath) {
method shouldHandle (line 333) | private boolean shouldHandle(Policy policy) {
method writeContent (line 350) | private Mono<Path> writeContent(Flux<DataBuffer> content,
method getFilename (line 378) | private String getFilename(String filename, PolicySetting setting) {
class PolicySetting (line 428) | @Data
method setMaxFileSize (line 441) | public void setMaxFileSize(String maxFileSize) {
type RenameMethod (line 449) | public enum RenameMethod {
class RenameStrategy (line 455) | @Data
FILE: application/src/main/java/run/halo/app/core/attachment/endpoint/PolicyEndpoint.java
class PolicyEndpoint (line 33) | @Component
method endpoint (line 43) | @Override
method updatePolicyConfigByGroup (line 99) | private Mono<ServerResponse> updatePolicyConfigByGroup(ServerRequest s...
method getPolicyConfigByGroup (line 158) | private Mono<ServerResponse> getPolicyConfigByGroup(ServerRequest serv...
method groupVersion (line 174) | @Override
FILE: application/src/main/java/run/halo/app/core/attachment/extension/LocalThumbnail.java
class LocalThumbnail (line 17) | @Data
method setStatus (line 33) | public void setStatus(Status status) {
class Spec (line 37) | @Data
class Status (line 76) | @Data
type Phase (line 82) | public enum Phase {
method uniqueImageAndSize (line 86) | public static String uniqueImageAndSize(LocalThumbnail localThumbnail) {
method uniqueImageAndSize (line 91) | public static String uniqueImageAndSize(String imageSignature, Thumbna...
FILE: application/src/main/java/run/halo/app/core/attachment/extension/Thumbnail.java
class Thumbnail (line 13) | @Data
class Spec (line 25) | @Data
method idIndexFunc (line 42) | public static String idIndexFunc(Thumbnail thumbnail) {
method idIndexFunc (line 47) | public static String idIndexFunc(String imageHash, String size) {
FILE: application/src/main/java/run/halo/app/core/attachment/impl/AttachmentListerImpl.java
class AttachmentListerImpl (line 16) | @Component
method listBy (line 21) | @Override
FILE: application/src/main/java/run/halo/app/core/attachment/impl/AttachmentRootGetterImpl.java
class AttachmentRootGetterImpl (line 9) | @Component
method get (line 14) | @Override
FILE: application/src/main/java/run/halo/app/core/attachment/reconciler/AttachmentReconciler.java
class AttachmentReconciler (line 27) | @Slf4j
method reconcile (line 38) | @Override
method setupWith (line 87) | @Override
method cleanUpResources (line 94) | void cleanUpResources(Attachment attachment) {
FILE: application/src/main/java/run/halo/app/core/attachment/reconciler/LocalThumbnailsReconciler.java
class LocalThumbnailsReconciler (line 21) | @Slf4j
method reconcile (line 33) | @Override
method setupWith (line 53) | @Override
method cleanUpThumbnailFile (line 60) | private void cleanUpThumbnailFile(LocalThumbnail thumbnail) {
FILE: application/src/main/java/run/halo/app/core/attachment/reconciler/PolicyReconciler.java
class PolicyReconciler (line 13) | @Component
method reconcile (line 18) | @Override
method checkOwnerLabel (line 25) | private void checkOwnerLabel(Policy policy) {
method setupWith (line 36) | @Override
FILE: application/src/main/java/run/halo/app/core/attachment/reconciler/ThumbnailReconciler.java
class ThumbnailReconciler (line 12) | @Slf4j
method ThumbnailReconciler (line 19) | ThumbnailReconciler(ExtensionClient client) {
method reconcile (line 23) | @Override
method setupWith (line 36) | @Override
FILE: application/src/main/java/run/halo/app/core/attachment/thumbnail/DefaultLocalThumbnailService.java
class DefaultLocalThumbnailService (line 38) | @Slf4j
method DefaultLocalThumbnailService (line 61) | public DefaultLocalThumbnailService(AttachmentRootGetter attachmentRoo...
method setExecutorService (line 77) | void setExecutorService(ExecutorService executorService) {
method destroy (line 81) | @Override
method generate (line 86) | @Override
method delete (line 121) | @Override
method resolveThumbnailPath (line 141) | Optional<Path> resolveThumbnailPath(Path source, ThumbnailSize size) {
method generateThumbnail (line 160) | private Path generateThumbnail(Path sourcePath, Path thumbnailPath, Th...
FILE: application/src/main/java/run/halo/app/core/attachment/thumbnail/DefaultThumbnailService.java
class DefaultThumbnailService (line 35) | @Slf4j
method DefaultThumbnailService (line 47) | public DefaultThumbnailService(ReactiveExtensionClient client,
method handleAttachmentChangedEvent (line 57) | @EventListener
method updateCache (line 62) | void updateCache(Attachment attachment) {
method get (line 93) | @Override
method get (line 98) | @Override
FILE: application/src/main/java/run/halo/app/core/attachment/thumbnail/LocalThumbnailService.java
type LocalThumbnailService (line 14) | public interface LocalThumbnailService {
method generate (line 24) | Mono<Resource> generate(Path source, ThumbnailSize size);
method delete (line 31) | void delete(Path source);
FILE: application/src/main/java/run/halo/app/core/attachment/thumbnail/ThumbnailImgTagPostProcessor.java
class ThumbnailImgTagPostProcessor (line 21) | @Slf4j
method ThumbnailImgTagPostProcessor (line 36) | public ThumbnailImgTagPostProcessor(ThumbnailService thumbnailService) {
method process (line 43) | @Override
FILE: application/src/main/java/run/halo/app/core/attachment/thumbnail/ThumbnailResourceTransformer.java
class ThumbnailResourceTransformer (line 20) | @Slf4j
method ThumbnailResourceTransformer (line 25) | public ThumbnailResourceTransformer(LocalThumbnailService localThumbna...
method transform (line 29) | @Override
FILE: application/src/main/java/run/halo/app/core/attachment/thumbnail/ThumbnailService.java
type ThumbnailService (line 14) | public interface ThumbnailService {
method get (line 23) | Mono<URI> get(URI permalink, ThumbnailSize size);
method get (line 31) | Mono<Map<ThumbnailSize, URI>> get(URI permalink);
FILE: application/src/main/java/run/halo/app/core/attachment/thumbnail/ThumbnailUtils.java
type ThumbnailUtils (line 16) | public enum ThumbnailUtils {
method isSupportedImage (line 36) | public static boolean isSupportedImage(@Nullable String fileSuffix) {
method isSupportedImage (line 43) | public static boolean isSupportedImage(@Nullable MimeType mimeType) {
method buildSrcsetMap (line 54) | public static Map<ThumbnailSize, URI> buildSrcsetMap(URI permalink) {
FILE: application/src/main/java/run/halo/app/core/counter/CounterService.java
type CounterService (line 12) | public interface CounterService {
method getByName (line 14) | Mono<Counter> getByName(String counterName);
method getByNames (line 16) | Flux<Counter> getByNames(Collection<String> names);
method deleteByName (line 18) | Mono<Counter> deleteByName(String counterName);
FILE: application/src/main/java/run/halo/app/core/counter/CounterServiceImpl.java
class CounterServiceImpl (line 20) | @Service
method CounterServiceImpl (line 25) | public CounterServiceImpl(ReactiveExtensionClient client) {
method getByName (line 29) | @Override
method getByNames (line 34) | @Override
method deleteByName (line 45) | @Override
FILE: application/src/main/java/run/halo/app/core/counter/MeterUtils.java
class MeterUtils (line 17) | public class MeterUtils {
method nameOf (line 35) | public static String nameOf(String group, String plural, String name) {
method nameOf (line 42) | public static <T extends AbstractExtension> String nameOf(Class<T> cla...
method visitCounter (line 47) | public static Counter visitCounter(MeterRegistry registry, String name) {
method upvoteCounter (line 51) | public static Counter upvoteCounter(MeterRegistry registry, String nam...
method downvoteCounter (line 55) | public static Counter downvoteCounter(MeterRegistry registry, String n...
method totalCommentCounter (line 59) | public static Counter totalCommentCounter(MeterRegistry registry, Stri...
method approvedCommentCounter (line 63) | public static Counter approvedCommentCounter(MeterRegistry registry, S...
method isVisitCounter (line 67) | public static boolean isVisitCounter(Counter counter) {
method isUpvoteCounter (line 75) | public static boolean isUpvoteCounter(Counter counter) {
method isDownvoteCounter (line 83) | public static boolean isDownvoteCounter(Counter counter) {
method isTotalCommentCounter (line 91) | public static boolean isTotalCommentCounter(Counter counter) {
method isApprovedCommentCounter (line 99) | public static boolean isApprovedCommentCounter(Counter counter) {
method counter (line 114) | private static Counter counter(MeterRegistry registry, String name, Ta...
FILE: application/src/main/java/run/halo/app/core/endpoint/AttachmentHandler.java
class AttachmentHandler (line 30) | @Slf4j
method buildDoc (line 42) | public void buildDoc(Builder builder) {
method handleUpload (line 59) | public Mono<ServerResponse> handleUpload(ServerRequest serverRequest,
class UploadForm (line 120) | @Data
FILE: application/src/main/java/run/halo/app/core/endpoint/WebSocketEndpointManager.java
type WebSocketEndpointManager (line 10) | public interface WebSocketEndpointManager {
method register (line 12) | void register(Collection<WebSocketEndpoint> endpoints);
method unregister (line 14) | void unregister(Collection<WebSocketEndpoint> endpoints);
FILE: application/src/main/java/run/halo/app/core/endpoint/WebSocketHandlerMapping.java
class WebSocketHandlerMapping (line 24) | public class WebSocketHandlerMapping extends AbstractHandlerMapping
method WebSocketHandlerMapping (line 31) | public WebSocketHandlerMapping() {
method getHandlerInternal (line 36) | @Override
method register (line 93) | @Override
method unregister (line 114) | @Override
method afterPropertiesSet (line 129) | @Override
method getEndpointMap (line 137) | BiMap<PathPattern, WebSocketEndpoint> getEndpointMap() {
FILE: application/src/main/java/run/halo/app/core/endpoint/console/AttachmentConsoleEndpoint.java
class AttachmentConsoleEndpoint (line 23) | @Slf4j
method groupVersion (line 32) | @Override
method endpoint (line 37) | @Override
method handleUpload (line 55) | private Mono<ServerResponse> handleUpload(ServerRequest serverRequest) {
FILE: application/src/main/java/run/halo/app/core/endpoint/console/AuthProviderEndpoint.java
class AuthProviderEndpoint (line 25) | @Component
method endpoint (line 31) | @Override
method enableAuthProvider (line 71) | private Mono<ServerResponse> enableAuthProvider(ServerRequest request) {
method disableAuthProvider (line 77) | private Mono<ServerResponse> disableAuthProvider(ServerRequest request) {
method listAuthProviders (line 83) | Mono<ServerResponse> listAuthProviders(ServerRequest request) {
FILE: application/src/main/java/run/halo/app/core/endpoint/console/CommentEndpoint.java
class CommentEndpoint (line 38) | @Component
method CommentEndpoint (line 44) | public CommentEndpoint(CommentService commentService, ReplyService rep...
method endpoint (line 49) | @Override
method listComments (line 98) | Mono<ServerResponse> listComments(ServerRequest request) {
method createComment (line 104) | Mono<ServerResponse> createComment(ServerRequest request) {
method createReply (line 115) | Mono<ServerResponse> createReply(ServerRequest request) {
FILE: application/src/main/java/run/halo/app/core/endpoint/console/ConsoleUserEndpoint.java
class ConsoleUserEndpoint (line 30) | @Component
method ConsoleUserEndpoint (line 35) | ConsoleUserEndpoint(UserService userService) {
method endpoint (line 39) | @Override
method handleEnableUser (line 78) | private Mono<ServerResponse> handleEnableUser(ServerRequest request) {
method handleDisableUser (line 86) | private Mono<ServerResponse> handleDisableUser(ServerRequest request) {
method groupVersion (line 105) | @Override
FILE: application/src/main/java/run/halo/app/core/endpoint/console/CustomEndpointsBuilder.java
class CustomEndpointsBuilder (line 15) | public class CustomEndpointsBuilder {
method CustomEndpointsBuilder (line 19) | public CustomEndpointsBuilder() {
method add (line 23) | public CustomEndpointsBuilder add(CustomEndpoint customEndpoint) {
method build (line 30) | public RouterFunction<ServerResponse> build() {
FILE: application/src/main/java/run/halo/app/core/endpoint/console/PluginEndpoint.java
class PluginEndpoint (line 76) | @Slf4j
method PluginEndpoint (line 96) | public PluginEndpoint(ReactiveExtensionClient client,
method endpoint (line 108) | @Override
method fetchPluginJsonConfig (line 281) | private Mono<ServerResponse> fetchPluginJsonConfig(ServerRequest reque...
method updatePluginJsonConfig (line 289) | private Mono<ServerResponse> updatePluginJsonConfig(ServerRequest requ...
method changePluginRunningState (line 310) | Mono<ServerResponse> changePluginRunningState(ServerRequest request) {
method afterPropertiesSet (line 321) | @Override
class RunningStateRequest (line 331) | @Data
method fetchJsBundle (line 338) | private Mono<ServerResponse> fetchJsBundle(ServerRequest request) {
method fetchCssBundle (line 367) | private Mono<ServerResponse> fetchCssBundle(ServerRequest request) {
method buildJsBundleUri (line 396) | URI buildJsBundleUri(String type, String version) {
method upgradeFromUri (line 401) | private Mono<ServerResponse> upgradeFromUri(ServerRequest request) {
method installFromUri (line 414) | private Mono<ServerResponse> installFromUri(ServerRequest request) {
method reload (line 433) | private Mono<ServerResponse> reload(ServerRequest serverRequest) {
method fetchPluginConfig (line 438) | private Mono<ServerResponse> fetchPluginConfig(ServerRequest request) {
method fetchPluginSetting (line 446) | private Mono<ServerResponse> fetchPluginSetting(ServerRequest request) {
method updatePluginConfig (line 454) | private Mono<ServerResponse> updatePluginConfig(ServerRequest request) {
method resetSettingConfig (line 491) | private Mono<ServerResponse> resetSettingConfig(ServerRequest request) {
method updateConfigMapData (line 507) | private Mono<ConfigMap> updateConfigMapData(String configMapName, Map<...
method install (line 518) | private Mono<ServerResponse> install(ServerRequest request) {
method upgrade (line 534) | private Mono<ServerResponse> upgrade(ServerRequest request) {
method installFromFile (line 552) | private Mono<Plugin> installFromFile(FilePart filePart,
class ListRequest (line 560) | public static class ListRequest extends SortableRequest {
method ListRequest (line 562) | public ListRequest(ServerRequest request) {
method getKeyword (line 566) | @Schema(name = "keyword", description = "Keyword of plugin name or d...
method getEnabled (line 571) | @Schema(name = "enabled", description = "Whether the plugin is enabl...
method getSort (line 577) | @Override
method toListOptions (line 590) | @Override
method buildParameters (line 608) | public static void buildParameters(Builder builder) {
method list (line 626) | Mono<ServerResponse> list(ServerRequest request) {
class InstallRequest (line 637) | @Schema(name = "PluginInstallRequest", types = "object")
method InstallRequest (line 642) | public InstallRequest(MultiValueMap<String, Part> multipartData) {
method getFile (line 646) | @Schema(requiredMode = NOT_REQUIRED, description = "Plugin Jar file.")
method getPresetName (line 661) | @Schema(requiredMode = NOT_REQUIRED,
method getSource (line 679) | @Schema(requiredMode = NOT_REQUIRED, description = "Install source. ...
type InstallSource (line 694) | public enum InstallSource {
method deleteFileIfExists (line 700) | Mono<Void> deleteFileIfExists(Path path) {
method writeToTempFile (line 704) | private Mono<Path> writeToTempFile(Publisher<DataBuffer> content) {
FILE: application/src/main/java/run/halo/app/core/endpoint/console/PostEndpoint.java
class PostEndpoint (line 50) | @Slf4j
method endpoint (line 59) | @Override
method deleteContent (line 249) | private Mono<ServerResponse> deleteContent(ServerRequest request) {
method revertToSpecifiedSnapshot (line 256) | private Mono<ServerResponse> revertToSpecifiedSnapshot(ServerRequest r...
method fetchContent (line 270) | private Mono<ServerResponse> fetchContent(ServerRequest request) {
method listSnapshots (line 281) | private Mono<ServerResponse> listSnapshots(ServerRequest request) {
method fetchReleaseContent (line 287) | private Mono<ServerResponse> fetchReleaseContent(ServerRequest request) {
method fetchHeadContent (line 293) | private Mono<ServerResponse> fetchHeadContent(ServerRequest request) {
method draftPost (line 299) | Mono<ServerResponse> draftPost(ServerRequest request) {
method updateContent (line 305) | Mono<ServerResponse> updateContent(ServerRequest request) {
method updatePost (line 319) | Mono<ServerResponse> updatePost(ServerRequest request) {
method publishPost (line 325) | Mono<ServerResponse> publishPost(ServerRequest request) {
method awaitPostPublished (line 352) | private Mono<Post> awaitPostPublished(String postName) {
method unpublishPost (line 373) | private Mono<ServerResponse> unpublishPost(ServerRequest request) {
method recyclePost (line 386) | private Mono<ServerResponse> recyclePost(ServerRequest request) {
method listPost (line 399) | Mono<ServerResponse> listPost(ServerRequest request) {
method setMaxAttemptsWaitForPublish (line 408) | void setMaxAttemptsWaitForPublish(int maxAttempts) {
FILE: application/src/main/java/run/halo/app/core/endpoint/console/ReplyEndpoint.java
class ReplyEndpoint (line 24) | @Component
method ReplyEndpoint (line 29) | public ReplyEndpoint(ReplyService replyService) {
method endpoint (line 33) | @Override
method listReplies (line 50) | Mono<ServerResponse> listReplies(ServerRequest request) {
FILE: application/src/main/java/run/halo/app/core/endpoint/console/SinglePageEndpoint.java
class SinglePageEndpoint (line 46) | @Slf4j
method endpoint (line 54) | @Override
method deleteContent (line 218) | private Mono<ServerResponse> deleteContent(ServerRequest request) {
method revertToSpecifiedSnapshot (line 225) | private Mono<ServerResponse> revertToSpecifiedSnapshot(ServerRequest r...
method fetchContent (line 240) | private Mono<ServerResponse> fetchContent(ServerRequest request) {
method listSnapshots (line 250) | private Mono<ServerResponse> listSnapshots(ServerRequest request) {
method fetchReleaseContent (line 256) | private Mono<ServerResponse> fetchReleaseContent(ServerRequest request) {
method fetchHeadContent (line 262) | private Mono<ServerResponse> fetchHeadContent(ServerRequest request) {
method draftSinglePage (line 268) | Mono<ServerResponse> draftSinglePage(ServerRequest request) {
method updateContent (line 274) | Mono<ServerResponse> updateContent(ServerRequest request) {
method updateSinglePage (line 288) | Mono<ServerResponse> updateSinglePage(ServerRequest request) {
method publishSinglePage (line 294) | Mono<ServerResponse> publishSinglePage(ServerRequest request) {
method listSinglePage (line 339) | Mono<ServerResponse> listSinglePage(ServerRequest request) {
FILE: application/src/main/java/run/halo/app/core/endpoint/console/StatsEndpoint.java
class StatsEndpoint (line 29) | @Component
method StatsEndpoint (line 34) | public StatsEndpoint(ReactiveExtensionClient client) {
method endpoint (line 38) | @Override
method getStats (line 52) | Mono<ServerResponse> getStats(ServerRequest request) {
class DashboardStats (line 103) | @Data
method emptyStats (line 117) | public static DashboardStats emptyStats() {
FILE: application/src/main/java/run/halo/app/core/endpoint/console/SystemConfigEndpoint.java
class SystemConfigEndpoint (line 29) | @Component
method endpoint (line 35) | @Override
method updateConfigByGroup (line 74) | private Mono<ServerResponse> updateConfigByGroup(ServerRequest request) {
method getConfigByGroup (line 91) | private Mono<ServerResponse> getConfigByGroup(ServerRequest request) {
method groupVersion (line 98) | @Override
FILE: application/src/main/java/run/halo/app/core/endpoint/console/TagEndpoint.java
class TagEndpoint (line 35) | @Slf4j
method endpoint (line 42) | @Override
method listTag (line 60) | Mono<ServerResponse> listTag(ServerRequest request) {
class TagQuery (line 68) | public static class TagQuery extends SortableRequest {
method TagQuery (line 70) | public TagQuery(ServerRequest request) {
method getKeyword (line 74) | public Optional<String> getKeyword() {
method toListOptions (line 79) | @Override
method buildParameters (line 91) | public static void buildParameters(Builder builder) {
FILE: application/src/main/java/run/halo/app/core/endpoint/console/TrackerEndpoint.java
class TrackerEndpoint (line 31) | @AllArgsConstructor
method endpoint (line 37) | @Override
method increaseVisit (line 86) | private Mono<ServerResponse> increaseVisit(ServerRequest request) {
method upvote (line 97) | private Mono<ServerResponse> upvote(ServerRequest request) {
method downvote (line 108) | private Mono<ServerResponse> downvote(ServerRequest request) {
method groupVersion (line 135) | @Override
FILE: application/src/main/java/run/halo/app/core/endpoint/console/UserEndpoint.java
class UserEndpoint (line 97) | @Component
method endpoint (line 114) | @Override
method verifyEmail (line 258) | private Mono<ServerResponse> verifyEmail(ServerRequest request) {
method doVerifyCode (line 267) | private Mono<Void> doVerifyCode(VerifyCodeRequest verifyCodeRequest) {
method verifyPasswordAndCode (line 274) | private Mono<Void> verifyPasswordAndCode(String username, VerifyCodeRe...
method verifyEmailCode (line 282) | private Mono<Void> verifyEmailCode(String username, String code) {
method sendEmailVerificationCode (line 301) | private Mono<ServerResponse> sendEmailVerificationCode(ServerRequest r...
method verificationEmailRateLimiter (line 328) | <T> RateLimiterOperator<T> verificationEmailRateLimiter(String usernam...
method sendEmailVerificationCodeRateLimiter (line 335) | <T> RateLimiterOperator<T> sendEmailVerificationCodeRateLimiter(String...
method deleteUserAvatar (line 342) | private Mono<ServerResponse> deleteUserAvatar(ServerRequest request) {
method getUserOrSelf (line 354) | private Mono<User> getUserOrSelf(String name) {
method uploadUserAvatar (line 362) | private Mono<ServerResponse> uploadUserAvatar(ServerRequest request) {
type IAvatarUploadRequest (line 380) | @Schema(types = "object")
method getFile (line 382) | @Schema(requiredMode = REQUIRED, description = "Avatar file")
method getFile (line 387) | public FilePart getFile() {
method uploadAvatar (line 404) | private Mono<Attachment> uploadAvatar(AvatarUploadRequest uploadReques...
method maxSizeCheck (line 429) | private Flux<DataBuffer> maxSizeCheck(Flux<DataBuffer> content) {
method createUser (line 440) | private Mono<ServerResponse> createUser(ServerRequest request) {
method getUserByName (line 462) | private Mono<ServerResponse> getUserByName(ServerRequest request) {
method from (line 492) | public static User from(CreateUserRequest userRequest) {
method updateProfile (line 512) | private Mono<ServerResponse> updateProfile(ServerRequest request) {
method getAuthenticatedUserName (line 567) | private static Mono<String> getAuthenticatedUserName() {
method changeAnyonePasswordForAdmin (line 573) | Mono<ServerResponse> changeAnyonePasswordForAdmin(ServerRequest reques...
method changeOwnPassword (line 591) | Mono<ServerResponse> changeOwnPassword(ServerRequest request) {
method me (line 639) | @NonNull
method grantPermission (line 660) | @NonNull
method getUserPermission (line 673) | @NonNull
method uiPermissions (line 701) | private List<String> uiPermissions(Collection<Role> roles) {
class UserPermission (line 716) | @Data
class ListRequest (line 729) | public static class ListRequest extends SortableRequest {
method ListRequest (line 731) | public ListRequest(ServerRequest request) {
method getKeyword (line 735) | @Schema(name = "keyword")
method getRole (line 740) | @Schema(name = "role")
method toListOptions (line 748) | public ListOptions toListOptions() {
method buildParameters (line 769) | public static void buildParameters(Builder builder) {
method list (line 791) | Mono<ServerResponse> list(ServerRequest request) {
method toListedUser (line 803) | private Mono<ListResult<ListedUser>> toListedUser(ListResult<User> lis...
method convertFrom (line 832) | <T> ListResult<T> convertFrom(ListResult<?> listResult, List<T> items) {
method isDisplayNameAllowed (line 839) | private boolean isDisplayNameAllowed(SystemSetting.User setting, Strin...
FILE: application/src/main/java/run/halo/app/core/endpoint/theme/CategoryQueryEndpoint.java
class CategoryQueryEndpoint (line 35) | @Component
method endpoint (line 42) | @Override
method listPostsByCategoryName (line 91) | private Mono<ServerResponse> listPostsByCategoryName(ServerRequest req...
method getByName (line 105) | private Mono<ServerResponse> getByName(ServerRequest request) {
method listCategories (line 115) | private Mono<ServerResponse> listCategories(ServerRequest request) {
class CategoryPublicQuery (line 125) | public static class CategoryPublicQuery extends SortableRequest {
method CategoryPublicQuery (line 126) | public CategoryPublicQuery(ServerWebExchange exchange) {
method buildParameters (line 130) | public static void buildParameters(Builder builder) {
method groupVersion (line 135) | @Override
FILE: application/src/main/java/run/halo/app/core/endpoint/theme/CommentFinderEndpoint.java
class CommentFinderEndpoint (line 64) | @Component
method endpoint (line 74) | @Override
method groupVersion (line 147) | @Override
method createComment (line 152) | Mono<ServerResponse> createComment(ServerRequest request) {
method createIpBasedRateLimiter (line 165) | private <T> RateLimiterOperator<T> createIpBasedRateLimiter(ServerRequ...
method createReply (line 172) | Mono<ServerResponse> createReply(ServerRequest request) {
method checkReplyOwner (line 207) | private boolean checkReplyOwner(Reply reply, Boolean onlySystemUser) {
method listComments (line 215) | Mono<ServerResponse> listComments(ServerRequest request) {
method getComment (line 228) | Mono<ServerResponse> getComment(ServerRequest request) {
method listCommentReplies (line 235) | Mono<ServerResponse> listCommentReplies(ServerRequest request) {
class CommentQuery (line 244) | public static class CommentQuery extends PageableRequest {
method CommentQuery (line 248) | public CommentQuery(ServerRequest request) {
method getGroup (line 253) | @Schema(description = "The comment subject group.")
method getVersion (line 258) | @Schema(requiredMode = REQUIRED, description = "The comment subject ...
method getKind (line 268) | @Schema(requiredMode = REQUIRED, description = "The comment subject ...
method getName (line 282) | @Schema(requiredMode = REQUIRED, description = "The comment subject ...
method getWithReplies (line 291) | @Schema(description = "Whether to include replies. Default is false.",
method getReplySize (line 298) | @Schema(description = "Reply size of the comment, default is 10, onl...
method getSort (line 305) | @ArraySchema(uniqueItems = true,
method toRef (line 316) | Ref toRef() {
method toPageRequest (line 325) | public PageRequest toPageRequest() {
method emptyToNull (line 329) | String emptyToNull(String str) {
method buildParameters (line 333) | public static void buildParameters(Builder builder) {
class PageableRequest (line 377) | public static class PageableRequest extends IListRequest.QueryListRequ...
method PageableRequest (line 379) | public PageableRequest(MultiValueMap<String, String> queryParams) {
method getLabelSelector (line 383) | @Override
method getFieldSelector (line 389) | @Override
method buildParameters (line 395) | public static void buildParameters(Builder builder) {
FILE: application/src/main/java/run/halo/app/core/endpoint/theme/MenuQueryEndpoint.java
class MenuQueryEndpoint (line 30) | @Component
method endpoint (line 37) | @Override
method getByName (line 66) | private Mono<ServerResponse> getByName(ServerRequest request) {
method determineMenuName (line 75) | private Mono<String> determineMenuName(ServerRequest request) {
method groupVersion (line 88) | @Override
FILE: application/src/main/java/run/halo/app/core/endpoint/theme/PluginQueryEndpoint.java
class PluginQueryEndpoint (line 25) | @Component
method endpoint (line 31) | @Override
method availableByName (line 52) | private Mono<ServerResponse> availableByName(ServerRequest request) {
method groupVersion (line 58) | @Override
FILE: application/src/main/java/run/halo/app/core/endpoint/theme/PostPublicQuery.java
class PostPublicQuery (line 13) | public class PostPublicQuery extends SortableRequest {
method PostPublicQuery (line 15) | public PostPublicQuery(ServerWebExchange exchange) {
method buildParameters (line 19) | public static void buildParameters(Builder builder) {
FILE: application/src/main/java/run/halo/app/core/endpoint/theme/PostQueryEndpoint.java
class PostQueryEndpoint (line 32) | @Component
method endpoint (line 39) | @Override
method getPostNavigationByName (line 85) | private Mono<ServerResponse> getPostNavigationByName(ServerRequest req...
method getPostByName (line 91) | private Mono<ServerResponse> getPostByName(ServerRequest request) {
method listPosts (line 100) | private Mono<ServerResponse> listPosts(ServerRequest request) {
method groupVersion (line 108) | @Override
FILE: application/src/main/java/run/halo/app/core/endpoint/theme/PublicApiUtils.java
class PublicApiUtils (line 21) | @UtilityClass
method groupVersion (line 31) | public static GroupVersion groupVersion(Extension extension) {
method toAnotherListResult (line 46) | public static <T, R> ListResult<R> toAnotherListResult(ListResult<T> l...
method containsElement (line 63) | public static <T> boolean containsElement(@Nullable Collection<T> coll...
FILE: application/src/main/java/run/halo/app/core/endpoint/theme/SinglePageQueryEndpoint.java
class SinglePageQueryEndpoint (line 33) | @Component
method endpoint (line 41) | @Override
method getByName (line 74) | private Mono<ServerResponse> getByName(ServerRequest request) {
method listSinglePages (line 83) | private Mono<ServerResponse> listSinglePages(ServerRequest request) {
class SinglePagePublicQuery (line 89) | static class SinglePagePublicQuery extends SortableRequest {
method SinglePagePublicQuery (line 91) | public SinglePagePublicQuery(ServerWebExchange exchange) {
method buildParameters (line 95) | public static void buildParameters(Builder builder) {
method groupVersion (line 100) | @Override
FILE: application/src/main/java/run/halo/app/core/endpoint/theme/SiteStatsQueryEndpoint.java
class SiteStatsQueryEndpoint (line 24) | @Component
method endpoint (line 30) | @Override
method getStats (line 45) | private Mono<ServerResponse> getStats(ServerRequest request) {
method groupVersion (line 53) | @Override
FILE: application/src/main/java/run/halo/app/core/endpoint/theme/TagQueryEndpoint.java
class TagQueryEndpoint (line 35) | @Component
method endpoint (line 43) | @Override
method getTagByName (line 93) | private Mono<ServerResponse> getTagByName(ServerRequest request) {
method listPostsByTagName (line 102) | private Mono<ServerResponse> listPostsByTagName(ServerRequest request) {
method listTags (line 116) | private Mono<ServerResponse> listTags(ServerRequest request) {
class TagPublicQuery (line 130) | static class TagPublicQuery extends SortableRequest {
method TagPublicQuery (line 131) | public TagPublicQuery(ServerWebExchange exchange) {
method buildParameters (line 135) | public static void buildParameters(Builder builder) {
method groupVersion (line 140) | @Override
FILE: application/src/main/java/run/halo/app/core/endpoint/theme/ThumbnailEndpoint.java
class ThumbnailEndpoint (line 33) | @Component
method endpoint (line 39) | @Override
method getThumbnailByUri (line 82) | private Mono<ServerResponse> getThumbnailByUri(ServerRequest request) {
method groupVersion (line 111) | @Override
FILE: application/src/main/java/run/halo/app/core/endpoint/uc/AnnotationSettingEndpoint.java
class AnnotationSettingEndpoint (line 37) | @Component
method endpoint (line 47) | @Override
method listAvailableAnnotationSettings (line 77) | private Mono<ServerResponse> listAvailableAnnotationSettings(ServerReq...
method groupVersion (line 118) | @Override
FILE: application/src/main/java/run/halo/app/core/endpoint/uc/AttachmentUcEndpoint.java
class AttachmentUcEndpoint (line 55) | @Component
method endpoint (line 72) | @Override
method uploadAttachment (line 144) | private Mono<ServerResponse> uploadAttachment(ServerRequest request) {
method listMyAttachments (line 168) | private Mono<ServerResponse> listMyAttachments(ServerRequest request) {
class UcSearchRequest (line 180) | @Getter
method UcSearchRequest (line 184) | public UcSearchRequest(ServerRequest request, String owner) {
method toListOptions (line 190) | @Override
method uploadFromUrlForPost (line 199) | private Mono<ServerResponse> uploadFromUrlForPost(ServerRequest reques...
method createAttachmentForPost (line 224) | private Mono<ServerResponse> createAttachmentForPost(ServerRequest req...
method waitForPermalink (line 248) | private Mono<Attachment> waitForPermalink(Mono<Attachment> createdAtta...
method getPostSettingMono (line 263) | private Mono<SystemSetting.Post> getPostSettingMono() {
method linkWith (line 275) | private Consumer<Attachment> linkWith(PostAttachmentRequest request) {
method checkPostOwnership (line 291) | private Mono<Void> checkPostOwnership(Mono<PostAttachmentRequest> post...
method getCurrentUser (line 303) | private Mono<String> getCurrentUser() {
method groupVersion (line 309) | @Override
method from (line 342) | public static PostAttachmentRequest from(MultiValueMap<String, Part> m...
FILE: application/src/main/java/run/halo/app/core/endpoint/uc/UcPostEndpoint.java
class UcPostEndpoint (line 38) | @Component
method UcPostEndpoint (line 47) | public UcPostEndpoint(PostService postService, SnapshotService snapsho...
method endpoint (line 52) | @Override
method recycleMyPost (line 140) | private Mono<ServerResponse> recycleMyPost(ServerRequest request) {
method getMyPostDraft (line 147) | private Mono<ServerResponse> getMyPostDraft(ServerRequest request) {
method unpublishMyPost (line 165) | private Mono<ServerResponse> unpublishMyPost(ServerRequest request) {
method publishMyPost (line 173) | private Mono<ServerResponse> publishMyPost(ServerRequest request) {
method updateMyPostDraft (line 182) | private Mono<ServerResponse> updateMyPostDraft(ServerRequest request) {
method updateMyPost (line 255) | private Mono<ServerResponse> updateMyPost(ServerRequest request) {
method createMyPost (line 285) | private Mono<ServerResponse> createMyPost(ServerRequest request) {
method getContent (line 302) | private Content getContent(Post post) {
method listMyPost (line 312) | private Mono<ServerResponse> listMyPost(ServerRequest request) {
method getMyPost (line 319) | private Mono<ServerResponse> getMyPost(ServerRequest request) {
method getMyPost (line 325) | private Mono<Post> getMyPost(String postName) {
method getCurrentUser (line 334) | private Mono<String> getCurrentUser() {
method groupVersion (line 340) | @Override
FILE: application/src/main/java/run/halo/app/core/endpoint/uc/UcSnapshotEndpoint.java
class UcSnapshotEndpoint (line 27) | @Component
method UcSnapshotEndpoint (line 34) | public UcSnapshotEndpoint(PostService postService, SnapshotService sna...
method endpoint (line 39) | @Override
method getSnapshot (line 74) | private Mono<ServerResponse> getSnapshot(ServerRequest request) {
method getCurrentUser (line 110) | private Mono<String> getCurrentUser() {
method groupVersion (line 117) | @Override
FILE: application/src/main/java/run/halo/app/core/endpoint/uc/UcUserPreferenceEndpoint.java
class UcUserPreferenceEndpoint (line 40) | @Component
method endpoint (line 52) | @Override
method updateMyPreference (line 95) | private Mono<ServerResponse> updateMyPreference(ServerRequest serverRe...
method getMyPreference (line 133) | private Mono<ServerResponse> getMyPreference(ServerRequest serverReque...
method authenticated (line 145) | private Mono<Authentication> authenticated() {
method groupVersion (line 154) | @Override
FILE: application/src/main/java/run/halo/app/core/endpoint/uc/UserConnectionEndpoint.java
class UserConnectionEndpoint (line 27) | @Component
method UserConnectionEndpoint (line 35) | public UserConnectionEndpoint(UserConnectionService connectionService) {
method endpoint (line 39) | @Override
method groupVersion (line 70) | @Override
FILE: application/src/main/java/run/halo/app/core/reconciler/AnnotationSettingReconciler.java
class AnnotationSettingReconciler (line 21) | @Component
method reconcile (line 27) | @Override
method populateDefaultLabels (line 33) | private void populateDefaultLabels(String name) {
method setupWith (line 48) | @Override
FILE: application/src/main/java/run/halo/app/core/reconciler/AuthProviderReconciler.java
class AuthProviderReconciler (line 22) | @Component
method reconcile (line 29) | @Override
method setupWith (line 36) | @Override
method handlePrivileged (line 43) | private void handlePrivileged(AuthProvider authProvider) {
method privileged (line 50) | private boolean privileged(AuthProvider authProvider) {
FILE: application/src/main/java/run/halo/app/core/reconciler/CategoryReconciler.java
class CategoryReconciler (line 35) | @Component
method reconcile (line 47) | @Override
method checkHiddenState (line 70) | private void checkHiddenState(Category category) {
method refreshHiddenState (line 80) | private void refreshHiddenState(Category category, boolean hidden) {
method publishHiddenStateChangeEvent (line 101) | private void publishHiddenStateChangeEvent(Category category) {
method isHiddenStateChanged (line 108) | boolean isHiddenStateChanged(Category category) {
method setupWith (line 113) | @Override
method populatePermalinkPattern (line 120) | void populatePermalinkPattern(Category category) {
method populatePermalink (line 128) | void populatePermalink(Category category) {
method updateCategoryForPost (line 133) | private void updateCategoryForPost(String categoryName) {
FILE: application/src/main/java/run/halo/app/core/reconciler/CommentReconciler.java
class CommentReconciler (line 47) | @Component
method reconcile (line 59) | @Override
method setupWith (line 93) | @Override
method compatibleCreationTime (line 108) | void compatibleCreationTime(Comment comment) {
method updateUnReplyCountIfNecessary (line 117) | private void updateUnReplyCountIfNecessary(Comment comment) {
method updateSameSubjectRefCommentCounter (line 135) | private void updateSameSubjectRefCommentCounter(Comment comment) {
method countTotalComments (line 163) | int countTotalComments(Ref commentSubjectRef) {
method countApprovedComments (line 170) | int countApprovedComments(Ref commentSubjectRef) {
method getBaseQuery (line 180) | private static Condition getBaseQuery(Ref commentSubjectRef) {
method cleanUpResources (line 185) | private void cleanUpResources(Comment comment) {
FILE: application/src/main/java/run/halo/app/core/reconciler/MenuItemReconciler.java
class MenuItemReconciler (line 22) | @Slf4j
method MenuItemReconciler (line 28) | public MenuItemReconciler(ExtensionClient client) {
method reconcile (line 32) | @Override
method setupWith (line 65) | @Override
method handleCategoryRef (line 72) | private Result handleCategoryRef(String menuItemName, MenuItemStatus s...
method handleTagRef (line 84) | private Result handleTagRef(String menuItemName, MenuItemStatus status...
method handlePostRef (line 94) | private Result handlePostRef(String menuItemName, MenuItemStatus statu...
method handleSinglePageSpec (line 105) | private Result handleSinglePageSpec(String menuItemName, MenuItemStatu...
method handleMenuSpec (line 117) | private Result handleMenuSpec(String menuItemName, MenuItemStatus stat...
method updateStatus (line 126) | private void updateStatus(String menuItemName, MenuItemStatus status) {
FILE: application/src/main/java/run/halo/app/core/reconciler/PluginReconciler.java
class PluginReconciler (line 87) | @Slf4j
method destroy (line 112) | @Override
method setClock (line 123) | void setClock(Clock clock) {
method setScheduler (line 133) | void setScheduler(Scheduler scheduler) {
method reconcile (line 138) | @Override
method removeUnusedAnnotations (line 215) | private void removeUnusedAnnotations(Plugin plugin) {
method checkDependents (line 222) | private boolean checkDependents(Plugin plugin) {
method syncPluginState (line 247) | private void syncPluginState(Plugin plugin) {
method requestToUnload (line 257) | private static String requestToUnload(Plugin plugin) {
method requestToReload (line 265) | private static boolean requestToReload(Plugin plugin) {
method removeRequestToReload (line 270) | private static void removeRequestToReload(Plugin plugin) {
method cleanupResources (line 277) | private void cleanupResources(Plugin plugin) {
method enablePlugin (line 308) | private Result enablePlugin(Plugin plugin) {
method requestToReloadPluginsOptionallyDependentOn (line 412) | void requestToReloadPluginsOptionallyDependentOn(String pluginName) {
method disablePlugin (line 431) | private Result disablePlugin(Plugin plugin) {
method requestToEnable (line 483) | private static boolean requestToEnable(Plugin plugin) {
method resolveStaticResources (line 488) | private Result resolveStaticResources(Plugin plugin) {
method loadOrReload (line 545) | private Result loadOrReload(Plugin plugin) {
method createOrUpdateSetting (line 644) | private Result createOrUpdateSetting(Plugin plugin) {
method resolveLoadLocation (line 699) | private Result resolveLoadLocation(Plugin plugin) {
method setupWith (line 823) | @Override
method removeStartTaskIfPresent (line 831) | private void removeStartTaskIfPresent(String pluginName) {
method createOrUpdateReverseProxy (line 842) | private Result createOrUpdateReverseProxy(Plugin plugin) {
method isInDevEnvironment (line 870) | private boolean isInDevEnvironment() {
method buildReverseProxyName (line 874) | static String buildReverseProxyName(String pluginName) {
method requestToUnloadChildren (line 878) | private List<String> requestToUnloadChildren(String pluginName) {
method cancelUnloadRequest (line 901) | private void cancelUnloadRequest(String pluginName) {
method removeConditionBy (line 919) | private static void removeConditionBy(ConditionList conditions, String...
class ConditionType (line 923) | public static class ConditionType {
class ConditionReason (line 940) | public static class ConditionReason {
FILE: application/src/main/java/run/halo/app/core/reconciler/PostCounterReconciler.java
class PostCounterReconciler (line 18) | @Component
method reconcile (line 25) | @Override
method setupWith (line 36) | @Override
method isSameAsPost (line 47) | static boolean isSameAsPost(String name) {
FILE: application/src/main/java/run/halo/app/core/reconciler/PostReconciler.java
class PostReconciler (line 85) | @Slf4j
method reconcile (line 102) | @Override
method computeHiddenState (line 208) | private void computeHiddenState(Post post) {
method populateLabels (line 221) | private void populateLabels(Post post, Set<ApplicationEvent> events) {
method shouldUnPublish (line 250) | private static boolean shouldUnPublish(Post post) {
method setupWith (line 254) | @Override
method schedulePublishIfNecessary (line 264) | void schedulePublishIfNecessary(Post post) {
method subscribeNewCommentNotification (line 286) | void subscribeNewCommentNotification(Post post) {
method publishPost (line 297) | private void publishPost(Post post, Set<ApplicationEvent> events) {
method unPublishPost (line 346) | void unPublishPost(Post post, Set<ApplicationEvent> events) {
method cleanUpResources (line 367) | private void cleanUpResources(Post post) {
method getExcerpt (line 380) | private String getExcerpt(Post post) {
method listTagDisplayNames (line 426) | private Set<String> listTagDisplayNames(Post post) {
class DefaultExcerptGenerator (line 438) | static class DefaultExcerptGenerator implements ExcerptGenerator {
method generate (line 439) | @Override
method listSnapshots (line 447) | List<Snapshot> listSnapshots(Ref ref) {
FILE: application/src/main/java/run/halo/app/core/reconciler/ReplyReconciler.java
class ReplyReconciler (line 28) | @Component
method reconcile (line 38) | @Override
method cleanUpResourcesAndRemoveFinalizer (line 71) | private void cleanUpResourcesAndRemoveFinalizer(String replyName) {
method setupWith (line 83) | @Override
FILE: application/src/main/java/run/halo/app/core/reconciler/ReverseProxyReconciler.java
class ReverseProxyReconciler (line 22) | @Component
method ReverseProxyReconciler (line 28) | public ReverseProxyReconciler(ExtensionClient client,
method reconcile (line 34) | @Override
method setupWith (line 49) | @Override
method registerReverseProxy (line 56) | private void registerReverseProxy(ReverseProxy reverseProxy) {
method cleanUpResources (line 61) | private void cleanUpResources(ReverseProxy reverseProxy) {
method addFinalizerIfNecessary (line 66) | private void addFinalizerIfNecessary(ReverseProxy oldReverseProxy) {
method cleanUpResourcesAndRemoveFinalizer (line 83) | private void cleanUpResourcesAndRemoveFinalizer(String name) {
method isDeleted (line 93) | private boolean isDeleted(ReverseProxy reverseProxy) {
method getPluginId (line 97) | private String getPluginId(ReverseProxy reverseProxy) {
FILE: application/src/main/java/run/halo/app/core/reconciler/RoleReconciler.java
class RoleReconciler (line 22) | @Slf4j
method RoleReconciler (line 28) | public RoleReconciler(ExtensionClient client) {
method reconcile (line 32) | @Override
method setupWith (line 46) | @Override
method updateLabelsAndAnnotations (line 53) | private void updateLabelsAndAnnotations(Role role) {
FILE: application/src/main/java/run/halo/app/core/reconciler/SinglePageReconciler.java
class SinglePageReconciler (line 67) | @Slf4j
method reconcile (line 83) | @Override
method setupWith (line 107) | @Override
method subscribeNewCommentNotification (line 114) | void subscribeNewCommentNotification(SinglePage page) {
method reconcileSpec (line 125) | private void reconcileSpec(String name) {
method publishPage (line 146) | private void publishPage(String name) {
method unPublish (line 205) | private void unPublish(String name) {
method publishFailed (line 227) | private void publishFailed(String name, Throwable error) {
method cleanUpResources (line 255) | private void cleanUpResources(SinglePage singlePage) {
method cleanUpResourcesAndRemoveFinalizer (line 269) | private void cleanUpResourcesAndRemoveFinalizer(String pageName) {
method reconcileMetadata (line 279) | private void reconcileMetadata(String name) {
method createPermalink (line 303) | String createPermalink(SinglePage page) {
method reconcileStatus (line 309) | private void reconcileStatus(String name) {
method getExcerpt (line 371) | private String getExcerpt(SinglePage singlePage) {
class DefaultExcerptGenerator (line 408) | static class DefaultExce
Copy disabled (too large)
Download .json
Condensed preview — 2670 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (11,757K chars).
[
{
"path": ".dockerignore",
"chars": 15,
"preview": "ui\n.github\n.git"
},
{
"path": ".editorconfig",
"chars": 22027,
"preview": "root=true\n\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_size = 4\nindent_style = space\ninsert_final_newline = false\nmax_li"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.en.yml",
"chars": 3159,
"preview": "name: Bug Report\ndescription: File a bug report\nlabels: [bug]\nbody:\n - type: checkboxes\n id: preface\n attributes:"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.zh.yml",
"chars": 2209,
"preview": "name: Bug 反馈\ndescription: 提交 Bug 反馈\nlabels: [bug]\nbody:\n - type: checkboxes\n id: preface\n attributes:\n label"
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 255,
"preview": "blank_issues_enabled: false\ncontact_links:\n - name: 商业产品反馈\n url: https://github.com/orgs/lxware-dev/discussions\n "
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.en.yml",
"chars": 1639,
"preview": "name: Feature Request\ndescription: File a feature request\nbody:\n - type: checkboxes\n id: preface\n attributes:\n "
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.zh.yml",
"chars": 1103,
"preview": "name: 新特性建议\ndescription: 提交新特性建议\nbody:\n - type: checkboxes\n id: preface\n attributes:\n label: 前置条件\n desc"
},
{
"path": ".github/actions/docker-buildx-push/action.yaml",
"chars": 3211,
"preview": "name: \"Docker buildx and push\"\ndescription: \"Buildx and push the Docker image.\"\n\ninputs:\n ghcr-token:\n description: "
},
{
"path": ".github/actions/setup-env/action.yaml",
"chars": 905,
"preview": "name: Setup Environment\ndescription: Setup environment to check and build Halo, including console and core projects.\n\nin"
},
{
"path": ".github/pull_request_template.md",
"chars": 1998,
"preview": "<!-- Thanks for sending a pull request! Here are some tips for you:\n1. 如果这是你的第一次,请阅读我们的贡献指南:<https://github.com/halo-d"
},
{
"path": ".github/workflows/halo.yaml",
"chars": 5415,
"preview": "name: Halo Workflow\n\non:\n pull_request:\n branches:\n - main\n - release-*\n paths:\n - \"**\"\n - \"!"
},
{
"path": ".github/workflows/openapi-check.yaml",
"chars": 1469,
"preview": "name: OpenAPI Check\n\non:\n pull_request:\n branches:\n - main\n - release-*\n paths:\n - 'application/sr"
},
{
"path": ".github/workflows/packages-preview-release.yaml",
"chars": 656,
"preview": "name: \"Packages preview release\"\non:\n push:\n paths:\n - \"ui/packages/**\"\n branches:\n - main\n pull_reque"
},
{
"path": ".github/workflows/release-ui-packages.yaml",
"chars": 525,
"preview": "name: Release UI Packages\n\non:\n release:\n types:\n - published\n\npermissions:\n contents: write\n id-token: write"
},
{
"path": ".github/workflows/stale-issues.yaml",
"chars": 1092,
"preview": "name: Close Stale Issues\n\non:\n schedule:\n - cron: \"30 1 * * *\"\n workflow_dispatch:\n\npermissions:\n issues: write\n\nj"
},
{
"path": ".gitignore",
"chars": 1256,
"preview": "### Maven\ntarget/\nlogs/\n!.mvn/wrapper/maven-wrapper.jar\n\n### Gradle\n.gradle\nbuild/\nout/\n!gradle/wrapper/gradle-wrapper.j"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 5213,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participa"
},
{
"path": "CONTRIBUTING.md",
"chars": 3491,
"preview": "# Contributing Guide\n\nThank you for your interest in contributing to Halo.\n\nThis document explains the recommended workf"
},
{
"path": "Dockerfile",
"chars": 908,
"preview": "FROM eclipse-temurin:21-jre as builder\n\nWORKDIR application\nARG JAR_FILE=application/build/libs/*.jar\nCOPY ${JAR_FILE} a"
},
{
"path": "LICENSE",
"chars": 35147,
"preview": " GNU GENERAL PUBLIC LICENSE\n Version 3, 29 June 2007\n\n Copyright (C) 2007 Free "
},
{
"path": "OWNERS",
"chars": 50,
"preview": "approvers:\n- ruibaby\n- guqing\n- JohnNiang\n- LIlGG\n"
},
{
"path": "README.md",
"chars": 4083,
"preview": "<p align=\"center\">\n <a href=\"https://www.halo.run\" target=\"_blank\" rel=\"noopener noreferrer\">\n <img width=\"100"
},
{
"path": "SECURITY.md",
"chars": 1556,
"preview": "# Security Policy\n\n## Supported Versions\n\nHalo currently supports the versions listed below, where as:\n\n- :white_check_m"
},
{
"path": "api/build.gradle",
"chars": 4381,
"preview": "plugins {\n id 'checkstyle'\n id 'java-library'\n id 'halo.publish'\n id 'jacoco'\n alias(libs.plugins.lombok)"
},
{
"path": "api/src/main/java/run/halo/app/content/ContentWrapper.java",
"chars": 1641,
"preview": "package run.halo.app.content;\n\nimport lombok.Builder;\nimport lombok.Data;\nimport org.apache.commons.lang3.StringUtils;\ni"
},
{
"path": "api/src/main/java/run/halo/app/content/ExcerptGenerator.java",
"chars": 757,
"preview": "package run.halo.app.content;\n\nimport java.util.Set;\nimport lombok.Data;\nimport lombok.experimental.Accessors;\nimport or"
},
{
"path": "api/src/main/java/run/halo/app/content/PatchUtils.java",
"chars": 3227,
"preview": "package run.halo.app.content;\n\nimport com.fasterxml.jackson.core.type.TypeReference;\nimport com.github.difflib.DiffUtils"
},
{
"path": "api/src/main/java/run/halo/app/content/PostContentService.java",
"chars": 400,
"preview": "package run.halo.app.content;\n\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\npublic interface"
},
{
"path": "api/src/main/java/run/halo/app/content/comment/CommentSubject.java",
"chars": 572,
"preview": "package run.halo.app.content.comment;\n\nimport org.pf4j.ExtensionPoint;\nimport reactor.core.publisher.Mono;\nimport run.ha"
},
{
"path": "api/src/main/java/run/halo/app/core/attachment/ThumbnailProvider.java",
"chars": 1294,
"preview": "package run.halo.app.core.attachment;\n\nimport java.net.URI;\nimport java.net.URL;\nimport lombok.Builder;\nimport lombok.Da"
},
{
"path": "api/src/main/java/run/halo/app/core/attachment/ThumbnailSize.java",
"chars": 1502,
"preview": "package run.halo.app.core.attachment;\n\nimport java.util.Arrays;\nimport java.util.Optional;\nimport lombok.Getter;\n\n@Gette"
},
{
"path": "api/src/main/java/run/halo/app/core/endpoint/WebSocketEndpoint.java",
"chars": 640,
"preview": "package run.halo.app.core.endpoint;\n\nimport org.springframework.web.reactive.socket.WebSocketHandler;\nimport run.halo.ap"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/AnnotationSetting.java",
"chars": 1165,
"preview": "package run.halo.app.core.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\nim"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/AuthProvider.java",
"chars": 2655,
"preview": "package run.halo.app.core.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.NOT_REQUIRED"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/Counter.java",
"chars": 1050,
"preview": "package run.halo.app.core.extension;\n\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport run.halo.app.extension"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/Device.java",
"chars": 1824,
"preview": "package run.halo.app.core.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\n\ni"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/Menu.java",
"chars": 1188,
"preview": "package run.halo.app.core.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\n\ni"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/MenuItem.java",
"chars": 2434,
"preview": "package run.halo.app.core.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\n\ni"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/Plugin.java",
"chars": 4093,
"preview": "package run.halo.app.core.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\n\ni"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/RememberMeToken.java",
"chars": 1103,
"preview": "package run.halo.app.core.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\n\ni"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/ReverseProxy.java",
"chars": 855,
"preview": "package run.halo.app.core.extension;\n\nimport java.util.List;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/Role.java",
"chars": 6513,
"preview": "package run.halo.app.core.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\nim"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/RoleBinding.java",
"chars": 4998,
"preview": "package run.halo.app.core.extension;\n\nimport static run.halo.app.core.extension.RoleBinding.GROUP;\nimport static run.hal"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/Setting.java",
"chars": 1367,
"preview": "package run.halo.app.core.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\nim"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/Theme.java",
"chars": 3532,
"preview": "package run.halo.app.core.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.NOT_REQUIRED"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/User.java",
"chars": 2381,
"preview": "package run.halo.app.core.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\nim"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/UserConnection.java",
"chars": 1554,
"preview": "package run.halo.app.core.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\n\ni"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/attachment/Attachment.java",
"chars": 2156,
"preview": "package run.halo.app.core.extension.attachment;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.R"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/attachment/Constant.java",
"chars": 890,
"preview": "package run.halo.app.core.extension.attachment;\n\nimport run.halo.app.core.extension.attachment.endpoint.AttachmentHandle"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/attachment/Group.java",
"chars": 1345,
"preview": "package run.halo.app.core.extension.attachment;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.R"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/attachment/Policy.java",
"chars": 1260,
"preview": "package run.halo.app.core.extension.attachment;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.R"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/attachment/PolicyTemplate.java",
"chars": 951,
"preview": "package run.halo.app.core.extension.attachment;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.R"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/attachment/endpoint/AttachmentHandler.java",
"chars": 3151,
"preview": "package run.halo.app.core.extension.attachment.endpoint;\n\nimport java.net.URI;\nimport java.time.Duration;\nimport java.ut"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/attachment/endpoint/DeleteOption.java",
"chars": 349,
"preview": "package run.halo.app.core.extension.attachment.endpoint;\n\nimport run.halo.app.core.extension.attachment.Attachment;\nimpo"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/attachment/endpoint/SimpleFilePart.java",
"chars": 1180,
"preview": "package run.halo.app.core.extension.attachment.endpoint;\n\nimport java.nio.file.Path;\nimport org.springframework.core.io."
},
{
"path": "api/src/main/java/run/halo/app/core/extension/attachment/endpoint/UploadOption.java",
"chars": 1020,
"preview": "package run.halo.app.core.extension.attachment.endpoint;\n\nimport lombok.Builder;\nimport org.jspecify.annotations.Nullabl"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/content/Category.java",
"chars": 3971,
"preview": "package run.halo.app.core.extension.content;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.NOT_"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/content/Comment.java",
"chars": 4780,
"preview": "package run.halo.app.core.extension.content;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQU"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/content/Constant.java",
"chars": 523,
"preview": "package run.halo.app.core.extension.content;\n\npublic enum Constant {\n ;\n\n public static final String GROUP = \"cont"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/content/Post.java",
"chars": 7311,
"preview": "package run.halo.app.core.extension.content;\n\nimport static java.lang.Boolean.parseBoolean;\n\nimport com.fasterxml.jackso"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/content/Reply.java",
"chars": 1548,
"preview": "package run.halo.app.core.extension.content;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQU"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/content/SinglePage.java",
"chars": 3607,
"preview": "package run.halo.app.core.extension.content;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQU"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/content/Snapshot.java",
"chars": 2943,
"preview": "package run.halo.app.core.extension.content;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQU"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/content/Tag.java",
"chars": 2443,
"preview": "package run.halo.app.core.extension.content;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQU"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/endpoint/CustomEndpoint.java",
"chars": 529,
"preview": "package run.halo.app.core.extension.endpoint;\n\nimport org.springframework.web.reactive.function.server.RouterFunction;\ni"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/endpoint/SortResolver.java",
"chars": 977,
"preview": "package run.halo.app.core.extension.endpoint;\n\nimport org.springframework.core.MethodParameter;\nimport org.springframewo"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/notification/Notification.java",
"chars": 1772,
"preview": "package run.halo.app.core.extension.notification;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/notification/NotificationTemplate.java",
"chars": 1826,
"preview": "package run.halo.app.core.extension.notification;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/notification/NotifierDescriptor.java",
"chars": 1684,
"preview": "package run.halo.app.core.extension.notification;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/notification/Reason.java",
"chars": 2091,
"preview": "package run.halo.app.core.extension.notification;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/notification/ReasonType.java",
"chars": 1642,
"preview": "package run.halo.app.core.extension.notification;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/notification/Subscription.java",
"chars": 5129,
"preview": "package run.halo.app.core.extension.notification;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode"
},
{
"path": "api/src/main/java/run/halo/app/core/extension/service/AttachmentService.java",
"chars": 4034,
"preview": "package run.halo.app.core.extension.service;\n\nimport java.net.URI;\nimport java.net.URL;\nimport java.time.Duration;\nimpor"
},
{
"path": "api/src/main/java/run/halo/app/core/user/service/RoleService.java",
"chars": 1416,
"preview": "package run.halo.app.core.user.service;\n\nimport java.util.Collection;\nimport java.util.Map;\nimport java.util.Set;\nimport"
},
{
"path": "api/src/main/java/run/halo/app/core/user/service/SignUpData.java",
"chars": 2391,
"preview": "package run.halo.app.core.user.service;\n\nimport jakarta.validation.Constraint;\nimport jakarta.validation.ConstraintValid"
},
{
"path": "api/src/main/java/run/halo/app/core/user/service/UserPostCreatingHandler.java",
"chars": 499,
"preview": "package run.halo.app.core.user.service;\n\nimport org.pf4j.ExtensionPoint;\nimport reactor.core.publisher.Mono;\nimport run."
},
{
"path": "api/src/main/java/run/halo/app/core/user/service/UserPreCreatingHandler.java",
"chars": 507,
"preview": "package run.halo.app.core.user.service;\n\nimport org.pf4j.ExtensionPoint;\nimport reactor.core.publisher.Mono;\nimport run."
},
{
"path": "api/src/main/java/run/halo/app/core/user/service/UserService.java",
"chars": 1647,
"preview": "package run.halo.app.core.user.service;\n\nimport java.util.Collection;\nimport java.util.Set;\nimport reactor.core.publishe"
},
{
"path": "api/src/main/java/run/halo/app/event/post/PostDeletedEvent.java",
"chars": 496,
"preview": "package run.halo.app.event.post;\n\nimport run.halo.app.core.extension.content.Post;\nimport run.halo.app.plugin.SharedEven"
},
{
"path": "api/src/main/java/run/halo/app/event/post/PostEvent.java",
"chars": 505,
"preview": "package run.halo.app.event.post;\n\nimport org.springframework.context.ApplicationEvent;\n\n/**\n * An abstract class for pos"
},
{
"path": "api/src/main/java/run/halo/app/event/post/PostPublishedEvent.java",
"chars": 247,
"preview": "package run.halo.app.event.post;\n\nimport run.halo.app.plugin.SharedEvent;\n\n@SharedEvent\npublic class PostPublishedEvent "
},
{
"path": "api/src/main/java/run/halo/app/event/post/PostUnpublishedEvent.java",
"chars": 251,
"preview": "package run.halo.app.event.post;\n\nimport run.halo.app.plugin.SharedEvent;\n\n@SharedEvent\npublic class PostUnpublishedEven"
},
{
"path": "api/src/main/java/run/halo/app/event/post/PostUpdatedEvent.java",
"chars": 243,
"preview": "package run.halo.app.event.post;\n\nimport run.halo.app.plugin.SharedEvent;\n\n@SharedEvent\npublic class PostUpdatedEvent ex"
},
{
"path": "api/src/main/java/run/halo/app/event/post/PostVisibleChangedEvent.java",
"chars": 783,
"preview": "package run.halo.app.event.post;\n\nimport org.springframework.lang.Nullable;\nimport run.halo.app.core.extension.content.P"
},
{
"path": "api/src/main/java/run/halo/app/event/user/UserConnectionDisconnectedEvent.java",
"chars": 643,
"preview": "package run.halo.app.event.user;\n\nimport lombok.Getter;\nimport org.springframework.context.ApplicationEvent;\nimport run."
},
{
"path": "api/src/main/java/run/halo/app/event/user/UserLoginEvent.java",
"chars": 462,
"preview": "package run.halo.app.event.user;\n\nimport lombok.Getter;\nimport org.springframework.context.ApplicationEvent;\nimport run."
},
{
"path": "api/src/main/java/run/halo/app/event/user/UserLogoutEvent.java",
"chars": 465,
"preview": "package run.halo.app.event.user;\n\nimport lombok.Getter;\nimport org.springframework.context.ApplicationEvent;\nimport run."
},
{
"path": "api/src/main/java/run/halo/app/extension/AbstractExtension.java",
"chars": 722,
"preview": "package run.halo.app.extension;\n\nimport lombok.Data;\n\n/**\n * AbstractExtension contains basic structure of Extension and"
},
{
"path": "api/src/main/java/run/halo/app/extension/Comparators.java",
"chars": 1297,
"preview": "package run.halo.app.extension;\n\nimport java.time.Instant;\nimport java.util.Comparator;\n\npublic enum Comparators {\n ;"
},
{
"path": "api/src/main/java/run/halo/app/extension/ConfigMap.java",
"chars": 871,
"preview": "package run.halo.app.extension;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport lombok.Data;\nimport lombok"
},
{
"path": "api/src/main/java/run/halo/app/extension/DefaultExtensionMatcher.java",
"chars": 2039,
"preview": "package run.halo.app.extension;\n\nimport lombok.Builder;\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\nimp"
},
{
"path": "api/src/main/java/run/halo/app/extension/Extension.java",
"chars": 669,
"preview": "package run.halo.app.extension;\n\nimport java.util.Comparator;\nimport java.util.Objects;\n\n/**\n * Extension is an interfac"
},
{
"path": "api/src/main/java/run/halo/app/extension/ExtensionClient.java",
"chars": 3582,
"preview": "package run.halo.app.extension;\n\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Optional;\nimport j"
},
{
"path": "api/src/main/java/run/halo/app/extension/ExtensionMatcher.java",
"chars": 134,
"preview": "package run.halo.app.extension;\n\n@FunctionalInterface\npublic interface ExtensionMatcher {\n\n boolean match(Extension e"
},
{
"path": "api/src/main/java/run/halo/app/extension/ExtensionOperator.java",
"chars": 2322,
"preview": "package run.halo.app.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\n\nimport"
},
{
"path": "api/src/main/java/run/halo/app/extension/ExtensionUtil.java",
"chars": 2742,
"preview": "package run.halo.app.extension;\n\nimport static org.springframework.data.domain.Sort.Order.asc;\nimport static org.springf"
},
{
"path": "api/src/main/java/run/halo/app/extension/GVK.java",
"chars": 770,
"preview": "package run.halo.app.extension;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport "
},
{
"path": "api/src/main/java/run/halo/app/extension/GroupKind.java",
"chars": 254,
"preview": "package run.halo.app.extension;\n\n/**\n * GroupKind contains group and kind data only.\n *\n * @param group is group name of"
},
{
"path": "api/src/main/java/run/halo/app/extension/GroupVersion.java",
"chars": 1374,
"preview": "package run.halo.app.extension;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/"
},
{
"path": "api/src/main/java/run/halo/app/extension/GroupVersionKind.java",
"chars": 1929,
"preview": "package run.halo.app.extension;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/"
},
{
"path": "api/src/main/java/run/halo/app/extension/JsonExtension.java",
"chars": 8533,
"preview": "package run.halo.app.extension;\n\nimport com.fasterxml.jackson.core.JsonGenerator;\nimport com.fasterxml.jackson.core.Json"
},
{
"path": "api/src/main/java/run/halo/app/extension/ListOptions.java",
"chars": 5897,
"preview": "package run.halo.app.extension;\n\nimport java.util.List;\nimport java.util.function.Function;\nimport lombok.Data;\nimport l"
},
{
"path": "api/src/main/java/run/halo/app/extension/ListResult.java",
"chars": 5107,
"preview": "package run.halo.app.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\n\nimport"
},
{
"path": "api/src/main/java/run/halo/app/extension/Metadata.java",
"chars": 1089,
"preview": "package run.halo.app.extension;\n\nimport java.time.Instant;\nimport java.util.Map;\nimport java.util.Set;\nimport lombok.Dat"
},
{
"path": "api/src/main/java/run/halo/app/extension/MetadataOperator.java",
"chars": 3585,
"preview": "package run.halo.app.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\n\nimport"
},
{
"path": "api/src/main/java/run/halo/app/extension/MetadataUtil.java",
"chars": 1640,
"preview": "package run.halo.app.extension;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport org.springframework.util.Assert;"
},
{
"path": "api/src/main/java/run/halo/app/extension/PageRequest.java",
"chars": 1878,
"preview": "package run.halo.app.extension;\n\nimport org.springframework.data.domain.Sort;\nimport org.springframework.util.Assert;\n\n/"
},
{
"path": "api/src/main/java/run/halo/app/extension/PageRequestImpl.java",
"chars": 2654,
"preview": "package run.halo.app.extension;\n\nimport static org.apache.commons.lang3.ObjectUtils.defaultIfNull;\n\nimport lombok.extern"
},
{
"path": "api/src/main/java/run/halo/app/extension/ReactiveExtensionClient.java",
"chars": 3564,
"preview": "package run.halo.app.extension;\n\nimport java.util.Comparator;\nimport java.util.function.Predicate;\nimport org.springfram"
},
{
"path": "api/src/main/java/run/halo/app/extension/Ref.java",
"chars": 2420,
"preview": "package run.halo.app.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\n\nimport"
},
{
"path": "api/src/main/java/run/halo/app/extension/Scheme.java",
"chars": 3347,
"preview": "package run.halo.app.extension;\n\nimport com.fasterxml.jackson.databind.node.ObjectNode;\nimport io.swagger.v3.core.conver"
},
{
"path": "api/src/main/java/run/halo/app/extension/SchemeManager.java",
"chars": 1712,
"preview": "package run.halo.app.extension;\n\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java"
},
{
"path": "api/src/main/java/run/halo/app/extension/Secret.java",
"chars": 1978,
"preview": "package run.halo.app.extension;\n\nimport java.util.Map;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\n\n/**\n * Secr"
},
{
"path": "api/src/main/java/run/halo/app/extension/Unstructured.java",
"chars": 10861,
"preview": "package run.halo.app.extension;\n\nimport com.fasterxml.jackson.core.JsonGenerator;\nimport com.fasterxml.jackson.core.Json"
},
{
"path": "api/src/main/java/run/halo/app/extension/Watcher.java",
"chars": 2523,
"preview": "package run.halo.app.extension;\n\nimport java.util.List;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport reactor"
},
{
"path": "api/src/main/java/run/halo/app/extension/WatcherExtensionMatchers.java",
"chars": 2325,
"preview": "package run.halo.app.extension;\n\nimport java.util.Objects;\nimport lombok.Builder;\nimport lombok.Getter;\nimport org.sprin"
},
{
"path": "api/src/main/java/run/halo/app/extension/WatcherPredicates.java",
"chars": 3418,
"preview": "package run.halo.app.extension;\n\nimport java.util.function.BiPredicate;\nimport java.util.function.Predicate;\n\npublic cla"
},
{
"path": "api/src/main/java/run/halo/app/extension/controller/Controller.java",
"chars": 171,
"preview": "package run.halo.app.extension.controller;\n\nimport reactor.core.Disposable;\n\npublic interface Controller extends Disposa"
},
{
"path": "api/src/main/java/run/halo/app/extension/controller/ControllerBuilder.java",
"chars": 4334,
"preview": "package run.halo.app.extension.controller;\n\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.util.functi"
},
{
"path": "api/src/main/java/run/halo/app/extension/controller/DefaultController.java",
"chars": 10550,
"preview": "package run.halo.app.extension.controller;\n\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.util.concur"
},
{
"path": "api/src/main/java/run/halo/app/extension/controller/DefaultQueue.java",
"chars": 4578,
"preview": "package run.halo.app.extension.controller;\n\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.util.HashSe"
},
{
"path": "api/src/main/java/run/halo/app/extension/controller/ExtensionWatcher.java",
"chars": 2046,
"preview": "package run.halo.app.extension.controller;\n\nimport run.halo.app.extension.Extension;\nimport run.halo.app.extension.Watch"
},
{
"path": "api/src/main/java/run/halo/app/extension/controller/Reconciler.java",
"chars": 522,
"preview": "package run.halo.app.extension.controller;\n\nimport java.time.Duration;\n\npublic interface Reconciler<R> {\n\n Result rec"
},
{
"path": "api/src/main/java/run/halo/app/extension/controller/RequestQueue.java",
"chars": 2383,
"preview": "package run.halo.app.extension.controller;\n\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.util.Object"
},
{
"path": "api/src/main/java/run/halo/app/extension/controller/RequestSynchronizer.java",
"chars": 2728,
"preview": "package run.halo.app.extension.controller;\n\nimport static org.springframework.data.domain.Sort.Direction.ASC;\n\nimport lo"
},
{
"path": "api/src/main/java/run/halo/app/extension/controller/RequeueException.java",
"chars": 671,
"preview": "package run.halo.app.extension.controller;\n\nimport run.halo.app.extension.controller.Reconciler.Result;\n\n\n/**\n * Requeue"
},
{
"path": "api/src/main/java/run/halo/app/extension/controller/Synchronizer.java",
"chars": 153,
"preview": "package run.halo.app.extension.controller;\n\nimport reactor.core.Disposable;\n\npublic interface Synchronizer<R> extends Di"
},
{
"path": "api/src/main/java/run/halo/app/extension/exception/ExtensionException.java",
"chars": 889,
"preview": "package run.halo.app.extension.exception;\n\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.H"
},
{
"path": "api/src/main/java/run/halo/app/extension/exception/NotImplementedException.java",
"chars": 399,
"preview": "package run.halo.app.extension.exception;\n\n/**\n * Exception thrown to indicate that the requested operation is not imple"
},
{
"path": "api/src/main/java/run/halo/app/extension/exception/SchemeNotFoundException.java",
"chars": 508,
"preview": "package run.halo.app.extension.exception;\n\nimport org.springframework.http.HttpStatus;\nimport run.halo.app.extension.Gro"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/AbstractValueIndexSpecBuilder.java",
"chars": 1163,
"preview": "package run.halo.app.extension.index;\n\nimport org.springframework.util.Assert;\nimport run.halo.app.extension.Extension;\n"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/DefaultIndexAttribute.java",
"chars": 1670,
"preview": "package run.halo.app.extension.index;\n\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.function.Functi"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/IndexAttribute.java",
"chars": 1156,
"preview": "package run.halo.app.extension.index;\n\nimport java.util.Set;\nimport run.halo.app.extension.Extension;\n\n/**\n *\n * An attr"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/IndexAttributeFactory.java",
"chars": 1920,
"preview": "package run.halo.app.extension.index;\n\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.function.Functi"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/IndexSpec.java",
"chars": 2186,
"preview": "package run.halo.app.extension.index;\n\nimport com.google.common.base.Objects;\nimport java.util.Set;\nimport lombok.Data;\n"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/IndexSpecBuilder.java",
"chars": 957,
"preview": "package run.halo.app.extension.index;\n\nimport run.halo.app.extension.Extension;\n\n/**\n * Index specification builder.\n *\n"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/IndexSpecs.java",
"chars": 2181,
"preview": "package run.halo.app.extension.index;\n\nimport java.util.List;\nimport run.halo.app.extension.Extension;\n\n/**\n * An interf"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/IndexedQueryEngine.java",
"chars": 2196,
"preview": "package run.halo.app.extension.index;\n\nimport java.util.List;\nimport org.springframework.data.domain.Sort;\nimport run.ha"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/KeyComparator.java",
"chars": 5541,
"preview": "package run.halo.app.extension.index;\n\nimport java.util.Comparator;\nimport org.springframework.lang.Nullable;\n\n@Deprecat"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/MultiValueBuilder.java",
"chars": 1737,
"preview": "package run.halo.app.extension.index;\n\nimport java.util.Set;\nimport java.util.function.Function;\nimport org.springframew"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/MultiValueIndexSpec.java",
"chars": 654,
"preview": "package run.halo.app.extension.index;\n\nimport java.util.Set;\nimport org.springframework.lang.Nullable;\nimport run.halo.a"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/MultiValueIndexSpecBuilder.java",
"chars": 680,
"preview": "package run.halo.app.extension.index;\n\nimport java.util.Set;\nimport java.util.function.Function;\nimport run.halo.app.ext"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/SingleValueBuilder.java",
"chars": 1697,
"preview": "package run.halo.app.extension.index;\n\nimport java.util.function.Function;\nimport org.springframework.util.Assert;\nimpor"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/SingleValueIndexSpec.java",
"chars": 635,
"preview": "package run.halo.app.extension.index;\n\nimport org.springframework.lang.Nullable;\nimport run.halo.app.extension.Extension"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/SingleValueIndexSpecBuilder.java",
"chars": 657,
"preview": "package run.halo.app.extension.index;\n\nimport java.util.function.Function;\nimport run.halo.app.extension.Extension;\n\n/**"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/UnknownKey.java",
"chars": 943,
"preview": "package run.halo.app.extension.index;\n\nimport java.util.Objects;\nimport org.jetbrains.annotations.NotNull;\nimport org.sp"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/ValueIndexSpec.java",
"chars": 890,
"preview": "package run.halo.app.extension.index;\n\nimport run.halo.app.extension.Extension;\n\n/**\n * Specification for a value index "
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/AllCondition.java",
"chars": 347,
"preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord AllCondition(String index"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/And.java",
"chars": 610,
"preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * This condition is only fo"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/AndCondition.java",
"chars": 581,
"preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\nimport org.springframework.util.A"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/BetweenCondition.java",
"chars": 638,
"preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord BetweenCondition(\n Str"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/Condition.java",
"chars": 1174,
"preview": "package run.halo.app.extension.index.query;\n\nimport org.springframework.data.relational.core.sql.Visitable;\n\n/**\n * A co"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/EmptyCondition.java",
"chars": 227,
"preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord EmptyCondition() implemen"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/EqualCondition.java",
"chars": 528,
"preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\nimport org.springframework.util.A"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/GreaterThanCondition.java",
"chars": 464,
"preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord GreaterThanCondition(Stri"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/InCondition.java",
"chars": 699,
"preview": "package run.halo.app.extension.index.query;\n\nimport java.util.Collection;\nimport java.util.stream.Collectors;\nimport org"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/IndexCondition.java",
"chars": 308,
"preview": "package run.halo.app.extension.index.query;\n\n/**\n * Index condition interface for index-based queries.\n *\n * @author joh"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/IsNotNullCondition.java",
"chars": 368,
"preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord IsNotNullCondition(String"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/IsNullCondition.java",
"chars": 363,
"preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord IsNullCondition(String in"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/LabelCondition.java",
"chars": 390,
"preview": "package run.halo.app.extension.index.query;\n\n/**\n * Label condition interface for label-based queries.\n *\n * @author joh"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/LabelEqualsCondition.java",
"chars": 443,
"preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord LabelEqualsCondition(Stri"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/LabelExistsCondition.java",
"chars": 402,
"preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord LabelExistsCondition(Stri"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/LabelInCondition.java",
"chars": 731,
"preview": "package run.halo.app.extension.index.query;\n\nimport java.util.Collection;\nimport org.jetbrains.annotations.NotNull;\nimpo"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/LabelNotEqualsCondition.java",
"chars": 445,
"preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord LabelNotEqualsCondition(S"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/LabelNotExistsCondition.java",
"chars": 406,
"preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord LabelNotExistsCondition(S"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/LabelNotInCondition.java",
"chars": 742,
"preview": "package run.halo.app.extension.index.query;\n\nimport java.util.Collection;\nimport org.jetbrains.annotations.NotNull;\nimpo"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/LessThanCondition.java",
"chars": 464,
"preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord LessThanCondition(String "
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/NoneCondition.java",
"chars": 352,
"preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord NoneCondition(String inde"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/NotBetweenCondition.java",
"chars": 642,
"preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord NotBetweenCondition(\n "
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/NotCondition.java",
"chars": 475,
"preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\nimport org.springframework.util.A"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/NotEqualCondition.java",
"chars": 533,
"preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\nimport org.springframework.util.A"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/NotInCondition.java",
"chars": 706,
"preview": "package run.halo.app.extension.index.query;\n\nimport java.util.Collection;\nimport java.util.stream.Collectors;\nimport org"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/OrCondition.java",
"chars": 578,
"preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\nimport org.springframework.util.A"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/Queries.java",
"chars": 10252,
"preview": "package run.halo.app.extension.index.query;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Colle"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/Query.java",
"chars": 358,
"preview": "package run.halo.app.extension.index.query;\n\n/**\n * A {@link Query} is used to build queries for searching indexed objec"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/QueryFactory.java",
"chars": 6574,
"preview": "package run.halo.app.extension.index.query;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.C"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/StringContainsCondition.java",
"chars": 416,
"preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord StringContainsCondition(S"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/StringEndsWithCondition.java",
"chars": 414,
"preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord StringEndsWithCondition(S"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/StringNotContainsCondition.java",
"chars": 421,
"preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord StringNotContainsConditio"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/StringNotEndsWithCondition.java",
"chars": 418,
"preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord StringNotEndsWithConditio"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/StringNotStartsWithCondition.java",
"chars": 424,
"preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord StringNotStartsWithCondit"
},
{
"path": "api/src/main/java/run/halo/app/extension/index/query/StringStartsWithCondition.java",
"chars": 420,
"preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord StringStartsWithCondition"
},
{
"path": "api/src/main/java/run/halo/app/extension/router/IListRequest.java",
"chars": 3428,
"preview": "package run.halo.app.extension.router;\n\nimport static org.springdoc.core.fn.builders.parameter.Builder.parameterBuilder;"
},
{
"path": "api/src/main/java/run/halo/app/extension/router/QueryParamBuildUtil.java",
"chars": 979,
"preview": "package run.halo.app.extension.router;\n\nimport static org.springdoc.core.fn.builders.arrayschema.Builder.arraySchemaBuil"
},
{
"path": "api/src/main/java/run/halo/app/extension/router/SortableRequest.java",
"chars": 3585,
"preview": "package run.halo.app.extension.router;\n\nimport static run.halo.app.extension.Comparators.compareCreationTimestamp;\nimpor"
},
{
"path": "api/src/main/java/run/halo/app/extension/router/selector/FieldSelector.java",
"chars": 983,
"preview": "package run.halo.app.extension.router.selector;\n\nimport java.util.Objects;\nimport org.springframework.lang.Nullable;\nimp"
},
{
"path": "api/src/main/java/run/halo/app/extension/router/selector/FieldSelectorConverter.java",
"chars": 1652,
"preview": "package run.halo.app.extension.router.selector;\n\nimport static org.apache.commons.lang3.ObjectUtils.defaultIfNull;\n\nimpo"
},
{
"path": "api/src/main/java/run/halo/app/extension/router/selector/LabelSelector.java",
"chars": 3272,
"preview": "package run.halo.app.extension.router.selector;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.L"
},
{
"path": "api/src/main/java/run/halo/app/extension/router/selector/LabelSelectorConverter.java",
"chars": 1672,
"preview": "package run.halo.app.extension.router.selector;\n\nimport static org.apache.commons.lang3.ObjectUtils.defaultIfNull;\n\nimpo"
},
{
"path": "api/src/main/java/run/halo/app/extension/router/selector/Operator.java",
"chars": 3459,
"preview": "package run.halo.app.extension.router.selector;\n\nimport java.util.Set;\nimport org.springframework.core.convert.converter"
},
{
"path": "api/src/main/java/run/halo/app/extension/router/selector/SelectorConverter.java",
"chars": 845,
"preview": "package run.halo.app.extension.router.selector;\n\nimport java.util.Arrays;\nimport java.util.Comparator;\nimport java.util."
},
{
"path": "api/src/main/java/run/halo/app/extension/router/selector/SelectorCriteria.java",
"chars": 159,
"preview": "package run.halo.app.extension.router.selector;\n\nimport java.util.Set;\n\npublic record SelectorCriteria(String key, Opera"
},
{
"path": "api/src/main/java/run/halo/app/extension/router/selector/SelectorUtil.java",
"chars": 1927,
"preview": "package run.halo.app.extension.router.selector;\n\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Optio"
},
{
"path": "api/src/main/java/run/halo/app/infra/AnonymousUserConst.java",
"chars": 247,
"preview": "package run.halo.app.infra;\n\npublic interface AnonymousUserConst {\n String PRINCIPAL = \"anonymousUser\";\n\n String R"
},
{
"path": "api/src/main/java/run/halo/app/infra/BackupRootGetter.java",
"chars": 243,
"preview": "package run.halo.app.infra;\n\nimport java.nio.file.Path;\nimport java.util.function.Supplier;\n\n/**\n * Utility of getting b"
},
{
"path": "api/src/main/java/run/halo/app/infra/Condition.java",
"chars": 1889,
"preview": "package run.halo.app.infra;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\n\nimport io."
},
{
"path": "api/src/main/java/run/halo/app/infra/ConditionList.java",
"chars": 4457,
"preview": "package run.halo.app.infra;\n\nimport java.util.AbstractCollection;\nimport java.util.Deque;\nimport java.util.Iterator;\nimp"
},
{
"path": "api/src/main/java/run/halo/app/infra/ConditionStatus.java",
"chars": 136,
"preview": "package run.halo.app.infra;\n\n/**\n * @author guqing\n * @since 2.0.0\n */\npublic enum ConditionStatus {\n TRUE,\n FALSE"
},
{
"path": "api/src/main/java/run/halo/app/infra/ExternalLinkProcessor.java",
"chars": 1052,
"preview": "package run.halo.app.infra;\n\nimport java.net.URI;\nimport org.springframework.http.HttpRequest;\nimport reactor.core.publi"
},
{
"path": "api/src/main/java/run/halo/app/infra/ExternalUrlSupplier.java",
"chars": 1150,
"preview": "package run.halo.app.infra;\n\nimport java.net.URI;\nimport java.net.URL;\nimport java.util.function.Supplier;\nimport javax."
}
]
// ... and 2470 more files (download for full content)
About this extraction
This page contains the full source code of the halo-dev/halo GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 2670 files (10.5 MB), approximately 2.9M tokens, and a symbol index with 10096 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.