feat: 添加通知功能自定义telegram域名功能
This commit is contained in:
@@ -121,7 +121,7 @@ export const uploadTerminalBackgroundController = async (req: Request, res: Resp
|
||||
};
|
||||
|
||||
/**
|
||||
* 新增:获取背景图片文件
|
||||
* 获取背景图片文件
|
||||
*/
|
||||
export const getBackgroundFileController = async (req: Request, res: Response): Promise<void> => {
|
||||
const filename = req.params.filename;
|
||||
|
||||
@@ -27,7 +27,7 @@ router.post(
|
||||
appearanceController.uploadTerminalBackgroundController
|
||||
);
|
||||
|
||||
// 新增:GET /api/v1/appearance/background/file/:filename - 获取背景图片文件
|
||||
// GET /api/v1/appearance/background/file/:filename - 获取背景图片文件
|
||||
router.get('/background/file/:filename', appearanceController.getBackgroundFileController);
|
||||
|
||||
// DELETE /api/v1/appearance/background/page - 删除页面背景图片
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
// 新的 Passkey 管理处理器
|
||||
listUserPasskeysHandler,
|
||||
deleteUserPasskeyHandler,
|
||||
updateUserPasskeyNameHandler, // 新增:更新 Passkey 名称的处理器
|
||||
updateUserPasskeyNameHandler, // 更新 Passkey 名称的处理器
|
||||
checkHasPasskeys
|
||||
} from './auth.controller';
|
||||
import { isAuthenticated } from './auth.middleware';
|
||||
|
||||
@@ -18,7 +18,7 @@ interface DbAppearanceSettingsRow {
|
||||
const mapRowsToAppearanceSettings = (rows: DbAppearanceSettingsRow[]): AppearanceSettings => {
|
||||
const settings: Partial<AppearanceSettings> = {};
|
||||
let latestUpdatedAt = 0;
|
||||
let terminalBackgroundEnabledFound = false; // 新增:标记是否在数据库中找到该设置
|
||||
let terminalBackgroundEnabledFound = false; // 标记是否在数据库中找到该设置
|
||||
|
||||
for (const row of rows) {
|
||||
// 更新 latestUpdatedAt
|
||||
@@ -85,7 +85,7 @@ const getDefaultAppearanceSettings = (): Omit<AppearanceSettings, '_id'> => {
|
||||
editorFontSize: 14,
|
||||
terminalBackgroundImage: undefined,
|
||||
pageBackgroundImage: undefined,
|
||||
terminalBackgroundEnabled: true, // 新增:默认启用
|
||||
terminalBackgroundEnabled: true, // 默认启用
|
||||
updatedAt: Date.now(), // 提供默认时间戳
|
||||
};
|
||||
};
|
||||
@@ -249,7 +249,7 @@ const updateAppearanceSettingsInternal = async (db: sqlite3.Database, settingsDt
|
||||
dbValue = key === 'activeTerminalThemeId' ? 'null' : ''; // 主题 ID 特殊存储为 'null'
|
||||
} else if (typeof value === 'object') {
|
||||
dbValue = JSON.stringify(value);
|
||||
} else if (typeof value === 'boolean') { // 新增:处理布尔值
|
||||
} else if (typeof value === 'boolean') { // 处理布尔值
|
||||
dbValue = value ? 'true' : 'false';
|
||||
} else {
|
||||
dbValue = String(value);
|
||||
|
||||
@@ -356,7 +356,17 @@ export class NotificationService {
|
||||
);
|
||||
console.log(`[通知测试 - Telegram] 渲染的消息文本:`, messageText);
|
||||
|
||||
const telegramApiUrl = `https://api.telegram.org/bot${config.botToken}/sendMessage`;
|
||||
let baseApiUrl = "https://api.telegram.org";
|
||||
if (config.customDomain) {
|
||||
try {
|
||||
const url = new URL(config.customDomain);
|
||||
baseApiUrl = `${url.protocol}//${url.host}`;
|
||||
console.log(`[通知测试 - Telegram] 使用自定义域名: ${baseApiUrl}`);
|
||||
} catch (e) {
|
||||
console.warn(`[通知测试 - Telegram] 无效的自定义域名 URL: ${config.customDomain}。将回退到默认 Telegram API。`);
|
||||
}
|
||||
}
|
||||
const telegramApiUrl = `${baseApiUrl}/bot${config.botToken}/sendMessage`;
|
||||
|
||||
try {
|
||||
console.log(
|
||||
@@ -802,7 +812,18 @@ export class NotificationService {
|
||||
}
|
||||
console.log(`[_sendTelegram] Final message text to send:`, messageText);
|
||||
|
||||
const telegramApiUrl = `https://api.telegram.org/bot${config.botToken}/sendMessage`;
|
||||
let baseApiUrlSend = "https://api.telegram.org";
|
||||
if (config.customDomain) {
|
||||
try {
|
||||
const url = new URL(config.customDomain);
|
||||
baseApiUrlSend = `${url.protocol}//${url.host}`;
|
||||
console.log(`[_sendTelegram] 使用自定义域名: ${baseApiUrlSend} (事件: ${payload.event})`);
|
||||
} catch (e) {
|
||||
console.warn(`[_sendTelegram] 无效的自定义域名 URL: ${config.customDomain} (事件: ${payload.event})。将回退到默认 Telegram API。`);
|
||||
}
|
||||
}
|
||||
const telegramApiUrl = `${baseApiUrlSend}/bot${config.botToken}/sendMessage`;
|
||||
|
||||
try {
|
||||
console.log(
|
||||
`[通知] 发送 Telegram 消息到聊天 ID ${config.chatId} (事件: ${payload.event})`
|
||||
|
||||
@@ -6,7 +6,7 @@ import { TelegramConfig } from "../../types/notification.types";
|
||||
class TelegramSenderService implements INotificationSender {
|
||||
async send(notification: ProcessedNotification): Promise<void> {
|
||||
const config = notification.config as TelegramConfig;
|
||||
const { botToken, chatId } = config;
|
||||
const { botToken, chatId, customDomain } = config; // Destructure customDomain
|
||||
const messageBody = notification.body;
|
||||
|
||||
if (!botToken || !chatId) {
|
||||
@@ -18,7 +18,19 @@ class TelegramSenderService implements INotificationSender {
|
||||
);
|
||||
}
|
||||
|
||||
const apiUrl = `https://api.telegram.org/bot${botToken}/sendMessage`;
|
||||
let baseApiUrl = "https://api.telegram.org";
|
||||
if (customDomain) {
|
||||
try {
|
||||
const url = new URL(customDomain); // Validate and parse the custom domain
|
||||
baseApiUrl = `${url.protocol}//${url.host}`; // Use protocol and host from customDomain
|
||||
console.log(`[TelegramSender] Using custom domain: ${baseApiUrl}`);
|
||||
} catch (e) {
|
||||
console.warn(`[TelegramSender] Invalid customDomain URL: ${customDomain}. Falling back to default Telegram API.`);
|
||||
// Optionally, you could throw an error here or decide to proceed with the default
|
||||
}
|
||||
}
|
||||
|
||||
const apiUrl = `${baseApiUrl}/bot${botToken}/sendMessage`;
|
||||
|
||||
try {
|
||||
console.log(
|
||||
|
||||
@@ -753,7 +753,7 @@ export class SftpService {
|
||||
}
|
||||
|
||||
try {
|
||||
// --- 新增:移动前检查目标是否存在 ---
|
||||
// --- 移动前检查目标是否存在 ---
|
||||
let targetExists = false;
|
||||
try {
|
||||
await this.getStats(sftp, newPath);
|
||||
@@ -1011,7 +1011,7 @@ export class SftpService {
|
||||
console.log(`[SFTP Upload ${uploadId}] Starting upload for ${remotePath} (${totalSize} bytes) in session ${sessionId}`);
|
||||
|
||||
try {
|
||||
// --- 新增:在创建流之前确保目录存在 ---
|
||||
// --- 在创建流之前确保目录存在 ---
|
||||
if (relativePath) {
|
||||
const targetDirectory = pathModule.dirname(remotePath).replace(/\\/g, '/');
|
||||
console.log(`[SFTP Upload ${uploadId}] Ensuring directory exists: ${targetDirectory}`);
|
||||
@@ -1029,7 +1029,7 @@ export class SftpService {
|
||||
}
|
||||
// --- 结束新增 ---
|
||||
|
||||
// --- 新增:预检查文件是否可写 ---
|
||||
// --- 预检查文件是否可写 ---
|
||||
console.log(`[SFTP Upload ${uploadId}] Pre-checking writability for: ${remotePath}`);
|
||||
try {
|
||||
// 确保 state.sftp 存在
|
||||
|
||||
@@ -16,7 +16,7 @@ export interface AppearanceSettings {
|
||||
terminalBackgroundImage?: string; // 终端背景图片 URL 或路径
|
||||
pageBackgroundImage?: string; // 页面背景图片 URL 或路径
|
||||
editorFontSize?: number; // 编辑器字体大小 (px)
|
||||
terminalBackgroundEnabled?: boolean; // 新增:终端背景是否启用
|
||||
terminalBackgroundEnabled?: boolean; // 终端背景是否启用
|
||||
updatedAt?: number;
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ export interface TelegramConfig {
|
||||
botToken: string; // Consider storing this securely, maybe encrypted or via env vars
|
||||
chatId: string; // Target chat ID
|
||||
messageTemplate?: string; // Optional message template
|
||||
customDomain?: string; // 允许用户自定义 Telegram API 域名
|
||||
}
|
||||
|
||||
export type NotificationChannelConfig = WebhookConfig | EmailConfig | TelegramConfig;
|
||||
|
||||
@@ -16,7 +16,7 @@ export function handleRdpProxyConnection(
|
||||
const rdpWidthStr = (request as any).rdpWidth; // Get as string first
|
||||
const rdpHeightStr = (request as any).rdpHeight; // Get as string first
|
||||
|
||||
// --- 新增:参数验证和 DPI 计算 ---
|
||||
// --- 参数验证和 DPI 计算 ---
|
||||
if (!rdpToken || !rdpWidthStr || !rdpHeightStr) { // Check string presence
|
||||
console.error(`WebSocket: RDP Proxy connection for ${ws.username} missing required parameters (token, width, height).`);
|
||||
ws.send(JSON.stringify({ type: 'rdp:error', payload: 'Missing RDP connection parameters (token, width, height).' }));
|
||||
|
||||
@@ -20,10 +20,10 @@ export interface ClientState { // 导出以便 Service 可以导入
|
||||
statusIntervalId?: NodeJS.Timeout; // 添加状态轮询 ID (由 StatusMonitorService 管理)
|
||||
dockerStatusIntervalId?: NodeJS.Timeout; // NEW: Docker 状态轮询 ID
|
||||
ipAddress?: string; // 添加 IP 地址字段
|
||||
isShellReady?: boolean; // 新增:标记 Shell 是否已准备好处理输入和调整大小
|
||||
isSuspendedByService?: boolean; // 新增:标记此会话是否已被 SshSuspendService 接管
|
||||
isMarkedForSuspend?: boolean; // 新增:标记此会话是否已被用户请求挂起(等待断开连接)
|
||||
suspendLogPath?: string; // 新增:如果标记挂起,则存储日志路径 (基于原始 sessionId)
|
||||
isShellReady?: boolean; // 标记 Shell 是否已准备好处理输入和调整大小
|
||||
isSuspendedByService?: boolean; // 标记此会话是否已被 SshSuspendService 接管
|
||||
isMarkedForSuspend?: boolean; // 标记此会话是否已被用户请求挂起(等待断开连接)
|
||||
suspendLogPath?: string; // 如果标记挂起,则存储日志路径 (基于原始 sessionId)
|
||||
// suspendLogWritableStream?: NodeJS.WritableStream; // 移除,将直接使用 temporaryLogStorageService.writeToLog
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user