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

@@ -3,6 +3,7 @@ import type {
ContentOverview,
ContentWindowHighlight,
FriendLink as UiFriendLink,
HumanVerificationMode,
Post as UiPost,
PopularPostHighlight,
SiteSettings,
@@ -36,6 +37,24 @@ function toUrlLike(value: string | URL) {
return value instanceof URL ? value : new URL(value);
}
function normalizeVerificationMode(
value: string | null | undefined,
fallback: HumanVerificationMode,
): HumanVerificationMode {
switch ((value ?? '').trim().toLowerCase()) {
case 'off':
return 'off';
case 'captcha':
case 'normal':
case 'simple':
return 'captcha';
case 'turnstile':
return 'turnstile';
default:
return fallback;
}
}
const buildTimePublicApiBaseUrl = normalizeApiBaseUrl(import.meta.env.PUBLIC_API_BASE_URL);
const buildTimeCommentTurnstileSiteKey =
import.meta.env.PUBLIC_COMMENT_TURNSTILE_SITE_KEY?.trim() ?? '';
@@ -262,7 +281,9 @@ export interface ApiSiteSettings {
}> | null;
ai_enabled: boolean;
paragraph_comments_enabled: boolean;
comment_verification_mode?: HumanVerificationMode | null;
comment_turnstile_enabled: boolean;
subscription_verification_mode?: HumanVerificationMode | null;
subscription_turnstile_enabled: boolean;
web_push_enabled: boolean;
turnstile_site_key: string | null;
@@ -452,6 +473,7 @@ export const DEFAULT_SITE_SETTINGS: SiteSettings = {
},
comments: {
paragraphsEnabled: true,
verificationMode: 'captcha',
turnstileEnabled: false,
turnstileSiteKey: undefined,
},
@@ -460,6 +482,7 @@ export const DEFAULT_SITE_SETTINGS: SiteSettings = {
popupTitle: '订阅更新',
popupDescription: '有新文章或汇总简报时,通过邮件第一时间收到提醒。需要先确认邮箱,可随时退订。',
popupDelaySeconds: 18,
verificationMode: 'off',
turnstileEnabled: false,
turnstileSiteKey: undefined,
webPushEnabled: false,
@@ -561,7 +584,17 @@ const normalizeFriendLink = (friendLink: ApiFriendLink): AppFriendLink => ({
status: friendLink.status,
});
const normalizeSiteSettings = (settings: ApiSiteSettings): SiteSettings => ({
const normalizeSiteSettings = (settings: ApiSiteSettings): SiteSettings => {
const commentVerificationMode = normalizeVerificationMode(
settings.comment_verification_mode,
settings.comment_turnstile_enabled ? 'turnstile' : 'captcha',
);
const subscriptionVerificationMode = normalizeVerificationMode(
settings.subscription_verification_mode,
settings.subscription_turnstile_enabled ? 'turnstile' : 'off',
);
return {
id: String(settings.id),
siteName: settings.site_name || DEFAULT_SITE_SETTINGS.siteName,
siteShortName: settings.site_short_name || DEFAULT_SITE_SETTINGS.siteShortName,
@@ -599,8 +632,9 @@ const normalizeSiteSettings = (settings: ApiSiteSettings): SiteSettings => ({
enabled: Boolean(settings.ai_enabled),
},
comments: {
verificationMode: commentVerificationMode,
paragraphsEnabled: settings.paragraph_comments_enabled ?? true,
turnstileEnabled: Boolean(settings.comment_turnstile_enabled),
turnstileEnabled: commentVerificationMode === 'turnstile',
turnstileSiteKey:
settings.turnstile_site_key || resolvePublicCommentTurnstileSiteKey() || undefined,
},
@@ -615,7 +649,8 @@ const normalizeSiteSettings = (settings: ApiSiteSettings): SiteSettings => ({
popupDelaySeconds:
settings.subscription_popup_delay_seconds ??
DEFAULT_SITE_SETTINGS.subscriptions.popupDelaySeconds,
turnstileEnabled: Boolean(settings.subscription_turnstile_enabled),
verificationMode: subscriptionVerificationMode,
turnstileEnabled: subscriptionVerificationMode === 'turnstile',
turnstileSiteKey:
settings.turnstile_site_key || resolvePublicCommentTurnstileSiteKey() || undefined,
webPushEnabled: Boolean(settings.web_push_enabled),
@@ -628,7 +663,8 @@ const normalizeSiteSettings = (settings: ApiSiteSettings): SiteSettings => ({
defaultOgImage: settings.seo_default_og_image ?? undefined,
defaultTwitterHandle: settings.seo_default_twitter_handle ?? undefined,
},
});
};
};
const normalizeContentOverview = (
overview: ApiHomePagePayload['content_overview'] | undefined,
@@ -937,13 +973,23 @@ class ApiClient {
});
}
async subscribe(input: { email: string; displayName?: string; source?: string }): Promise<PublicSubscriptionResponse> {
async subscribe(input: {
email: string;
displayName?: string;
source?: string;
turnstileToken?: string;
captchaToken?: string;
captchaAnswer?: string;
}): Promise<PublicSubscriptionResponse> {
return this.fetch<PublicSubscriptionResponse>('/subscriptions', {
method: 'POST',
body: JSON.stringify({
email: input.email,
displayName: input.displayName,
source: input.source,
turnstileToken: input.turnstileToken,
captchaToken: input.captchaToken,
captchaAnswer: input.captchaAnswer,
}),
});
}

View File

@@ -59,6 +59,8 @@ export interface FriendLink {
category?: string;
}
export type HumanVerificationMode = 'off' | 'captcha' | 'turnstile';
export interface SiteSettings {
id: string;
siteName: string;
@@ -85,6 +87,7 @@ export interface SiteSettings {
};
comments: {
paragraphsEnabled: boolean;
verificationMode: HumanVerificationMode;
turnstileEnabled: boolean;
turnstileSiteKey?: string;
};
@@ -93,6 +96,7 @@ export interface SiteSettings {
popupTitle: string;
popupDescription: string;
popupDelaySeconds: number;
verificationMode: HumanVerificationMode;
turnstileEnabled: boolean;
turnstileSiteKey?: string;
webPushEnabled: boolean;