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:
75
app/api/users/[id]/notification-settings/route.ts
Normal file
75
app/api/users/[id]/notification-settings/route.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { auth } from '@/lib/auth';
|
||||
import {
|
||||
getUserNotificationSettings,
|
||||
updateUserNotificationSettings,
|
||||
} from '@/lib/notification-settings-db';
|
||||
|
||||
// GET /api/users/[id]/notification-settings
|
||||
export async function GET(
|
||||
request: Request,
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
try {
|
||||
const session = await auth();
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||
}
|
||||
|
||||
const { id: userId } = await params;
|
||||
const currentUserId = (session.user as any).id;
|
||||
|
||||
// Users can only view their own settings
|
||||
if (userId !== currentUserId) {
|
||||
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
|
||||
}
|
||||
|
||||
const settings = getUserNotificationSettings(userId);
|
||||
|
||||
return NextResponse.json({ settings });
|
||||
} catch (error) {
|
||||
console.error('[GET /api/users/[id]/notification-settings]', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to get settings' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// PATCH /api/users/[id]/notification-settings
|
||||
export async function PATCH(
|
||||
request: Request,
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
try {
|
||||
const session = await auth();
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||
}
|
||||
|
||||
const { id: userId } = await params;
|
||||
const currentUserId = (session.user as any).id;
|
||||
|
||||
// Users can only update their own settings
|
||||
if (userId !== currentUserId) {
|
||||
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
|
||||
}
|
||||
|
||||
const body = await request.json();
|
||||
const { email_enabled, telegram_enabled, telegram_chat_id } = body;
|
||||
|
||||
const settings = updateUserNotificationSettings(userId, {
|
||||
email_enabled,
|
||||
telegram_enabled,
|
||||
telegram_chat_id,
|
||||
});
|
||||
|
||||
return NextResponse.json({ settings });
|
||||
} catch (error) {
|
||||
console.error('[PATCH /api/users/[id]/notification-settings]', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to update settings' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
52
app/api/users/[id]/notification-settings/test/route.ts
Normal file
52
app/api/users/[id]/notification-settings/test/route.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { auth } from '@/lib/auth';
|
||||
import { telegramService } from '@/lib/telegram-service';
|
||||
import { getUserNotificationSettings } from '@/lib/notification-settings-db';
|
||||
|
||||
// POST /api/users/[id]/notification-settings/test
|
||||
export async function POST(
|
||||
request: Request,
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
try {
|
||||
const session = await auth();
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||
}
|
||||
|
||||
const { id: userId } = await params;
|
||||
const currentUserId = (session.user as any).id;
|
||||
|
||||
if (userId !== currentUserId) {
|
||||
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
|
||||
}
|
||||
|
||||
const settings = getUserNotificationSettings(userId);
|
||||
|
||||
if (!settings.telegram_chat_id) {
|
||||
return NextResponse.json(
|
||||
{ error: 'No Telegram chat ID configured' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
const success = await telegramService.testConnection(
|
||||
settings.telegram_chat_id
|
||||
);
|
||||
|
||||
if (success) {
|
||||
return NextResponse.json({ success: true, message: 'Test message sent' });
|
||||
} else {
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to send test message' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[POST /api/users/[id]/notification-settings/test]', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to send test message' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user