mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-16 11:23:10 +02:00
Add Telegram bot integration for pipeline processing (#5185)
# Description of Changes This pull request introduces Telegram bot integration to the application, enabling users to send files via Telegram for processing through the pipeline. The main changes add configuration options, dependency management, and a new service for handling Telegram interactions. **Telegram bot integration:** * Added a new `TelegramPipelineBot` service (`TelegramPipelineBot.java`) that listens for incoming Telegram messages, downloads attached files or photos, places them in a pipeline inbox folder, waits for processing results, and sends the output files back to the user. The service includes error handling and status messaging. * Introduced a `TelegramBotConfig` configuration class to initialize and register the Telegram bot only when enabled via application properties. * Added a new `Telegram` configuration section to `ApplicationProperties` and the `settings.yml.template`, supporting options like enabling/disabling the bot, bot token/username, pipeline folder, processing timeout, and polling interval. [[1]](diffhunk://#diff-1c357db0a3e88cf5bedd4a5852415fadad83b8b3b9eb56e67059d8b9d8b10702R63) [[2]](diffhunk://#diff-1c357db0a3e88cf5bedd4a5852415fadad83b8b3b9eb56e67059d8b9d8b10702R580-R589) [[3]](diffhunk://#diff-12f23603ae35319a3ea08f91b6340d5d935216941fda2e69d2df1b6cd22a63f2R108-R115) **Dependency management:** * Added the `org.telegram:telegrambots` library to the project dependencies to support Telegram bot functionality. --- ## Checklist ### General - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md) (if applicable) - [ ] I have performed a self-review of my own code - [ ] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing) for more details. --------- Co-authored-by: Copilot <[email protected]> Co-authored-by: Anthony Stirling <[email protected]>
This commit is contained in:
co-authored by
Copilot
Anthony Stirling
parent
83e96a9aa3
commit
e7b030e6b5
+94
-7
@@ -10,14 +10,38 @@ import { useAdminSettings } from '@app/hooks/useAdminSettings';
|
||||
import PendingBadge from '@app/components/shared/config/PendingBadge';
|
||||
import { Z_INDEX_CONFIG_MODAL } from '@app/styles/zIndex';
|
||||
import ProviderCard from '@app/components/shared/config/configSections/ProviderCard';
|
||||
import {
|
||||
ALL_PROVIDERS,
|
||||
Provider,
|
||||
} from '@app/components/shared/config/configSections/providerDefinitions';
|
||||
import { Provider, useAllProviders } from '@app/components/shared/config/configSections/providerDefinitions';
|
||||
import apiClient from '@app/services/apiClient';
|
||||
import { useLoginRequired } from '@app/hooks/useLoginRequired';
|
||||
import LoginRequiredBanner from '@app/components/shared/config/LoginRequiredBanner';
|
||||
|
||||
interface FeedbackFlags {
|
||||
noValidDocument?: boolean;
|
||||
errorProcessing?: boolean;
|
||||
errorMessage?: boolean;
|
||||
}
|
||||
|
||||
interface FeedbackSettings {
|
||||
general?: { enabled?: boolean };
|
||||
channel?: FeedbackFlags;
|
||||
user?: FeedbackFlags;
|
||||
}
|
||||
|
||||
interface TelegramSettingsData {
|
||||
enabled?: boolean;
|
||||
botToken?: string;
|
||||
botUsername?: string;
|
||||
pipelineInboxFolder?: string;
|
||||
customFolderSuffix?: boolean;
|
||||
enableAllowUserIDs?: boolean;
|
||||
allowUserIDs?: number[];
|
||||
enableAllowChannelIDs?: boolean;
|
||||
allowChannelIDs?: number[];
|
||||
processingTimeoutSeconds?: number;
|
||||
pollingIntervalMillis?: number;
|
||||
feedback?: FeedbackSettings;
|
||||
}
|
||||
|
||||
interface ConnectionsSettingsData {
|
||||
oauth2?: {
|
||||
enabled?: boolean;
|
||||
@@ -45,6 +69,7 @@ interface ConnectionsSettingsData {
|
||||
password?: string;
|
||||
from?: string;
|
||||
};
|
||||
telegram?: TelegramSettingsData;
|
||||
ssoAutoLogin?: boolean;
|
||||
enableMobileScanner?: boolean;
|
||||
mobileScannerConvertToPdf?: boolean;
|
||||
@@ -58,6 +83,7 @@ export default function AdminConnectionsSection() {
|
||||
const navigate = useNavigate();
|
||||
const { loginEnabled, validateLoginEnabled, getDisabledStyles } = useLoginRequired();
|
||||
const { restartModalOpened, showRestartModal, closeRestartModal, restartServer } = useRestartServer();
|
||||
const allProviders = useAllProviders();
|
||||
|
||||
const adminSettings = useAdminSettings<ConnectionsSettingsData>({
|
||||
sectionName: 'connections',
|
||||
@@ -74,6 +100,10 @@ export default function AdminConnectionsSection() {
|
||||
const premiumResponse = await apiClient.get('/api/v1/admin/settings/section/premium');
|
||||
const premiumData = premiumResponse.data || {};
|
||||
|
||||
// Fetch Telegram settings
|
||||
const telegramResponse = await apiClient.get('/api/v1/admin/settings/section/telegram');
|
||||
const telegramData = telegramResponse.data || {};
|
||||
|
||||
// Fetch system settings for enableMobileScanner
|
||||
const systemResponse = await apiClient.get('/api/v1/admin/settings/section/system');
|
||||
const systemData = systemResponse.data || {};
|
||||
@@ -82,6 +112,7 @@ export default function AdminConnectionsSection() {
|
||||
oauth2: securityData.oauth2 || {},
|
||||
saml2: securityData.saml2 || {},
|
||||
mail: mailData || {},
|
||||
telegram: telegramData || {},
|
||||
ssoAutoLogin: premiumData.proFeatures?.ssoAutoLogin || false,
|
||||
enableMobileScanner: systemData.enableMobileScanner || false,
|
||||
mobileScannerConvertToPdf: systemData.mobileScannerSettings?.convertToPdf !== false,
|
||||
@@ -101,6 +132,9 @@ export default function AdminConnectionsSection() {
|
||||
if (mailData._pending) {
|
||||
pendingBlock.mail = mailData._pending;
|
||||
}
|
||||
if (telegramData._pending) {
|
||||
pendingBlock.telegram = telegramData._pending;
|
||||
}
|
||||
if (premiumData._pending?.proFeatures?.ssoAutoLogin !== undefined) {
|
||||
pendingBlock.ssoAutoLogin = premiumData._pending.proFeatures.ssoAutoLogin;
|
||||
}
|
||||
@@ -162,6 +196,10 @@ export default function AdminConnectionsSection() {
|
||||
return settings?.mail?.enabled === true;
|
||||
}
|
||||
|
||||
if (provider.id === 'telegram') {
|
||||
return settings?.telegram?.enabled === true;
|
||||
}
|
||||
|
||||
if (provider.id === 'oauth2-generic') {
|
||||
return settings?.oauth2?.enabled === true;
|
||||
}
|
||||
@@ -180,6 +218,10 @@ export default function AdminConnectionsSection() {
|
||||
return settings?.mail || {};
|
||||
}
|
||||
|
||||
if (provider.id === 'telegram') {
|
||||
return settings?.telegram || {};
|
||||
}
|
||||
|
||||
if (provider.id === 'oauth2-generic') {
|
||||
// Generic OAuth2 settings are at the root oauth2 level
|
||||
return {
|
||||
@@ -210,6 +252,35 @@ export default function AdminConnectionsSection() {
|
||||
// Mail settings use a different endpoint
|
||||
const response = await apiClient.put('/api/v1/admin/settings/section/mail', providerSettings);
|
||||
|
||||
if (response.status === 200) {
|
||||
await fetchSettings(); // Refresh settings
|
||||
alert({
|
||||
alertType: 'success',
|
||||
title: t('admin.success', 'Success'),
|
||||
body: t('admin.settings.saveSuccess', 'Settings saved successfully'),
|
||||
});
|
||||
showRestartModal();
|
||||
} else {
|
||||
throw new Error('Failed to save');
|
||||
}
|
||||
} else if (provider.id === 'telegram') {
|
||||
const parseToNumberArray = (values: any) =>
|
||||
(Array.isArray(values) ? values : [])
|
||||
.map((value) => Number(value))
|
||||
.filter((value) => !Number.isNaN(value));
|
||||
|
||||
const response = await apiClient.put('/api/v1/admin/settings/section/telegram', {
|
||||
...providerSettings,
|
||||
allowUserIDs: parseToNumberArray(providerSettings.allowUserIDs),
|
||||
allowChannelIDs: parseToNumberArray(providerSettings.allowChannelIDs),
|
||||
processingTimeoutSeconds: providerSettings.processingTimeoutSeconds
|
||||
? Number(providerSettings.processingTimeoutSeconds)
|
||||
: undefined,
|
||||
pollingIntervalMillis: providerSettings.pollingIntervalMillis
|
||||
? Number(providerSettings.pollingIntervalMillis)
|
||||
: undefined,
|
||||
});
|
||||
|
||||
if (response.status === 200) {
|
||||
await fetchSettings(); // Refresh settings
|
||||
alert({
|
||||
@@ -271,11 +342,27 @@ export default function AdminConnectionsSection() {
|
||||
return;
|
||||
}
|
||||
|
||||
try{
|
||||
try {
|
||||
if (provider.id === 'smtp') {
|
||||
// Mail settings use a different endpoint
|
||||
const response = await apiClient.put('/api/v1/admin/settings/section/mail', { enabled: false });
|
||||
|
||||
if (response.status === 200) {
|
||||
await fetchSettings();
|
||||
alert({
|
||||
alertType: 'success',
|
||||
title: t('admin.success', 'Success'),
|
||||
body: t('admin.settings.connections.disconnected', 'Provider disconnected successfully'),
|
||||
});
|
||||
showRestartModal();
|
||||
} else {
|
||||
throw new Error('Failed to disconnect');
|
||||
}
|
||||
} else if (provider.id === 'telegram') {
|
||||
const response = await apiClient.put('/api/v1/admin/settings/section/telegram', {
|
||||
enabled: false,
|
||||
});
|
||||
|
||||
if (response.status === 200) {
|
||||
await fetchSettings();
|
||||
alert({
|
||||
@@ -425,8 +512,8 @@ export default function AdminConnectionsSection() {
|
||||
}
|
||||
};
|
||||
|
||||
const linkedProviders = ALL_PROVIDERS.filter((p) => isProviderConfigured(p));
|
||||
const availableProviders = ALL_PROVIDERS.filter((p) => !isProviderConfigured(p));
|
||||
const linkedProviders = allProviders.filter((p) => isProviderConfigured(p));
|
||||
const availableProviders = allProviders.filter((p) => !isProviderConfigured(p));
|
||||
|
||||
return (
|
||||
<Stack gap="xl">
|
||||
|
||||
Reference in New Issue
Block a user