diff --git a/backend/src/index.ts b/backend/src/index.ts index d482bfb..b2b78cc 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -37,6 +37,15 @@ async function runMigrations() { IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'users' AND column_name = 'pushover_app_token') THEN ALTER TABLE users ADD COLUMN pushover_app_token TEXT; END IF; + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'users' AND column_name = 'telegram_enabled') THEN + ALTER TABLE users ADD COLUMN telegram_enabled BOOLEAN DEFAULT true; + END IF; + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'users' AND column_name = 'discord_enabled') THEN + ALTER TABLE users ADD COLUMN discord_enabled BOOLEAN DEFAULT true; + END IF; + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'users' AND column_name = 'pushover_enabled') THEN + ALTER TABLE users ADD COLUMN pushover_enabled BOOLEAN DEFAULT true; + END IF; END $$; `); console.log('Database migrations completed'); diff --git a/backend/src/models/index.ts b/backend/src/models/index.ts index 8f5fe86..8855619 100644 --- a/backend/src/models/index.ts +++ b/backend/src/models/index.ts @@ -24,9 +24,12 @@ export interface UserProfile { export interface NotificationSettings { telegram_bot_token: string | null; telegram_chat_id: string | null; + telegram_enabled: boolean; discord_webhook_url: string | null; + discord_enabled: boolean; pushover_user_key: string | null; pushover_app_token: string | null; + pushover_enabled: boolean; } export interface AISettings { @@ -63,7 +66,10 @@ export const userQueries = { getNotificationSettings: async (id: number): Promise => { const result = await pool.query( - 'SELECT telegram_bot_token, telegram_chat_id, discord_webhook_url, pushover_user_key, pushover_app_token FROM users WHERE id = $1', + `SELECT telegram_bot_token, telegram_chat_id, COALESCE(telegram_enabled, true) as telegram_enabled, + discord_webhook_url, COALESCE(discord_enabled, true) as discord_enabled, + pushover_user_key, pushover_app_token, COALESCE(pushover_enabled, true) as pushover_enabled + FROM users WHERE id = $1`, [id] ); return result.rows[0] || null; @@ -74,7 +80,7 @@ export const userQueries = { settings: Partial ): Promise => { const fields: string[] = []; - const values: (string | null)[] = []; + const values: (string | boolean | null)[] = []; let paramIndex = 1; if (settings.telegram_bot_token !== undefined) { @@ -85,10 +91,18 @@ export const userQueries = { fields.push(`telegram_chat_id = $${paramIndex++}`); values.push(settings.telegram_chat_id); } + if (settings.telegram_enabled !== undefined) { + fields.push(`telegram_enabled = $${paramIndex++}`); + values.push(settings.telegram_enabled); + } if (settings.discord_webhook_url !== undefined) { fields.push(`discord_webhook_url = $${paramIndex++}`); values.push(settings.discord_webhook_url); } + if (settings.discord_enabled !== undefined) { + fields.push(`discord_enabled = $${paramIndex++}`); + values.push(settings.discord_enabled); + } if (settings.pushover_user_key !== undefined) { fields.push(`pushover_user_key = $${paramIndex++}`); values.push(settings.pushover_user_key); @@ -97,13 +111,19 @@ export const userQueries = { fields.push(`pushover_app_token = $${paramIndex++}`); values.push(settings.pushover_app_token); } + if (settings.pushover_enabled !== undefined) { + fields.push(`pushover_enabled = $${paramIndex++}`); + values.push(settings.pushover_enabled); + } if (fields.length === 0) return null; values.push(id.toString()); const result = await pool.query( `UPDATE users SET ${fields.join(', ')} WHERE id = $${paramIndex} - RETURNING telegram_bot_token, telegram_chat_id, discord_webhook_url, pushover_user_key, pushover_app_token`, + RETURNING telegram_bot_token, telegram_chat_id, COALESCE(telegram_enabled, true) as telegram_enabled, + discord_webhook_url, COALESCE(discord_enabled, true) as discord_enabled, + pushover_user_key, pushover_app_token, COALESCE(pushover_enabled, true) as pushover_enabled`, values ); return result.rows[0] || null; diff --git a/backend/src/routes/settings.ts b/backend/src/routes/settings.ts index 318e59c..4ac680e 100644 --- a/backend/src/routes/settings.ts +++ b/backend/src/routes/settings.ts @@ -22,8 +22,11 @@ router.get('/notifications', async (req: AuthRequest, res: Response) => { res.json({ telegram_configured: !!(settings.telegram_bot_token && settings.telegram_chat_id), telegram_chat_id: settings.telegram_chat_id, + telegram_enabled: settings.telegram_enabled ?? true, discord_configured: !!settings.discord_webhook_url, + discord_enabled: settings.discord_enabled ?? true, pushover_configured: !!(settings.pushover_user_key && settings.pushover_app_token), + pushover_enabled: settings.pushover_enabled ?? true, }); } catch (error) { console.error('Error fetching notification settings:', error); @@ -35,14 +38,26 @@ router.get('/notifications', async (req: AuthRequest, res: Response) => { router.put('/notifications', async (req: AuthRequest, res: Response) => { try { const userId = req.userId!; - const { telegram_bot_token, telegram_chat_id, discord_webhook_url, pushover_user_key, pushover_app_token } = req.body; + const { + telegram_bot_token, + telegram_chat_id, + telegram_enabled, + discord_webhook_url, + discord_enabled, + pushover_user_key, + pushover_app_token, + pushover_enabled, + } = req.body; const settings = await userQueries.updateNotificationSettings(userId, { telegram_bot_token, telegram_chat_id, + telegram_enabled, discord_webhook_url, + discord_enabled, pushover_user_key, pushover_app_token, + pushover_enabled, }); if (!settings) { @@ -53,8 +68,11 @@ router.put('/notifications', async (req: AuthRequest, res: Response) => { res.json({ telegram_configured: !!(settings.telegram_bot_token && settings.telegram_chat_id), telegram_chat_id: settings.telegram_chat_id, + telegram_enabled: settings.telegram_enabled ?? true, discord_configured: !!settings.discord_webhook_url, + discord_enabled: settings.discord_enabled ?? true, pushover_configured: !!(settings.pushover_user_key && settings.pushover_app_token), + pushover_enabled: settings.pushover_enabled ?? true, message: 'Notification settings updated successfully', }); } catch (error) { diff --git a/backend/src/services/notifications.ts b/backend/src/services/notifications.ts index 5e2ba9f..3973164 100644 --- a/backend/src/services/notifications.ts +++ b/backend/src/services/notifications.ts @@ -187,25 +187,29 @@ export async function sendNotifications( settings: { telegram_bot_token: string | null; telegram_chat_id: string | null; + telegram_enabled?: boolean; discord_webhook_url: string | null; + discord_enabled?: boolean; pushover_user_key: string | null; pushover_app_token: string | null; + pushover_enabled?: boolean; }, payload: NotificationPayload ): Promise { const promises: Promise[] = []; - if (settings.telegram_bot_token && settings.telegram_chat_id) { + // Only send if channel is configured AND enabled (default to true if not specified) + if (settings.telegram_bot_token && settings.telegram_chat_id && settings.telegram_enabled !== false) { promises.push( sendTelegramNotification(settings.telegram_bot_token, settings.telegram_chat_id, payload) ); } - if (settings.discord_webhook_url) { + if (settings.discord_webhook_url && settings.discord_enabled !== false) { promises.push(sendDiscordNotification(settings.discord_webhook_url, payload)); } - if (settings.pushover_user_key && settings.pushover_app_token) { + if (settings.pushover_user_key && settings.pushover_app_token && settings.pushover_enabled !== false) { promises.push( sendPushoverNotification(settings.pushover_user_key, settings.pushover_app_token, payload) ); diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index 259e610..3c3f0d6 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -126,8 +126,11 @@ export const pricesApi = { export interface NotificationSettings { telegram_configured: boolean; telegram_chat_id: string | null; + telegram_enabled: boolean; discord_configured: boolean; + discord_enabled: boolean; pushover_configured: boolean; + pushover_enabled: boolean; } export const settingsApi = { @@ -137,9 +140,12 @@ export const settingsApi = { updateNotifications: (data: { telegram_bot_token?: string | null; telegram_chat_id?: string | null; + telegram_enabled?: boolean; discord_webhook_url?: string | null; + discord_enabled?: boolean; pushover_user_key?: string | null; pushover_app_token?: string | null; + pushover_enabled?: boolean; }) => api.put('/settings/notifications', data), testTelegram: () => diff --git a/frontend/src/pages/ProductDetail.tsx b/frontend/src/pages/ProductDetail.tsx index 49e553c..a45436c 100644 --- a/frontend/src/pages/ProductDetail.tsx +++ b/frontend/src/pages/ProductDetail.tsx @@ -521,7 +521,11 @@ export default function ProductDetail() { onRangeChange={handleRangeChange} /> - {notificationSettings && (notificationSettings.telegram_configured || notificationSettings.discord_configured || notificationSettings.pushover_configured) && ( + {notificationSettings && ( + (notificationSettings.telegram_configured && notificationSettings.telegram_enabled) || + (notificationSettings.discord_configured && notificationSettings.discord_enabled) || + (notificationSettings.pushover_configured && notificationSettings.pushover_enabled) + ) && ( <>