Add Telegram notification integration for geofencing
Features: - Multi-channel notifications (Email + Telegram) - User-configurable notification settings per channel - Telegram bot integration with rich messages, location pins, and inline buttons - QR code generation for easy bot access (@myidbot support) - Admin UI for notification settings management - Test functionality for Telegram connection - Comprehensive documentation Implementation: - lib/telegram-service.ts: Telegram API integration - lib/notification-settings-db.ts: Database layer for user notification preferences - lib/geofence-notifications.ts: Extended for parallel multi-channel delivery - API routes for settings management and testing - Admin UI with QR code display and step-by-step instructions - Database table: UserNotificationSettings Documentation: - docs/telegram.md: Technical implementation guide - docs/telegram-anleitung.md: User guide with @myidbot instructions - docs/telegram-setup.md: Admin setup guide - README.md: Updated NPM scripts section Docker: - Updated Dockerfile to copy public directory - Added TELEGRAM_BOT_TOKEN environment variable - Integrated notification settings initialization in db:init 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
40
scripts/generate-telegram-qr.js
Executable file
40
scripts/generate-telegram-qr.js
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Generate QR Code for Telegram Bot
|
||||
*/
|
||||
|
||||
const QRCode = require('qrcode');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const BOT_URL = 'https://t.me/MeinTracking_bot';
|
||||
const OUTPUT_DIR = path.join(process.cwd(), 'public');
|
||||
const OUTPUT_FILE = path.join(OUTPUT_DIR, 'telegram-bot-qr.png');
|
||||
|
||||
async function generateQR() {
|
||||
try {
|
||||
// Ensure public directory exists
|
||||
if (!fs.existsSync(OUTPUT_DIR)) {
|
||||
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
// Generate QR Code
|
||||
await QRCode.toFile(OUTPUT_FILE, BOT_URL, {
|
||||
width: 400,
|
||||
margin: 2,
|
||||
color: {
|
||||
dark: '#000000',
|
||||
light: '#FFFFFF'
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`✅ QR Code generated: ${OUTPUT_FILE}`);
|
||||
console.log(`📱 Bot URL: ${BOT_URL}`);
|
||||
console.log(`🖼️ QR Code size: 400x400px`);
|
||||
} catch (error) {
|
||||
console.error('❌ Error generating QR Code:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
generateQR();
|
||||
38
scripts/init-notification-settings.js
Executable file
38
scripts/init-notification-settings.js
Executable file
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Initialize UserNotificationSettings table
|
||||
*/
|
||||
|
||||
const Database = require('better-sqlite3');
|
||||
const path = require('path');
|
||||
|
||||
const dbPath = path.join(process.cwd(), 'data', 'database.sqlite');
|
||||
|
||||
try {
|
||||
const db = new Database(dbPath);
|
||||
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS UserNotificationSettings (
|
||||
user_id TEXT PRIMARY KEY,
|
||||
email_enabled INTEGER DEFAULT 1,
|
||||
telegram_enabled INTEGER DEFAULT 0,
|
||||
telegram_chat_id TEXT,
|
||||
created_at TEXT DEFAULT (datetime('now')),
|
||||
updated_at TEXT DEFAULT (datetime('now')),
|
||||
|
||||
FOREIGN KEY (user_id) REFERENCES User(id) ON DELETE CASCADE,
|
||||
CHECK (email_enabled IN (0, 1)),
|
||||
CHECK (telegram_enabled IN (0, 1))
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_user_notification_settings_user
|
||||
ON UserNotificationSettings(user_id);
|
||||
`);
|
||||
|
||||
db.close();
|
||||
|
||||
console.log('✅ Notification settings table initialized!');
|
||||
} catch (error) {
|
||||
console.error('❌ Error:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
56
scripts/test-telegram-token.js
Executable file
56
scripts/test-telegram-token.js
Executable file
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Test Telegram Bot Token
|
||||
*/
|
||||
|
||||
const axios = require('axios');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// Read .env manually
|
||||
const envPath = path.join(process.cwd(), '.env');
|
||||
const envContent = fs.readFileSync(envPath, 'utf-8');
|
||||
const BOT_TOKEN = envContent
|
||||
.split('\n')
|
||||
.find(line => line.startsWith('TELEGRAM_BOT_TOKEN='))
|
||||
?.split('=')[1]
|
||||
?.trim();
|
||||
|
||||
async function testToken() {
|
||||
if (!BOT_TOKEN) {
|
||||
console.error('❌ TELEGRAM_BOT_TOKEN not found in .env');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log('🧪 Testing Telegram Bot Token...\n');
|
||||
console.log(`Token: ${BOT_TOKEN.substring(0, 15)}...`);
|
||||
|
||||
try {
|
||||
const response = await axios.get(`https://api.telegram.org/bot${BOT_TOKEN}/getMe`);
|
||||
|
||||
if (response.data.ok) {
|
||||
const bot = response.data.result;
|
||||
console.log('\n✅ Bot Token is VALID!\n');
|
||||
console.log('📱 Bot Information:');
|
||||
console.log(` ID: ${bot.id}`);
|
||||
console.log(` Name: ${bot.first_name}`);
|
||||
console.log(` Username: @${bot.username}`);
|
||||
console.log(` Can Join Groups: ${bot.can_join_groups}`);
|
||||
console.log(` Can Read Messages: ${bot.can_read_all_group_messages}`);
|
||||
console.log('\n🔗 Bot Link: https://t.me/' + bot.username);
|
||||
} else {
|
||||
console.error('❌ Invalid response:', response.data);
|
||||
process.exit(1);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('\n❌ Token test FAILED!');
|
||||
if (error.response) {
|
||||
console.error('Error:', error.response.data.description);
|
||||
} else {
|
||||
console.error('Error:', error.message);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
testToken();
|
||||
Reference in New Issue
Block a user