feat: add Telegram notification provider support

- Updated API to support Telegram as a notification provider type.
- Enhanced tests to cover Telegram provider creation, updates, and token handling.
- Modified frontend forms to include Telegram-specific fields and validation.
- Added localization strings for Telegram provider.
- Implemented security measures to ensure bot tokens are not exposed in API responses.
This commit is contained in:
GitHub Actions
2026-03-10 12:14:57 +00:00
parent 317bff326b
commit ef71f66029
26 changed files with 1884 additions and 366 deletions

View File

@@ -54,7 +54,8 @@ describe('notifications api', () => {
await expect(createProvider({ name: 'x', type: 'slack' })).rejects.toThrow('Unsupported notification provider type: slack')
await expect(updateProvider('2', { name: 'updated', type: 'generic' })).rejects.toThrow('Unsupported notification provider type: generic')
await expect(testProvider({ id: '2', name: 'test', type: 'telegram' })).rejects.toThrow('Unsupported notification provider type: telegram')
await testProvider({ id: '2', name: 'test', type: 'telegram' })
expect(client.post).toHaveBeenCalledWith('/notifications/providers/test', { id: '2', name: 'test', type: 'telegram' })
})
it('templates and previews use merged payloads', async () => {

View File

@@ -119,7 +119,52 @@ describe('notifications api', () => {
await expect(createProvider({ name: 'Bad', type: 'slack' })).rejects.toThrow('Unsupported notification provider type: slack')
await expect(updateProvider('bad', { type: 'generic' })).rejects.toThrow('Unsupported notification provider type: generic')
await expect(testProvider({ id: 'bad', type: 'telegram' })).rejects.toThrow('Unsupported notification provider type: telegram')
})
it('supports telegram provider with token payload contract', async () => {
mockedClient.post.mockResolvedValue({ data: { id: 'tg1' } })
mockedClient.put.mockResolvedValue({ data: { id: 'tg1' } })
await createProvider({ name: 'Telegram', type: 'telegram', gotify_token: 'bot123:ABC' })
expect(mockedClient.post).toHaveBeenCalledWith('/notifications/providers', {
name: 'Telegram',
type: 'telegram',
token: 'bot123:ABC',
})
await updateProvider('tg1', { type: 'telegram', url: '987654321', gotify_token: 'newtoken' })
expect(mockedClient.put).toHaveBeenCalledWith('/notifications/providers/tg1', {
type: 'telegram',
url: '987654321',
token: 'newtoken',
})
await updateProvider('tg1', { type: 'telegram', url: '987654321' })
expect(mockedClient.put).toHaveBeenCalledWith('/notifications/providers/tg1', {
type: 'telegram',
url: '987654321',
})
})
it('telegram preserves token in sanitization and strips gotify_token key', async () => {
mockedClient.post.mockResolvedValue({ data: { id: 'tg2' } })
await createProvider({ name: 'TG', type: 'telegram', token: 'direct-token', gotify_token: '' })
expect(mockedClient.post).toHaveBeenCalledWith('/notifications/providers', {
name: 'TG',
type: 'telegram',
token: 'direct-token',
})
})
it('telegram test/preview strips token from read-like actions', async () => {
mockedClient.post.mockResolvedValue({ data: { id: 'tg3' } })
await testProvider({ id: 'tg3', type: 'telegram', gotify_token: 'should-not-send' })
expect(mockedClient.post).toHaveBeenCalledWith('/notifications/providers/test', {
id: 'tg3',
type: 'telegram',
})
})
it('fetches templates and previews provider payloads with data', async () => {

View File

@@ -1,6 +1,6 @@
import client from './client';
export const SUPPORTED_NOTIFICATION_PROVIDER_TYPES = ['discord', 'gotify', 'webhook', 'email'] as const;
export const SUPPORTED_NOTIFICATION_PROVIDER_TYPES = ['discord', 'gotify', 'webhook', 'email', 'telegram'] as const;
export type SupportedNotificationProviderType = (typeof SUPPORTED_NOTIFICATION_PROVIDER_TYPES)[number];
const DEFAULT_PROVIDER_TYPE: SupportedNotificationProviderType = 'discord';
@@ -59,7 +59,7 @@ const sanitizeProviderForWriteAction = (data: Partial<NotificationProvider>): Pa
delete payload.gotify_token;
if (type !== 'gotify') {
if (type !== 'gotify' && type !== 'telegram') {
delete payload.token;
return payload;
}