feat: refresh content workflow and verification settings
All checks were successful
docker-images / build-and-push (admin, admin, termi-astro-admin, admin/Dockerfile) (push) Successful in 43s
docker-images / build-and-push (backend, backend, termi-astro-backend, backend/Dockerfile) (push) Successful in 25m9s
docker-images / build-and-push (frontend, frontend, termi-astro-frontend, frontend/Dockerfile) (push) Successful in 51s

This commit is contained in:
2026-04-01 18:47:17 +08:00
parent f2c07df320
commit 7de4ddc3ee
66 changed files with 1455 additions and 2759 deletions

View File

@@ -17,7 +17,8 @@ interface Props {
const { postSlug, class: className = '', siteSettings } = Astro.props as Props;
const { locale, t } = getI18n(Astro);
const publicApiBaseUrl = resolvePublicApiBaseUrl(Astro.url);
const turnstileSiteKey = siteSettings.comments.turnstileEnabled
const commentVerificationMode = siteSettings.comments.verificationMode;
const turnstileSiteKey = commentVerificationMode === 'turnstile'
? siteSettings.comments.turnstileSiteKey || resolvePublicCommentTurnstileSiteKey()
: '';
@@ -49,6 +50,7 @@ function formatCommentDate(dateStr: string): string {
class={`terminal-comments ${className}`}
data-post-slug={postSlug}
data-api-base={publicApiBaseUrl}
data-verification-mode={commentVerificationMode}
data-turnstile-site-key={turnstileSiteKey || undefined}
>
<div class="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
@@ -126,42 +128,44 @@ function formatCommentDate(dateStr: string): string {
</label>
</div>
<div class="rounded-2xl border border-[var(--border-color)] bg-[var(--header-bg)]/60 px-4 py-3">
<div class="flex flex-wrap items-center justify-between gap-2">
<p class="text-xs font-semibold uppercase tracking-[0.18em] text-[var(--text-tertiary)]">
{t('common.humanVerification')}
</p>
{turnstileSiteKey ? (
<span class="text-xs text-[var(--text-tertiary)]">Cloudflare Turnstile</span>
{commentVerificationMode !== 'off' && (
<div class="rounded-2xl border border-[var(--border-color)] bg-[var(--header-bg)]/60 px-4 py-3">
<div class="flex flex-wrap items-center justify-between gap-2">
<p class="text-xs font-semibold uppercase tracking-[0.18em] text-[var(--text-tertiary)]">
{t('common.humanVerification')}
</p>
{commentVerificationMode === 'turnstile' ? (
<span class="text-xs text-[var(--text-tertiary)]">Cloudflare Turnstile</span>
) : (
<button type="button" id="refresh-captcha" class="terminal-action-button px-3 py-2 text-xs">
<i class="fas fa-rotate-right"></i>
<span>{t('common.refresh')}</span>
</button>
)}
</div>
{commentVerificationMode === 'turnstile' ? (
<>
<div class="mt-3" data-turnstile-container></div>
<input type="hidden" name="turnstileToken" />
<p class="mt-3 text-sm text-[var(--text-secondary)]">{t('common.turnstileHint')}</p>
</>
) : (
<button type="button" id="refresh-captcha" class="terminal-action-button px-3 py-2 text-xs">
<i class="fas fa-rotate-right"></i>
<span>{t('common.refresh')}</span>
</button>
<>
<p id="captcha-question" class="mt-2 text-sm text-[var(--text-secondary)]">加载中...</p>
<input type="hidden" name="captchaToken" />
<input
type="text"
name="captchaAnswer"
required
inputmode="numeric"
placeholder="请输入上方答案"
class="mt-3 terminal-form-input"
/>
</>
)}
</div>
{turnstileSiteKey ? (
<>
<div class="mt-3" data-turnstile-container></div>
<input type="hidden" name="turnstileToken" />
<p class="mt-3 text-sm text-[var(--text-secondary)]">{t('common.turnstileHint')}</p>
</>
) : (
<>
<p id="captcha-question" class="mt-2 text-sm text-[var(--text-secondary)]">加载中...</p>
<input type="hidden" name="captchaToken" />
<input
type="text"
name="captchaAnswer"
required
inputmode="numeric"
placeholder="请输入上方答案"
class="mt-3 terminal-form-input"
/>
</>
)}
</div>
)}
<div id="replying-to" class="terminal-panel-muted hidden items-center justify-between gap-3 py-3">
<span class="text-sm text-[var(--text-secondary)]">
@@ -274,6 +278,9 @@ function formatCommentDate(dateStr: string): string {
const refreshCaptchaBtn = document.getElementById('refresh-captcha');
const postSlug = wrapper?.getAttribute('data-post-slug') || '';
const apiBase = wrapper?.getAttribute('data-api-base') || '/api';
const verificationMode = wrapper?.getAttribute('data-verification-mode') || 'captcha';
const useTurnstile = verificationMode === 'turnstile';
const useCaptcha = verificationMode === 'captcha';
const turnstileSiteKey = wrapper?.getAttribute('data-turnstile-site-key') || '';
const turnstileContainer = form?.querySelector('[data-turnstile-container]') as HTMLElement | null;
const turnstileTokenInput = form?.querySelector('input[name="turnstileToken"]') as HTMLInputElement | null;
@@ -390,13 +397,15 @@ function formatCommentDate(dateStr: string): string {
}
function resetHumanCheck() {
if (turnstileSiteKey) {
if (useTurnstile) {
turnstileTokenInput && (turnstileTokenInput.value = '');
turnstileWidget?.reset();
return;
}
void loadCaptcha(false);
if (useCaptcha) {
void loadCaptcha(false);
}
}
toggleBtn?.addEventListener('click', () => {
@@ -443,7 +452,7 @@ function formatCommentDate(dateStr: string): string {
const formData = new FormData(form);
const replyToId = replyingTo?.getAttribute('data-reply-to');
if (turnstileSiteKey) {
if (useTurnstile) {
const token = String(formData.get('turnstileToken') || '').trim();
if (!token) {
showMessage(t('common.turnstileRequired'), 'error');
@@ -502,9 +511,9 @@ function formatCommentDate(dateStr: string): string {
});
});
if (turnstileSiteKey) {
if (useTurnstile) {
void ensureTurnstile(false);
} else {
} else if (useCaptcha) {
void loadCaptcha(false);
}
</script>