forked from boos/BoosAPI
fix: improve tester timeouts and telegram proxy config
This commit is contained in:
@@ -32,6 +32,12 @@ describe('buildConfig', () => {
|
||||
expect(config.listenHost).toBe('127.0.0.1');
|
||||
});
|
||||
|
||||
it('defaults telegram api base url to the official endpoint', () => {
|
||||
const config = buildConfig({});
|
||||
|
||||
expect(config.telegramApiBaseUrl).toBe('https://api.telegram.org');
|
||||
});
|
||||
|
||||
it('accepts JSON request bodies larger than Fastify default 1 MiB', async () => {
|
||||
const app = Fastify(buildFastifyOptions(buildConfig({})));
|
||||
const largeText = 'a'.repeat(2 * 1024 * 1024);
|
||||
|
||||
@@ -61,6 +61,7 @@ export function buildConfig(env: NodeJS.ProcessEnv) {
|
||||
serverChanEnabled: parseBoolean(env.SERVERCHAN_ENABLED, true),
|
||||
serverChanKey: env.SERVERCHAN_KEY || '',
|
||||
telegramEnabled: parseBoolean(env.TELEGRAM_ENABLED, false),
|
||||
telegramApiBaseUrl: 'https://api.telegram.org',
|
||||
telegramBotToken: env.TELEGRAM_BOT_TOKEN || '',
|
||||
telegramChatId: env.TELEGRAM_CHAT_ID || '',
|
||||
smtpEnabled: parseBoolean(env.SMTP_ENABLED, false),
|
||||
|
||||
@@ -175,6 +175,11 @@ function applyRuntimeSettings(settingsMap: Map<string, string>) {
|
||||
const telegramEnabled = parseSettingFromMap<boolean>(settingsMap, 'telegram_enabled');
|
||||
if (typeof telegramEnabled === 'boolean') config.telegramEnabled = telegramEnabled;
|
||||
|
||||
const telegramApiBaseUrl = parseSettingFromMap<string>(settingsMap, 'telegram_api_base_url');
|
||||
if (typeof telegramApiBaseUrl === 'string' && telegramApiBaseUrl.trim()) {
|
||||
config.telegramApiBaseUrl = telegramApiBaseUrl.trim().replace(/\/+$/, '');
|
||||
}
|
||||
|
||||
const telegramBotToken = parseSettingFromMap<string>(settingsMap, 'telegram_bot_token');
|
||||
if (typeof telegramBotToken === 'string') config.telegramBotToken = telegramBotToken;
|
||||
|
||||
|
||||
@@ -49,6 +49,10 @@ describe('settings and auth events', () => {
|
||||
config.logCleanupProgramLogsEnabled = false;
|
||||
config.logCleanupRetentionDays = 30;
|
||||
config.routingFallbackUnitCost = 1;
|
||||
(config as any).telegramEnabled = false;
|
||||
(config as any).telegramApiBaseUrl = 'https://api.telegram.org';
|
||||
(config as any).telegramBotToken = '';
|
||||
(config as any).telegramChatId = '';
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
@@ -170,6 +174,49 @@ describe('settings and auth events', () => {
|
||||
expect(body.message).toContain('Telegram Chat ID');
|
||||
});
|
||||
|
||||
it('persists and returns telegram api base url from runtime settings', async () => {
|
||||
const updateResponse = await app.inject({
|
||||
method: 'PUT',
|
||||
url: '/api/settings/runtime',
|
||||
payload: {
|
||||
telegramApiBaseUrl: 'https://tg-proxy.example.com/custom/',
|
||||
},
|
||||
});
|
||||
|
||||
expect(updateResponse.statusCode).toBe(200);
|
||||
const updated = updateResponse.json() as { telegramApiBaseUrl?: string };
|
||||
expect(updated.telegramApiBaseUrl).toBe('https://tg-proxy.example.com/custom');
|
||||
expect((config as any).telegramApiBaseUrl).toBe('https://tg-proxy.example.com/custom');
|
||||
|
||||
const saved = await db.select().from(schema.settings).where(eq(schema.settings.key, 'telegram_api_base_url')).get();
|
||||
expect(saved?.value).toBe(JSON.stringify('https://tg-proxy.example.com/custom'));
|
||||
|
||||
const getResponse = await app.inject({
|
||||
method: 'GET',
|
||||
url: '/api/settings/runtime',
|
||||
});
|
||||
expect(getResponse.statusCode).toBe(200);
|
||||
const runtime = getResponse.json() as { telegramApiBaseUrl?: string };
|
||||
expect(runtime.telegramApiBaseUrl).toBe('https://tg-proxy.example.com/custom');
|
||||
});
|
||||
|
||||
it('rejects invalid telegram api base url when telegram is enabled', async () => {
|
||||
const response = await app.inject({
|
||||
method: 'PUT',
|
||||
url: '/api/settings/runtime',
|
||||
payload: {
|
||||
telegramEnabled: true,
|
||||
telegramBotToken: '123456:telegram-token',
|
||||
telegramChatId: '-1001234567890',
|
||||
telegramApiBaseUrl: 'not-a-url',
|
||||
},
|
||||
});
|
||||
|
||||
expect(response.statusCode).toBe(400);
|
||||
const body = response.json() as { message?: string };
|
||||
expect(body.message).toContain('Telegram API Base URL');
|
||||
});
|
||||
|
||||
it('persists and returns routing fallback unit cost from runtime settings', async () => {
|
||||
const updateResponse = await app.inject({
|
||||
method: 'PUT',
|
||||
|
||||
@@ -40,6 +40,7 @@ interface RuntimeSettingsBody {
|
||||
serverChanEnabled?: boolean;
|
||||
serverChanKey?: string;
|
||||
telegramEnabled?: boolean;
|
||||
telegramApiBaseUrl?: string;
|
||||
telegramBotToken?: string;
|
||||
telegramChatId?: string;
|
||||
smtpEnabled?: boolean;
|
||||
@@ -137,6 +138,10 @@ function isValidHttpUrl(raw: string): boolean {
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeTelegramApiBaseUrl(raw: string): string {
|
||||
return String(raw || '').trim().replace(/\/+$/, '');
|
||||
}
|
||||
|
||||
function applyImportedSettingToRuntime(key: string, value: unknown) {
|
||||
switch (key) {
|
||||
case 'checkin_cron': {
|
||||
@@ -223,6 +228,11 @@ function applyImportedSettingToRuntime(key: string, value: unknown) {
|
||||
config.telegramEnabled = !!value;
|
||||
return;
|
||||
}
|
||||
case 'telegram_api_base_url': {
|
||||
if (typeof value !== 'string') return;
|
||||
config.telegramApiBaseUrl = normalizeTelegramApiBaseUrl(value) || 'https://api.telegram.org';
|
||||
return;
|
||||
}
|
||||
case 'telegram_bot_token': {
|
||||
if (typeof value !== 'string') return;
|
||||
config.telegramBotToken = value.trim();
|
||||
@@ -322,6 +332,7 @@ function getRuntimeSettingsResponse(currentAdminIp = '') {
|
||||
serverChanEnabled: config.serverChanEnabled,
|
||||
serverChanKeyMasked: maskSecret(config.serverChanKey),
|
||||
telegramEnabled: config.telegramEnabled,
|
||||
telegramApiBaseUrl: config.telegramApiBaseUrl,
|
||||
telegramBotTokenMasked: maskSecret(config.telegramBotToken),
|
||||
telegramChatId: config.telegramChatId,
|
||||
smtpEnabled: config.smtpEnabled,
|
||||
@@ -452,11 +463,15 @@ export async function settingsRoutes(app: FastifyInstance) {
|
||||
}
|
||||
|
||||
const telegramTouched = body.telegramEnabled !== undefined
|
||||
|| body.telegramApiBaseUrl !== undefined
|
||||
|| body.telegramBotToken !== undefined
|
||||
|| body.telegramChatId !== undefined;
|
||||
const nextTelegramEnabled = body.telegramEnabled !== undefined
|
||||
? !!body.telegramEnabled
|
||||
: config.telegramEnabled;
|
||||
const nextTelegramApiBaseUrl = body.telegramApiBaseUrl !== undefined
|
||||
? normalizeTelegramApiBaseUrl(body.telegramApiBaseUrl)
|
||||
: config.telegramApiBaseUrl;
|
||||
const nextTelegramBotToken = body.telegramBotToken !== undefined
|
||||
? String(body.telegramBotToken || '').trim()
|
||||
: config.telegramBotToken;
|
||||
@@ -473,6 +488,11 @@ export async function settingsRoutes(app: FastifyInstance) {
|
||||
if (!nextTelegramChatId) {
|
||||
return reply.code(400).send({ success: false, message: 'Telegram Chat ID 不能为空(启用 Telegram 时)' });
|
||||
}
|
||||
if (nextTelegramApiBaseUrl && !isValidHttpUrl(nextTelegramApiBaseUrl)) {
|
||||
return reply.code(400).send({ success: false, message: 'Telegram API Base URL 无效,请填写 http/https 地址' });
|
||||
}
|
||||
} else if (body.telegramApiBaseUrl !== undefined && nextTelegramApiBaseUrl && !isValidHttpUrl(nextTelegramApiBaseUrl)) {
|
||||
return reply.code(400).send({ success: false, message: 'Telegram API Base URL 无效,请填写 http/https 地址' });
|
||||
}
|
||||
|
||||
if (body.checkinCron !== undefined) {
|
||||
@@ -639,6 +659,16 @@ export async function settingsRoutes(app: FastifyInstance) {
|
||||
upsertSetting('telegram_enabled', config.telegramEnabled);
|
||||
}
|
||||
|
||||
if (body.telegramApiBaseUrl !== undefined) {
|
||||
const normalizedTelegramApiBaseUrl = normalizeTelegramApiBaseUrl(body.telegramApiBaseUrl);
|
||||
const nextTelegramApiBaseUrl = normalizedTelegramApiBaseUrl || 'https://api.telegram.org';
|
||||
if (nextTelegramApiBaseUrl !== config.telegramApiBaseUrl) {
|
||||
changedLabels.push('Telegram API Base URL');
|
||||
}
|
||||
config.telegramApiBaseUrl = nextTelegramApiBaseUrl;
|
||||
upsertSetting('telegram_api_base_url', config.telegramApiBaseUrl);
|
||||
}
|
||||
|
||||
if (body.telegramBotToken !== undefined) {
|
||||
if (String(body.telegramBotToken || '').trim() !== config.telegramBotToken) {
|
||||
changedLabels.push('Telegram Bot Token');
|
||||
|
||||
@@ -198,4 +198,28 @@ describe('notifyService', () => {
|
||||
expect(payload.text || '').toContain('Local Time:');
|
||||
expect(payload.text || '').toContain('UTC Time:');
|
||||
});
|
||||
|
||||
it('uses TELEGRAM_API_BASE_URL when configured', async () => {
|
||||
const { config } = await import('../config.js');
|
||||
(config as any).telegramEnabled = true;
|
||||
(config as any).telegramBotToken = '123456:telegram-token';
|
||||
(config as any).telegramChatId = '-1001234567890';
|
||||
(config as any).telegramApiBaseUrl = 'https://tg-proxy.example.com/custom/';
|
||||
config.smtpEnabled = false;
|
||||
|
||||
fetchMock.mockResolvedValue({
|
||||
ok: true,
|
||||
status: 200,
|
||||
});
|
||||
|
||||
const { sendNotification } = await import('./notifyService.js');
|
||||
await sendNotification('测试通知', 'message', 'warning', { bypassThrottle: true, throwOnFailure: true });
|
||||
|
||||
expect(fetchMock).toHaveBeenCalledWith(
|
||||
'https://tg-proxy.example.com/custom/bot123456:telegram-token/sendMessage',
|
||||
expect.objectContaining({
|
||||
method: 'POST',
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -218,7 +218,8 @@ export async function sendNotification(
|
||||
}
|
||||
|
||||
if (config.telegramEnabled && config.telegramBotToken && config.telegramChatId) {
|
||||
const telegramApiUrl = `https://api.telegram.org/bot${config.telegramBotToken}/sendMessage`;
|
||||
const telegramApiBaseUrl = String(config.telegramApiBaseUrl || 'https://api.telegram.org').replace(/\/+$/, '');
|
||||
const telegramApiUrl = `${telegramApiBaseUrl}/bot${config.telegramBotToken}/sendMessage`;
|
||||
const text = buildTelegramText(title, resolvedMessage, level, timeFootnote);
|
||||
tasks.push({
|
||||
channel: 'telegram',
|
||||
|
||||
Reference in New Issue
Block a user