feat: add traffic analytics configuration (Umami/GA/Custom)
Add traffic analytics support to the admin panel with three provider options: - Umami (open-source, self-hosted) — script URL + website ID - Google Analytics 4 — Measurement ID (G-XXXXXXXXXX) - Custom — any third-party analytics script (百度统计, Plausible, 51la, etc.) Changes: - admin.types.ts: Add AnalyticsEnabled, AnalyticsProvider, AnalyticsScriptUrl, AnalyticsWebsiteId, AnalyticsCustomScript to SiteConfig interface - config.ts: Add default values in getInitConfig() and configSelfCheck() - api/admin/site/route.ts: Add analytics fields to destructuring, type validation, and SiteConfig update - admin/page.tsx: Add SiteConfig interface fields, state initialization, config sync, and analytics configuration UI with provider-specific input fields - layout.tsx: Inject analytics scripts into <head> based on provider type (Umami: async script with data-website-id; GA: gtag.js + config; Custom: dangerouslySetInnerHTML)
This commit is contained in:
@@ -24,6 +24,7 @@ import { CSS } from '@dnd-kit/utilities';
|
|||||||
import {
|
import {
|
||||||
AlertCircle,
|
AlertCircle,
|
||||||
AlertTriangle,
|
AlertTriangle,
|
||||||
|
BarChart3,
|
||||||
BookMarked,
|
BookMarked,
|
||||||
BookOpen,
|
BookOpen,
|
||||||
Bot,
|
Bot,
|
||||||
@@ -406,6 +407,11 @@ interface SiteConfig {
|
|||||||
OIDCClientId?: string;
|
OIDCClientId?: string;
|
||||||
OIDCClientSecret?: string;
|
OIDCClientSecret?: string;
|
||||||
OIDCButtonText?: string;
|
OIDCButtonText?: string;
|
||||||
|
AnalyticsEnabled?: boolean;
|
||||||
|
AnalyticsProvider?: 'umami' | 'google' | 'custom';
|
||||||
|
AnalyticsScriptUrl?: string;
|
||||||
|
AnalyticsWebsiteId?: string;
|
||||||
|
AnalyticsCustomScript?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 视频源数据类型
|
// 视频源数据类型
|
||||||
@@ -10198,6 +10204,11 @@ const SiteConfigComponent = ({
|
|||||||
OIDCClientId: '',
|
OIDCClientId: '',
|
||||||
OIDCClientSecret: '',
|
OIDCClientSecret: '',
|
||||||
OIDCButtonText: '',
|
OIDCButtonText: '',
|
||||||
|
AnalyticsEnabled: false,
|
||||||
|
AnalyticsProvider: 'umami',
|
||||||
|
AnalyticsScriptUrl: '',
|
||||||
|
AnalyticsWebsiteId: '',
|
||||||
|
AnalyticsCustomScript: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
// 豆瓣数据源相关状态
|
// 豆瓣数据源相关状态
|
||||||
@@ -11528,6 +11539,170 @@ const SiteConfigComponent = ({
|
|||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
{/* 流量统计配置 */}
|
||||||
|
<details className='group rounded-lg border border-gray-200 p-4 dark:border-gray-700'>
|
||||||
|
<summary className='flex cursor-pointer items-center justify-between font-medium text-gray-900 dark:text-gray-100'>
|
||||||
|
<span className='flex items-center gap-2'>
|
||||||
|
<BarChart3 className='h-5 w-5' />
|
||||||
|
流量统计
|
||||||
|
</span>
|
||||||
|
<ChevronDown className='h-5 w-5 transition-transform group-open:rotate-180' />
|
||||||
|
</summary>
|
||||||
|
<div className='mt-4 space-y-4'>
|
||||||
|
{/* 启用开关 */}
|
||||||
|
<div className='flex items-center justify-between'>
|
||||||
|
<div>
|
||||||
|
<label className='block text-sm font-medium text-gray-700 dark:text-gray-300'>
|
||||||
|
启用流量统计
|
||||||
|
</label>
|
||||||
|
<p className='mt-1 text-xs text-gray-500 dark:text-gray-400'>
|
||||||
|
开启后将在页面中注入统计脚本,支持 Umami、Google Analytics 和自定义代码
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type='button'
|
||||||
|
onClick={() =>
|
||||||
|
setSiteSettings((prev) => ({
|
||||||
|
...prev,
|
||||||
|
AnalyticsEnabled: !prev.AnalyticsEnabled,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 ${
|
||||||
|
siteSettings.AnalyticsEnabled
|
||||||
|
? buttonStyles.toggleOn
|
||||||
|
: buttonStyles.toggleOff
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className={`inline-block h-4 w-4 transform rounded-full ${
|
||||||
|
buttonStyles.toggleThumb
|
||||||
|
} transition-transform ${
|
||||||
|
siteSettings.AnalyticsEnabled
|
||||||
|
? buttonStyles.toggleThumbOn
|
||||||
|
: buttonStyles.toggleThumbOff
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{siteSettings.AnalyticsEnabled && (
|
||||||
|
<>
|
||||||
|
{/* 统计服务提供商 */}
|
||||||
|
<div>
|
||||||
|
<label className='block text-sm font-medium text-gray-700 dark:text-gray-300'>
|
||||||
|
统计服务
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
value={siteSettings.AnalyticsProvider}
|
||||||
|
onChange={(e) =>
|
||||||
|
setSiteSettings((prev) => ({
|
||||||
|
...prev,
|
||||||
|
AnalyticsProvider: e.target.value as 'umami' | 'google' | 'custom',
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
className='mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 text-sm dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200'
|
||||||
|
>
|
||||||
|
<option value='umami'>Umami(开源,自托管)</option>
|
||||||
|
<option value='google'>Google Analytics</option>
|
||||||
|
<option value='custom'>自定义代码</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{siteSettings.AnalyticsProvider === 'umami' && (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<label className='block text-sm font-medium text-gray-700 dark:text-gray-300'>
|
||||||
|
Umami 脚本地址
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type='text'
|
||||||
|
value={siteSettings.AnalyticsScriptUrl}
|
||||||
|
onChange={(e) =>
|
||||||
|
setSiteSettings((prev) => ({
|
||||||
|
...prev,
|
||||||
|
AnalyticsScriptUrl: e.target.value,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
placeholder='https://your-umami-server.com/script.js'
|
||||||
|
className='mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 text-sm dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200'
|
||||||
|
/>
|
||||||
|
<p className='mt-1 text-xs text-gray-500 dark:text-gray-400'>
|
||||||
|
Umami 实例的 script.js 完整 URL
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className='block text-sm font-medium text-gray-700 dark:text-gray-300'>
|
||||||
|
网站 ID (Website ID)
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type='text'
|
||||||
|
value={siteSettings.AnalyticsWebsiteId}
|
||||||
|
onChange={(e) =>
|
||||||
|
setSiteSettings((prev) => ({
|
||||||
|
...prev,
|
||||||
|
AnalyticsWebsiteId: e.target.value,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
placeholder='e.g. 12345678-abcd-efgh-ijkl-1234567890ab'
|
||||||
|
className='mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 text-sm dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200'
|
||||||
|
/>
|
||||||
|
<p className='mt-1 text-xs text-gray-500 dark:text-gray-400'>
|
||||||
|
在 Umami 后台添加网站后获取的 Website ID
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{siteSettings.AnalyticsProvider === 'google' && (
|
||||||
|
<div>
|
||||||
|
<label className='block text-sm font-medium text-gray-700 dark:text-gray-300'>
|
||||||
|
Measurement ID
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type='text'
|
||||||
|
value={siteSettings.AnalyticsWebsiteId}
|
||||||
|
onChange={(e) =>
|
||||||
|
setSiteSettings((prev) => ({
|
||||||
|
...prev,
|
||||||
|
AnalyticsWebsiteId: e.target.value,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
placeholder='G-XXXXXXXXXX'
|
||||||
|
className='mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 text-sm dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200'
|
||||||
|
/>
|
||||||
|
<p className='mt-1 text-xs text-gray-500 dark:text-gray-400'>
|
||||||
|
Google Analytics 4 的 Measurement ID,在 GA 后台「数据流」中获取
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{siteSettings.AnalyticsProvider === 'custom' && (
|
||||||
|
<div>
|
||||||
|
<label className='block text-sm font-medium text-gray-700 dark:text-gray-300'>
|
||||||
|
自定义统计代码
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
value={siteSettings.AnalyticsCustomScript}
|
||||||
|
onChange={(e) =>
|
||||||
|
setSiteSettings((prev) => ({
|
||||||
|
...prev,
|
||||||
|
AnalyticsCustomScript: e.target.value,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
placeholder='粘贴完整的统计脚本代码,如百度统计、Plausible、51la 等...'
|
||||||
|
rows={6}
|
||||||
|
className='mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 font-mono text-sm dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200'
|
||||||
|
/>
|
||||||
|
<p className='mt-1 text-xs text-gray-500 dark:text-gray-400'>
|
||||||
|
支持任意第三方统计服务的脚本代码,将直接注入到页面 <head> 中
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
{/* 操作按钮 */}
|
{/* 操作按钮 */}
|
||||||
<div className='flex justify-end'>
|
<div className='flex justify-end'>
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -83,6 +83,11 @@ export async function POST(request: NextRequest) {
|
|||||||
OIDCClientSecret,
|
OIDCClientSecret,
|
||||||
OIDCButtonText,
|
OIDCButtonText,
|
||||||
OIDCMinTrustLevel,
|
OIDCMinTrustLevel,
|
||||||
|
AnalyticsEnabled,
|
||||||
|
AnalyticsProvider,
|
||||||
|
AnalyticsScriptUrl,
|
||||||
|
AnalyticsWebsiteId,
|
||||||
|
AnalyticsCustomScript,
|
||||||
} = body as {
|
} = body as {
|
||||||
SiteName: string;
|
SiteName: string;
|
||||||
Announcement: string;
|
Announcement: string;
|
||||||
@@ -138,6 +143,11 @@ export async function POST(request: NextRequest) {
|
|||||||
OIDCClientSecret?: string;
|
OIDCClientSecret?: string;
|
||||||
OIDCButtonText?: string;
|
OIDCButtonText?: string;
|
||||||
OIDCMinTrustLevel?: number;
|
OIDCMinTrustLevel?: number;
|
||||||
|
AnalyticsEnabled?: boolean;
|
||||||
|
AnalyticsProvider?: 'umami' | 'google' | 'custom';
|
||||||
|
AnalyticsScriptUrl?: string;
|
||||||
|
AnalyticsWebsiteId?: string;
|
||||||
|
AnalyticsCustomScript?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 参数校验
|
// 参数校验
|
||||||
@@ -224,7 +234,15 @@ export async function POST(request: NextRequest) {
|
|||||||
(OIDCClientSecret !== undefined &&
|
(OIDCClientSecret !== undefined &&
|
||||||
typeof OIDCClientSecret !== 'string') ||
|
typeof OIDCClientSecret !== 'string') ||
|
||||||
(OIDCButtonText !== undefined && typeof OIDCButtonText !== 'string') ||
|
(OIDCButtonText !== undefined && typeof OIDCButtonText !== 'string') ||
|
||||||
(OIDCMinTrustLevel !== undefined && typeof OIDCMinTrustLevel !== 'number')
|
(OIDCMinTrustLevel !== undefined && typeof OIDCMinTrustLevel !== 'number') ||
|
||||||
|
(AnalyticsEnabled !== undefined && typeof AnalyticsEnabled !== 'boolean') ||
|
||||||
|
(AnalyticsProvider !== undefined &&
|
||||||
|
AnalyticsProvider !== 'umami' &&
|
||||||
|
AnalyticsProvider !== 'google' &&
|
||||||
|
AnalyticsProvider !== 'custom') ||
|
||||||
|
(AnalyticsScriptUrl !== undefined && typeof AnalyticsScriptUrl !== 'string') ||
|
||||||
|
(AnalyticsWebsiteId !== undefined && typeof AnalyticsWebsiteId !== 'string') ||
|
||||||
|
(AnalyticsCustomScript !== undefined && typeof AnalyticsCustomScript !== 'string')
|
||||||
) {
|
) {
|
||||||
return NextResponse.json({ error: '参数格式错误' }, { status: 400 });
|
return NextResponse.json({ error: '参数格式错误' }, { status: 400 });
|
||||||
}
|
}
|
||||||
@@ -295,6 +313,11 @@ export async function POST(request: NextRequest) {
|
|||||||
OIDCClientSecret,
|
OIDCClientSecret,
|
||||||
OIDCButtonText,
|
OIDCButtonText,
|
||||||
OIDCMinTrustLevel,
|
OIDCMinTrustLevel,
|
||||||
|
AnalyticsEnabled,
|
||||||
|
AnalyticsProvider,
|
||||||
|
AnalyticsScriptUrl,
|
||||||
|
AnalyticsWebsiteId,
|
||||||
|
AnalyticsCustomScript,
|
||||||
};
|
};
|
||||||
|
|
||||||
// 写入数据库
|
// 写入数据库
|
||||||
|
|||||||
@@ -115,6 +115,11 @@ export default async function RootLayout({
|
|||||||
let liveEnabled = true;
|
let liveEnabled = true;
|
||||||
let webLiveEnabled = false;
|
let webLiveEnabled = false;
|
||||||
let customAdFilterVersion = 0;
|
let customAdFilterVersion = 0;
|
||||||
|
let analyticsEnabled = false;
|
||||||
|
let analyticsProvider: 'umami' | 'google' | 'custom' = 'umami';
|
||||||
|
let analyticsScriptUrl = '';
|
||||||
|
let analyticsWebsiteId = '';
|
||||||
|
let analyticsCustomScript = '';
|
||||||
let musicFeatureEnabled = false;
|
let musicFeatureEnabled = false;
|
||||||
let suwayomiEnabled = false;
|
let suwayomiEnabled = false;
|
||||||
let booksEnabled =
|
let booksEnabled =
|
||||||
@@ -202,6 +207,12 @@ export default async function RootLayout({
|
|||||||
webLiveEnabled = config.WebLiveEnabled ?? false;
|
webLiveEnabled = config.WebLiveEnabled ?? false;
|
||||||
// 自定义去广告代码版本号
|
// 自定义去广告代码版本号
|
||||||
customAdFilterVersion = config.SiteConfig?.CustomAdFilterVersion || 0;
|
customAdFilterVersion = config.SiteConfig?.CustomAdFilterVersion || 0;
|
||||||
|
// 流量统计配置
|
||||||
|
analyticsEnabled = config.SiteConfig?.AnalyticsEnabled || false;
|
||||||
|
analyticsProvider = config.SiteConfig?.AnalyticsProvider || 'umami';
|
||||||
|
analyticsScriptUrl = config.SiteConfig?.AnalyticsScriptUrl || '';
|
||||||
|
analyticsWebsiteId = config.SiteConfig?.AnalyticsWebsiteId || '';
|
||||||
|
analyticsCustomScript = config.SiteConfig?.AnalyticsCustomScript || '';
|
||||||
// 音乐功能配置
|
// 音乐功能配置
|
||||||
musicFeatureEnabled = config.MusicConfig?.Enabled || false;
|
musicFeatureEnabled = config.MusicConfig?.Enabled || false;
|
||||||
musicProxyEnabled = config.MusicConfig?.ProxyEnabled ?? true;
|
musicProxyEnabled = config.MusicConfig?.ProxyEnabled ?? true;
|
||||||
@@ -335,6 +346,37 @@ export default async function RootLayout({
|
|||||||
__html: `window.RUNTIME_CONFIG = ${JSON.stringify(runtimeConfig)};`,
|
__html: `window.RUNTIME_CONFIG = ${JSON.stringify(runtimeConfig)};`,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
{/* 流量统计脚本 */}
|
||||||
|
{analyticsEnabled && analyticsProvider === 'umami' && analyticsScriptUrl && (
|
||||||
|
<>
|
||||||
|
{/* eslint-disable-next-line @next/next/no-sync-scripts */}
|
||||||
|
<script
|
||||||
|
async
|
||||||
|
defer
|
||||||
|
data-website-id={analyticsWebsiteId}
|
||||||
|
src={analyticsScriptUrl}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{analyticsEnabled && analyticsProvider === 'google' && analyticsWebsiteId && (
|
||||||
|
<>
|
||||||
|
{/* eslint-disable-next-line @next/next/no-sync-scripts */}
|
||||||
|
<script
|
||||||
|
async
|
||||||
|
src={`https://www.googletagmanager.com/gtag/js?id=${analyticsWebsiteId}`}
|
||||||
|
/>
|
||||||
|
<script
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: `window.dataLayer = window.dataLayer || [];function gtag(){dataLayer.push(arguments);}gtag('js', new Date());gtag('config', '${analyticsWebsiteId}');`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{analyticsEnabled && analyticsProvider === 'custom' && analyticsCustomScript && (
|
||||||
|
<script
|
||||||
|
dangerouslySetInnerHTML={{ __html: analyticsCustomScript }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</head>
|
</head>
|
||||||
<body
|
<body
|
||||||
className={`${inter.className} min-h-screen bg-white text-gray-900 dark:bg-black dark:text-gray-200`}
|
className={`${inter.className} min-h-screen bg-white text-gray-900 dark:bg-black dark:text-gray-200`}
|
||||||
|
|||||||
@@ -73,6 +73,12 @@ export interface AdminConfig {
|
|||||||
OIDCClientSecret?: string; // OIDC Client Secret
|
OIDCClientSecret?: string; // OIDC Client Secret
|
||||||
OIDCButtonText?: string; // OIDC登录按钮文字
|
OIDCButtonText?: string; // OIDC登录按钮文字
|
||||||
OIDCMinTrustLevel?: number; // 最低信任等级(仅LinuxDo网站有效,为0时不判断)
|
OIDCMinTrustLevel?: number; // 最低信任等级(仅LinuxDo网站有效,为0时不判断)
|
||||||
|
// 流量统计配置
|
||||||
|
AnalyticsEnabled?: boolean; // 是否启用流量统计
|
||||||
|
AnalyticsProvider?: 'umami' | 'google' | 'custom'; // 统计服务提供商
|
||||||
|
AnalyticsScriptUrl?: string; // 脚本URL(Umami: umami.js地址; GA: gtag URL; 自定义: 脚本src)
|
||||||
|
AnalyticsWebsiteId?: string; // 网站ID(Umami: website_id; GA: Measurement ID如G-XXXX; 自定义: 留空)
|
||||||
|
AnalyticsCustomScript?: string; // 自定义统计代码(仅custom模式使用,完整的HTML脚本内容)
|
||||||
};
|
};
|
||||||
UserConfig: {
|
UserConfig: {
|
||||||
Users: {
|
Users: {
|
||||||
|
|||||||
@@ -328,6 +328,12 @@ async function getInitConfig(
|
|||||||
TurnstileSiteKey: '',
|
TurnstileSiteKey: '',
|
||||||
TurnstileSecretKey: '',
|
TurnstileSecretKey: '',
|
||||||
DefaultUserTags: [],
|
DefaultUserTags: [],
|
||||||
|
// 流量统计配置
|
||||||
|
AnalyticsEnabled: false,
|
||||||
|
AnalyticsProvider: 'umami',
|
||||||
|
AnalyticsScriptUrl: '',
|
||||||
|
AnalyticsWebsiteId: '',
|
||||||
|
AnalyticsCustomScript: '',
|
||||||
},
|
},
|
||||||
UserConfig: {
|
UserConfig: {
|
||||||
Users: [],
|
Users: [],
|
||||||
@@ -588,6 +594,22 @@ export function configSelfCheck(adminConfig: AdminConfig): AdminConfig {
|
|||||||
if (adminConfig.SiteConfig.DefaultUserTags === undefined) {
|
if (adminConfig.SiteConfig.DefaultUserTags === undefined) {
|
||||||
adminConfig.SiteConfig.DefaultUserTags = [];
|
adminConfig.SiteConfig.DefaultUserTags = [];
|
||||||
}
|
}
|
||||||
|
// 流量统计配置补全
|
||||||
|
if (adminConfig.SiteConfig.AnalyticsEnabled === undefined) {
|
||||||
|
adminConfig.SiteConfig.AnalyticsEnabled = false;
|
||||||
|
}
|
||||||
|
if (adminConfig.SiteConfig.AnalyticsProvider === undefined) {
|
||||||
|
adminConfig.SiteConfig.AnalyticsProvider = 'umami';
|
||||||
|
}
|
||||||
|
if (adminConfig.SiteConfig.AnalyticsScriptUrl === undefined) {
|
||||||
|
adminConfig.SiteConfig.AnalyticsScriptUrl = '';
|
||||||
|
}
|
||||||
|
if (adminConfig.SiteConfig.AnalyticsWebsiteId === undefined) {
|
||||||
|
adminConfig.SiteConfig.AnalyticsWebsiteId = '';
|
||||||
|
}
|
||||||
|
if (adminConfig.SiteConfig.AnalyticsCustomScript === undefined) {
|
||||||
|
adminConfig.SiteConfig.AnalyticsCustomScript = '';
|
||||||
|
}
|
||||||
if (!adminConfig.TelegramConfig) {
|
if (!adminConfig.TelegramConfig) {
|
||||||
adminConfig.TelegramConfig = {
|
adminConfig.TelegramConfig = {
|
||||||
enabled: process.env.TELEGRAM_BOT_ENABLED === 'true' || Boolean(process.env.TELEGRAM_BOT_TOKEN),
|
enabled: process.env.TELEGRAM_BOT_ENABLED === 'true' || Boolean(process.env.TELEGRAM_BOT_TOKEN),
|
||||||
|
|||||||
Reference in New Issue
Block a user