diff --git a/packages/comment-widget/src/base-form.ts b/packages/comment-widget/src/base-form.ts index 1a7ac12..c8991aa 100644 --- a/packages/comment-widget/src/base-form.ts +++ b/packages/comment-widget/src/base-form.ts @@ -6,13 +6,16 @@ import { createRef, Ref, ref } from 'lit/directives/ref.js'; import { allowAnonymousCommentsContext, baseUrlContext, + captchaEnabledContext, currentUserContext, groupContext, kindContext, nameContext, + toastContext, } from './context'; import './emoji-button'; import './icons/icon-loading'; +import { ToastManager } from './lit-toast'; import baseStyles from './styles/base'; import varStyles from './styles/var'; @@ -29,6 +32,10 @@ export class BaseForm extends LitElement { @state() allowAnonymousComments = false; + @consume({ context: captchaEnabledContext, subscribe: true }) + @state() + captchaEnabled = false; + @consume({ context: groupContext }) @state() group = ''; @@ -42,11 +49,16 @@ export class BaseForm extends LitElement { name = ''; @property({ type: String }) + @state() captcha = ''; @property({ type: Boolean }) submitting = false; + @consume({ context: toastContext, subscribe: true }) + @state() + toastManager: ToastManager | undefined; + textareaRef: Ref = createRef(); get customAccount() { @@ -61,6 +73,25 @@ export class BaseForm extends LitElement { return `/console/login?redirect_uri=${encodeURIComponent(window.location.href + parentDomId)}`; } + get showCaptcha() { + return this.captchaEnabled && !this.currentUser; + } + + async handleFetchCaptcha() { + if (!this.showCaptcha) { + return; + } + + const response = await fetch(`/apis/api.commentwidget.halo.run/v1alpha1/captcha/-/generate`); + + if (!response.ok) { + this.toastManager?.error('获取验证码失败'); + return; + } + + this.captcha = await response.text(); + } + handleOpenLoginPage() { window.location.href = this.loginUrl; } @@ -127,6 +158,7 @@ export class BaseForm extends LitElement { override connectedCallback(): void { super.connectedCallback(); this.addEventListener('keydown', this.onKeydown); + this.handleFetchCaptcha(); } override disconnectedCallback(): void { @@ -185,11 +217,16 @@ export class BaseForm extends LitElement { ` : ''}
- ${this.captcha + ${this.showCaptcha ? html`
- captcha + captcha
` : ''} diff --git a/packages/comment-widget/src/comment-form.ts b/packages/comment-widget/src/comment-form.ts index 19c79dc..197b1fd 100644 --- a/packages/comment-widget/src/comment-form.ts +++ b/packages/comment-widget/src/comment-form.ts @@ -127,7 +127,7 @@ export class CommentForm extends LitElement { return; } - this.captcha = ''; + this.baseFormRef.value?.handleFetchCaptcha(); if (!response.ok) { throw new Error('评论失败,请稍后重试'); diff --git a/packages/comment-widget/src/comment-widget.ts b/packages/comment-widget/src/comment-widget.ts index f349d94..2f92f13 100644 --- a/packages/comment-widget/src/comment-widget.ts +++ b/packages/comment-widget/src/comment-widget.ts @@ -1,11 +1,26 @@ -import { css, html, LitElement } from 'lit'; -import { property, state } from 'lit/decorators.js'; import { CommentVoList, User } from '@halo-dev/api-client'; -import { repeat } from 'lit/directives/repeat.js'; -import baseStyles from './styles/base'; import { provide } from '@lit/context'; +import { LitElement, css, html } from 'lit'; +import { property, state } from 'lit/decorators.js'; +import { repeat } from 'lit/directives/repeat.js'; import { + AllUserPolicy, + AnonymousUserPolicy, + AvatarPolicyEnum, + NoAvatarUserPolicy, + setPolicyInstance, +} from './avatar/avatar-policy'; +import { setAvatarProvider } from './avatar/providers'; +import './comment-form'; +import './comment-item'; +import './comment-pagination'; +import { + allowAnonymousCommentsContext, + avatarPolicyContext, + avatarProviderContext, + avatarProviderMirrorContext, baseUrlContext, + captchaEnabledContext, currentUserContext, emojiDataUrlContext, groupContext, @@ -13,27 +28,13 @@ import { nameContext, replySizeContext, toastContext, + useAvatarProviderContext, versionContext, withRepliesContext, - allowAnonymousCommentsContext, - useAvatarProviderContext, - avatarPolicyContext, - avatarProviderContext, - avatarProviderMirrorContext, } from './context'; -import './comment-form'; -import './comment-item'; -import './comment-pagination'; -import varStyles from './styles/var'; import { ToastManager } from './lit-toast'; -import { - AnonymousUserPolicy, - AllUserPolicy, - NoAvatarUserPolicy, - AvatarPolicyEnum, - setPolicyInstance, -} from './avatar/avatar-policy'; -import { setAvatarProvider } from './avatar/providers'; +import baseStyles from './styles/base'; +import varStyles from './styles/var'; export class CommentWidget extends LitElement { @provide({ context: baseUrlContext }) @@ -98,6 +99,10 @@ export class CommentWidget extends LitElement { @state() allowAnonymousComments = false; + @provide({ context: captchaEnabledContext }) + @property({ type: Boolean, attribute: 'enable-captcha' }) + captchaEnabled = false; + @provide({ context: toastContext }) @state() toastManager: ToastManager | undefined; diff --git a/packages/comment-widget/src/context/index.ts b/packages/comment-widget/src/context/index.ts index 5d7d01b..d35c564 100644 --- a/packages/comment-widget/src/context/index.ts +++ b/packages/comment-widget/src/context/index.ts @@ -18,6 +18,8 @@ export const allowAnonymousCommentsContext = createContext( Symbol('allowAnonymousComments') ); +export const captchaEnabledContext = createContext(Symbol('captchaEnabledContext')); + export const currentUserContext = createContext(Symbol('currentUser')); export const emojiDataUrlContext = createContext(Symbol('emojiDataUrl')); diff --git a/packages/comment-widget/src/reply-form.ts b/packages/comment-widget/src/reply-form.ts index 0ffc5c8..5c5f79a 100644 --- a/packages/comment-widget/src/reply-form.ts +++ b/packages/comment-widget/src/reply-form.ts @@ -123,7 +123,7 @@ export class ReplyForm extends LitElement { return; } - this.captcha = ''; + this.baseFormRef.value?.handleFetchCaptcha(); if (!response.ok) { throw new Error('评论失败,请稍后重试'); diff --git a/packages/widget/src/index.ts b/packages/widget/src/index.ts index 1e32d95..4aa74f8 100644 --- a/packages/widget/src/index.ts +++ b/packages/widget/src/index.ts @@ -15,6 +15,7 @@ interface Props { avatarProvider?: string; avatarProviderMirror?: string; avatarPolicy?: string; + captchaEnabled: boolean; } export function init(el: string, props: Props) { @@ -42,6 +43,7 @@ export function init(el: string, props: Props) { commentWidget.avatarProvider = props.avatarProvider || ''; commentWidget.avatarProviderMirror = props.avatarProviderMirror || ''; commentWidget.avatarPolicy = props.avatarPolicy || ''; + commentWidget.captchaEnabled = props.captchaEnabled || false; const observer = new IntersectionObserver((entries) => { entries.forEach((entry) => { diff --git a/src/main/java/run/halo/comment/widget/DefaultCommentWidget.java b/src/main/java/run/halo/comment/widget/DefaultCommentWidget.java index 13a5bc2..c30aa8d 100644 --- a/src/main/java/run/halo/comment/widget/DefaultCommentWidget.java +++ b/src/main/java/run/halo/comment/widget/DefaultCommentWidget.java @@ -84,7 +84,7 @@ private String commentHtml(IAttribute groupAttribute, IAttribute kindAttribute, .map(SettingConfigGetter.CaptchaConfig::anonymousCommentCaptcha) .blockOptional() .orElse(false); - properties.setProperty("enableCaptcha", String.valueOf(captcha)); + properties.setProperty("captchaEnabled", String.valueOf(captcha)); // placeholderHelper only support string, so we need to convert boolean to string return PROPERTY_PLACEHOLDER_HELPER.replacePlaceholders(""" @@ -104,7 +104,7 @@ private String commentHtml(IAttribute groupAttribute, IAttribute kindAttribute, avatarProvider: "${avatarProvider}", avatarProviderMirror: "${avatarProviderMirror}", avatarPolicy: "${avatarPolicy}", - enableCaptcha: ${enableCaptcha}, + captchaEnabled: ${captchaEnabled}, } ); diff --git a/src/main/resources/extensions/role-templates.yaml b/src/main/resources/extensions/role-templates.yaml index 859403a..9524cc7 100644 --- a/src/main/resources/extensions/role-templates.yaml +++ b/src/main/resources/extensions/role-templates.yaml @@ -9,6 +9,6 @@ metadata: rbac.authorization.halo.run/module: "Comment Widget" rbac.authorization.halo.run/display-name: "Comment Widget Public APIs" rules: - - apiGroups: [ "api.commentwidget.halo.run/v1alpha1" ] + - apiGroups: [ "api.commentwidget.halo.run" ] resources: [ "captcha/generate" ] verbs: [ "get" ]