Make Telegram chat_id per-company, bot token stays global

Each company can now have its own Telegram channel/group for alerts.
- Bot token: global (superadmin only, shared across companies)
- Chat ID: per-company (stored in integrations table config)
- sendTelegramAlert reads chat_id from company integration
- Test message shows company name
- Non-superadmin users can't see/edit bot token

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-13 19:05:57 +02:00
parent bbfff2f8b5
commit 20a2b78782
3 changed files with 40 additions and 14 deletions

43
api.php
View File

@@ -905,16 +905,26 @@ class ImapClient {
// ==================== TICKETS HELPER ==================== // ==================== TICKETS HELPER ====================
function sendTelegramAlert(string $companyId, array $ticket): void { function sendTelegramAlert(string $companyId, array $ticket): void {
// Bot token on globaali, chat_id on yrityskohtainen
$config = dbLoadConfig(); $config = dbLoadConfig();
$botToken = $config['telegram_bot_token'] ?? ''; $botToken = $config['telegram_bot_token'] ?? '';
$chatId = $config['telegram_chat_id'] ?? ''; if (!$botToken) return;
if (!$botToken || !$chatId) return;
// Hae yrityskohtainen chat_id integraation configista
$integ = dbGetIntegration($companyId, 'telegram');
if (!$integ || !$integ['enabled']) return;
$chatId = $integ['config']['chat_id'] ?? '';
if (!$chatId) return;
// Hae yrityksen nimi
$company = dbGetCompany($companyId);
$companyName = $company['nimi'] ?? $companyId;
$text = "🚨 *URGENT TIKETTI*\n\n"; $text = "🚨 *URGENT TIKETTI*\n\n";
$text .= "📋 *" . ($ticket['subject'] ?? '(Ei aihetta)') . "*\n"; $text .= "📋 *" . ($ticket['subject'] ?? '(Ei aihetta)') . "*\n";
$text .= "👤 " . ($ticket['from_name'] ?? $ticket['from_email'] ?? 'Tuntematon') . "\n"; $text .= "👤 " . ($ticket['from_name'] ?? $ticket['from_email'] ?? 'Tuntematon') . "\n";
$text .= "📧 " . ($ticket['from_email'] ?? '') . "\n"; $text .= "📧 " . ($ticket['from_email'] ?? '') . "\n";
$text .= "🏢 " . $companyId . "\n"; $text .= "🏢 " . $companyName . "\n";
$text .= "🕐 " . date('d.m.Y H:i'); $text .= "🕐 " . date('d.m.Y H:i');
$url = "https://api.telegram.org/bot{$botToken}/sendMessage"; $url = "https://api.telegram.org/bot{$botToken}/sendMessage";
@@ -1367,11 +1377,14 @@ switch ($action) {
requireAuth(); requireAuth();
$companyId = requireCompany(); $companyId = requireCompany();
$globalConf = dbLoadConfig(); $globalConf = dbLoadConfig();
// Telegram chat_id on yrityskohtainen
$teleInteg = dbGetIntegration($companyId, 'telegram');
$teleChatId = ($teleInteg && $teleInteg['config']) ? ($teleInteg['config']['chat_id'] ?? '') : '';
echo json_encode([ echo json_encode([
'api_key' => dbGetCompanyApiKey($companyId), 'api_key' => dbGetCompanyApiKey($companyId),
'cors_origins' => dbGetCompanyCorsOrigins($companyId), 'cors_origins' => dbGetCompanyCorsOrigins($companyId),
'telegram_bot_token' => $globalConf['telegram_bot_token'] ?? '', 'telegram_bot_token' => $globalConf['telegram_bot_token'] ?? '',
'telegram_chat_id' => $globalConf['telegram_chat_id'] ?? '', 'telegram_chat_id' => $teleChatId,
]); ]);
break; break;
@@ -1387,12 +1400,17 @@ switch ($action) {
$origins = array_filter(array_map('trim', explode("\n", $input['cors_origins']))); $origins = array_filter(array_map('trim', explode("\n", $input['cors_origins'])));
dbSetCompanyCorsOrigins($companyId, array_values($origins)); dbSetCompanyCorsOrigins($companyId, array_values($origins));
} }
// Telegram-asetukset (globaalit, tallennetaan config-tauluun) // Telegram Bot Token: globaali (vain superadmin voi muuttaa)
if (isset($input['telegram_bot_token'])) { if (isset($input['telegram_bot_token']) && ($_SESSION['role'] ?? '') === 'superadmin') {
dbSaveConfig(['telegram_bot_token' => trim($input['telegram_bot_token'])]); dbSaveConfig(['telegram_bot_token' => trim($input['telegram_bot_token'])]);
} }
// Telegram Chat ID: yrityskohtainen (tallennetaan integrations-tauluun)
if (isset($input['telegram_chat_id'])) { if (isset($input['telegram_chat_id'])) {
dbSaveConfig(['telegram_chat_id' => trim($input['telegram_chat_id'])]); $teleInteg = dbGetIntegration($companyId, 'telegram');
$teleConfig = ($teleInteg && $teleInteg['config']) ? $teleInteg['config'] : [];
$teleConfig['chat_id'] = trim($input['telegram_chat_id']);
$teleEnabled = $teleInteg ? $teleInteg['enabled'] : false;
dbSaveIntegration($companyId, 'telegram', $teleEnabled, $teleConfig);
} }
dbAddLog($companyId, currentUser(), 'config_update', '', '', 'Päivitti asetuksia'); dbAddLog($companyId, currentUser(), 'config_update', '', '', 'Päivitti asetuksia');
echo json_encode([ echo json_encode([
@@ -1403,17 +1421,22 @@ switch ($action) {
case 'telegram_test': case 'telegram_test':
requireAdmin(); requireAdmin();
$companyId = requireCompany();
if ($method !== 'POST') break; if ($method !== 'POST') break;
$config = dbLoadConfig(); $config = dbLoadConfig();
$botToken = $config['telegram_bot_token'] ?? ''; $botToken = $config['telegram_bot_token'] ?? '';
$chatId = $config['telegram_chat_id'] ?? ''; // Chat ID yrityskohtainen
$teleInteg = dbGetIntegration($companyId, 'telegram');
$chatId = ($teleInteg && $teleInteg['config']) ? ($teleInteg['config']['chat_id'] ?? '') : '';
if (!$botToken || !$chatId) { if (!$botToken || !$chatId) {
http_response_code(400); http_response_code(400);
echo json_encode(['error' => 'Telegram Bot Token ja Chat ID vaaditaan']); echo json_encode(['error' => 'Telegram Bot Token (globaali) ja Chat ID (yrityskohtainen) vaaditaan']);
break; break;
} }
$company = dbGetCompany($companyId);
$companyName = $company['nimi'] ?? $companyId;
$url = "https://api.telegram.org/bot{$botToken}/sendMessage"; $url = "https://api.telegram.org/bot{$botToken}/sendMessage";
$data = ['chat_id' => $chatId, 'text' => '✅ Noxus HUB Telegram-hälytys toimii!', 'parse_mode' => 'Markdown']; $data = ['chat_id' => $chatId, 'text' => "✅ Noxus HUB Telegram-hälytys toimii!\n🏢 $companyName", 'parse_mode' => 'Markdown'];
$ch = curl_init($url); $ch = curl_init($url);
curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode($data), CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 5]); curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode($data), CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 5]);
$resp = curl_exec($ch); $resp = curl_exec($ch);

View File

@@ -1571,14 +1571,14 @@
<!-- Telegram-asetukset --> <!-- Telegram-asetukset -->
<div class="table-card" id="settings-telegram-card" style="padding:1.5rem;margin-top:1rem;display:none;"> <div class="table-card" id="settings-telegram-card" style="padding:1.5rem;margin-top:1rem;display:none;">
<h3 style="color:#0f3460;margin-bottom:0.5rem;border-bottom:2px solid #f0f2f5;padding-bottom:0.5rem;">Telegram-hälytykset</h3> <h3 style="color:#0f3460;margin-bottom:0.5rem;border-bottom:2px solid #f0f2f5;padding-bottom:0.5rem;">Telegram-hälytykset</h3>
<p style="color:#666;font-size:0.85rem;margin-bottom:1rem;">URGENT-prioriteetin tiketit lähettävät hälytyksen Telegram-bottiin.</p> <p style="color:#666;font-size:0.85rem;margin-bottom:1rem;">URGENT-prioriteetin tiketit lähettävät hälytyksen Telegram-kanavalle. Chat ID on yrityskohtainen — eri yritykset voivat käyttää eri kanavia.</p>
<div class="form-grid" style="max-width:500px;"> <div class="form-grid" style="max-width:500px;">
<div class="form-group full-width"> <div class="form-group full-width" id="telegram-token-group">
<label>Bot Token</label> <label>Bot Token <span style="color:#888;font-weight:normal;font-size:0.8rem;">(globaali, kaikille yrityksille sama)</span></label>
<input type="text" id="settings-telegram-token" placeholder="123456:ABC-DEF..." style="font-family:monospace;"> <input type="text" id="settings-telegram-token" placeholder="123456:ABC-DEF..." style="font-family:monospace;">
</div> </div>
<div class="form-group full-width"> <div class="form-group full-width">
<label>Chat ID</label> <label>Chat ID <span style="color:#888;font-weight:normal;font-size:0.8rem;">(yrityskohtainen kanava/ryhmä)</span></label>
<input type="text" id="settings-telegram-chat" placeholder="-1001234567890" style="font-family:monospace;"> <input type="text" id="settings-telegram-chat" placeholder="-1001234567890" style="font-family:monospace;">
</div> </div>
<div class="form-group full-width" style="display:flex;gap:0.5rem;"> <div class="form-group full-width" style="display:flex;gap:0.5rem;">

View File

@@ -2738,6 +2738,9 @@ async function loadSettings() {
// Telegram-asetukset // Telegram-asetukset
document.getElementById('settings-telegram-token').value = config.telegram_bot_token || ''; document.getElementById('settings-telegram-token').value = config.telegram_bot_token || '';
document.getElementById('settings-telegram-chat').value = config.telegram_chat_id || ''; document.getElementById('settings-telegram-chat').value = config.telegram_chat_id || '';
// Bot Token vain superadminille
const tokenGroup = document.getElementById('telegram-token-group');
if (tokenGroup) tokenGroup.style.display = currentUser?.role === 'superadmin' ? '' : 'none';
} catch (e) { console.error(e); } } catch (e) { console.error(e); }
// Lataa saatavuuskyselyt // Lataa saatavuuskyselyt