mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-17 11:45:05 +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
@@ -82,7 +82,7 @@ incorrectPasswordMessage = "Das Passwort ist falsch."
|
||||
usernameExistsMessage = "Neuer Benutzername existiert bereits."
|
||||
invalidUsernameMessage = "Ungültiger Benutzername. Der Benutzername darf nur Buchstaben, Zahlen und die folgenden Sonderzeichen @._+- enthalten oder muss eine gültige E-Mail-Adresse sein."
|
||||
invalidPasswordMessage = "Das Passwort darf nicht leer sein und kein Leerzeichen am Anfang und Ende haben."
|
||||
confirmPasswordErrorMessage = "„Neues Passwort“ und „Neues Passwort bestätigen“ müssen übereinstimmen."
|
||||
confirmPasswordErrorMessage = "\"Neues Passwort\" und \"Neues Passwort bestätigen\" müssen übereinstimmen."
|
||||
deleteCurrentUserMessage = "Der aktuell angemeldete Benutzer kann nicht gelöscht werden."
|
||||
deleteUsernameExistsMessage = "Der Benutzername existiert nicht und kann nicht gelöscht werden."
|
||||
downgradeCurrentUserMessage = "Die Rolle des aktuellen Benutzers kann nicht herabgestuft werden"
|
||||
@@ -363,6 +363,7 @@ advanced = "Erweitert"
|
||||
title = "Sicherheit & Authentifizierung"
|
||||
security = "Sicherheit"
|
||||
connections = "Verbindungen"
|
||||
telegram = "Telegram"
|
||||
|
||||
[settings.licensingAnalytics]
|
||||
title = "Lizenzierung & Analytics"
|
||||
@@ -2316,7 +2317,7 @@ colorLabel = "Textfarbe"
|
||||
heading = "Gespeicherte Unterschriften"
|
||||
description = "Gespeicherte Unterschriften jederzeit wiederverwenden."
|
||||
emptyTitle = "Noch keine gespeicherten Unterschriften"
|
||||
emptyDescription = "Zeichnen, laden oder tippen Sie oben eine Unterschrift und wählen Sie dann „In Bibliothek speichern“, um bis zu {{max}} Favoriten bereitzuhalten."
|
||||
emptyDescription = "Zeichnen, laden oder tippen Sie oben eine Unterschrift und wählen Sie dann \"In Bibliothek speichern\", um bis zu {{max}} Favoriten bereitzuhalten."
|
||||
limitTitle = "Limit erreicht"
|
||||
limitDescription = "Entfernen Sie eine gespeicherte Unterschrift, bevor Sie neue hinzufügen (max. {{max}})."
|
||||
carouselPosition = "{{current}} von {{total}}"
|
||||
@@ -2526,7 +2527,7 @@ title = "Über Anmerkungen entfernen"
|
||||
description = "Dieses Werkzeug entfernt alle Anmerkungen (Kommentare, Hervorhebungen, Notizen usw.) aus Ihren PDF-Dokumenten."
|
||||
|
||||
[removeAnnotations.tooltip.header]
|
||||
title = "Über „Anmerkungen entfernen“"
|
||||
title = "Über \"Anmerkungen entfernen\""
|
||||
|
||||
[removeAnnotations.tooltip.description]
|
||||
title = "Funktion"
|
||||
@@ -3849,11 +3850,6 @@ failed = "Ein Fehler ist beim Komprimieren der PDF aufgetreten."
|
||||
_value = "Kompressionseinstellungen"
|
||||
1 = "1-3 PDF-Komprimierung, </br> 4-6 Leichte Bildkomprimierung, </br> 7-9 Intensive Bildkomprimierung verringert die Bildqualität dramatisch"
|
||||
|
||||
[compress.compressionLevel]
|
||||
range1to3 = "Lower values preserve quality but result in larger files"
|
||||
range4to6 = "Medium compression with moderate quality reduction"
|
||||
range7to9 = "Higher values reduce file size significantly but may reduce image clarity"
|
||||
|
||||
[compress.lineArt]
|
||||
description = "Uses ImageMagick to reduce pages to high-contrast black and white for maximum size reduction."
|
||||
detailLevel = "Detail level"
|
||||
@@ -3867,6 +3863,11 @@ unavailable = "ImageMagick is not installed or enabled on this server"
|
||||
[compress.linearize]
|
||||
label = "Linearize PDF for fast web viewing"
|
||||
|
||||
[compress.compressionLevel]
|
||||
range1to3 = "Lower values preserve quality but result in larger files"
|
||||
range4to6 = "Medium compression with moderate quality reduction"
|
||||
range7to9 = "Higher values reduce file size significantly but may reduce image clarity"
|
||||
|
||||
[decrypt]
|
||||
passwordPrompt = "Diese Datei ist passwortgeschützt. Bitte geben Sie das Passwort ein:"
|
||||
cancelled = "Vorgang für PDF abgebrochen: {0}"
|
||||
@@ -4020,7 +4021,7 @@ showPreferencesBtn = "Einstellungen verwalten"
|
||||
|
||||
[cookieBanner.popUp.description]
|
||||
1 = "Wir verwenden Cookies und andere Technologien, damit Stirling PDF für Sie besser funktioniert. Dies hilft uns dabei, unsere Tools zu verbessern und weiterhin Funktionen zu entwickeln, die Ihnen gefallen werden."
|
||||
2 = "Wenn Sie dies nicht möchten, klicken Sie auf „Nein, Danke“. Dadurch werden nur die unbedingt erforderlichen Cookies aktiviert, die für einen reibungslosen Ablauf erforderlich sind."
|
||||
2 = "Wenn Sie dies nicht möchten, klicken Sie auf \"Nein, Danke\". Dadurch werden nur die unbedingt erforderlichen Cookies aktiviert, die für einen reibungslosen Ablauf erforderlich sind."
|
||||
|
||||
[cookieBanner.preferencesModal]
|
||||
title = "Einwilligungszentrum"
|
||||
@@ -4119,13 +4120,13 @@ toggleSidebar = "Seitenleiste umschalten"
|
||||
exportSelected = "Ausgewählte Seiten exportieren"
|
||||
toggleAnnotations = "Anmerkungen ein-/ausblenden"
|
||||
print = "PDF drucken"
|
||||
draw = "Zeichnen"
|
||||
save = "Speichern"
|
||||
saveChanges = "Änderungen speichern"
|
||||
annotations = "Annotations"
|
||||
applyRedactionsFirst = "Apply redactions first"
|
||||
draw = "Draw"
|
||||
exitRedaction = "Exit Redaction Mode"
|
||||
redact = "Redact"
|
||||
save = "Save"
|
||||
|
||||
[search]
|
||||
title = "PDF durchsuchen"
|
||||
@@ -4574,6 +4575,102 @@ pageFormatA4 = "A4 (210×297mm)"
|
||||
pageFormatKeep = "Keep (Original Dimensions)"
|
||||
pageFormatLetter = "Letter (8.5×11in)"
|
||||
|
||||
[admin.settings.telegram]
|
||||
title = "Telegram-Bot"
|
||||
description = "Telegram-Bot-Anbindung, Zugriffskontrollen und Feedback-Verhalten konfigurieren."
|
||||
|
||||
[admin.settings.telegram.enabled]
|
||||
label = "Telegram-Bot aktivieren"
|
||||
description = "Erlaubt Benutzern die Interaktion mit Stirling PDF über den konfigurierten Telegram-Bot."
|
||||
|
||||
[admin.settings.telegram.botUsername]
|
||||
label = "Bot-Benutzername"
|
||||
description = "Der öffentliche Benutzername Ihres Telegram-Bots."
|
||||
|
||||
[admin.settings.telegram.botToken]
|
||||
label = "Bot-Token"
|
||||
description = "API-Token, das von BotFather für Ihren Telegram-Bot bereitgestellt wird."
|
||||
|
||||
[admin.settings.telegram.pipelineInboxFolder]
|
||||
label = "Posteingangsordner"
|
||||
description = "Ordner innerhalb des Pipeline-Verzeichnisses, in dem eingehende Telegram-Dateien gespeichert werden."
|
||||
|
||||
[admin.settings.telegram.customFolderSuffix]
|
||||
label = "Benutzerdefinierten Ordner-Suffix verwenden"
|
||||
description = "Hängt die Chat-ID an eingehende Dateiordner an, um Uploads pro Chat zu isolieren."
|
||||
|
||||
[admin.settings.telegram.accessControl]
|
||||
title = "Zugriffskontrolle"
|
||||
description = "Einschränken, welche Benutzer oder Kanäle mit dem Bot interagieren dürfen."
|
||||
|
||||
[admin.settings.telegram.enableAllowUserIDs]
|
||||
label = "Bestimmte Benutzer-IDs erlauben"
|
||||
description = "Wenn aktiviert, dürfen nur aufgeführte Benutzer-IDs den Bot verwenden."
|
||||
|
||||
[admin.settings.telegram.allowUserIDs]
|
||||
label = "Erlaubte Benutzer-IDs"
|
||||
description = "Telegram-Benutzer-IDs, die mit dem Bot interagieren dürfen."
|
||||
placeholder = "Benutzer-ID hinzufügen und Enter drücken"
|
||||
|
||||
[admin.settings.telegram.enableAllowChannelIDs]
|
||||
label = "Bestimmte Kanal-IDs erlauben"
|
||||
description = "Wenn aktiviert, dürfen nur aufgeführte Kanal-IDs den Bot verwenden."
|
||||
|
||||
[admin.settings.telegram.allowChannelIDs]
|
||||
label = "Erlaubte Kanal-IDs"
|
||||
description = "Telegram-Kanal-IDs, die mit dem Bot interagieren dürfen."
|
||||
placeholder = "Kanal-ID hinzufügen und Enter drücken"
|
||||
|
||||
[admin.settings.telegram.processing]
|
||||
title = "Verarbeitung"
|
||||
description = "Polling-Intervalle und Verarbeitungs-Timeouts für Telegram-Uploads steuern."
|
||||
|
||||
[admin.settings.telegram.processingTimeoutSeconds]
|
||||
label = "Verarbeitungs-Timeout (Sekunden)"
|
||||
description = "Maximale Wartezeit für einen Verarbeitungsjob, bevor ein Fehler gemeldet wird."
|
||||
|
||||
[admin.settings.telegram.pollingIntervalMillis]
|
||||
label = "Polling-Intervall (ms)"
|
||||
description = "Intervall zwischen Prüfungen auf neue Telegram-Updates."
|
||||
|
||||
[admin.settings.telegram.feedback]
|
||||
title = "Feedback-Nachrichten"
|
||||
description = "Festlegen, wann der Bot Feedback an Benutzer und Kanäle senden soll."
|
||||
|
||||
[admin.settings.telegram.feedback.general.enabled]
|
||||
label = "Feedback aktivieren"
|
||||
description = "Legt fest, ob der Bot überhaupt Feedback-Nachrichten sendet."
|
||||
|
||||
[admin.settings.telegram.feedback.channel]
|
||||
title = "Kanal-Feedback-Regeln"
|
||||
|
||||
[admin.settings.telegram.feedback.channel.noValidDocument]
|
||||
label = "\"Kein gültiges Dokument\" einblenden (Kanal)"
|
||||
description = "Sendet die Meldung \"Kein gültiges Dokument\" bei Kanal-Uploads."
|
||||
|
||||
[admin.settings.telegram.feedback.channel.errorProcessing]
|
||||
label = "Verarbeitungsfehler einblenden (Kanal)"
|
||||
description = "Sendet Verarbeitungsfehlermeldungen an Kanäle senden."
|
||||
|
||||
[admin.settings.telegram.feedback.channel.errorMessage]
|
||||
label = "Fehlermeldungen einblenden (Kanal)"
|
||||
description = "Detaillierte Fehlermeldungen für Kanäle einblenden."
|
||||
|
||||
[admin.settings.telegram.feedback.user]
|
||||
title = "Benutzer-Feedback-Regeln"
|
||||
|
||||
[admin.settings.telegram.feedback.user.noValidDocument]
|
||||
label = "\"Kein gültiges Dokument\" einblenden (Benutzer)"
|
||||
description = "Sendet die Meldung \"Kein gültiges Dokument\" bei Benutzer-Uploads."
|
||||
|
||||
[admin.settings.telegram.feedback.user.errorProcessing]
|
||||
label = "Verarbeitungsfehler einblenden (Benutzer)"
|
||||
description = "Sendet Verarbeitungsfehlermeldungen an Benutzer."
|
||||
|
||||
[admin.settings.telegram.feedback.user.errorMessage]
|
||||
label = "Fehlermeldungen einblenden (Benutzer)"
|
||||
description = "Detaillierte Fehlermeldungen für Benutzer einblenden."
|
||||
|
||||
[admin.settings.database]
|
||||
title = "Datenbank"
|
||||
description = "Benutzerdefinierte Datenbankverbindungseinstellungen für Enterprise-Bereitstellungen konfigurieren."
|
||||
@@ -4842,11 +4939,11 @@ description = "Optionale Funktionen und Features konfigurieren."
|
||||
|
||||
[admin.settings.features.serverCertificate]
|
||||
label = "Serverzertifikat"
|
||||
description = "Serverseitige Zertifikatserstellung für die Funktion „Mit Stirling-PDF signieren“ konfigurieren"
|
||||
description = "Serverseitige Zertifikatserstellung für die Funktion \"Mit Stirling-PDF signieren\" konfigurieren"
|
||||
|
||||
[admin.settings.features.serverCertificate.enabled]
|
||||
label = "Serverzertifikat aktivieren"
|
||||
description = "Serverseitiges Zertifikat für die Option „Mit Stirling-PDF signieren“ aktivieren"
|
||||
description = "Serverseitiges Zertifikat für die Option \"Mit Stirling-PDF signieren\" aktivieren"
|
||||
|
||||
[admin.settings.features.serverCertificate.organizationName]
|
||||
label = "Name der Organisation"
|
||||
@@ -5328,13 +5425,13 @@ confirmPrompt = "Sind Sie sicher, dass Sie fortfahren möchten?"
|
||||
confirmCta = "Schlüssel aktualisieren"
|
||||
|
||||
[config.apiKeys.alert]
|
||||
apiKeyErrorTitle = "API-Schlüssel-Fehler"
|
||||
failedToCreateApiKey = "API-Schlüssel konnte nicht erstellt werden."
|
||||
failedToRetrieveApiKey = "API-Schlüssel konnte nicht aus der Antwort abgerufen werden."
|
||||
failedToFetchApiKey = "API-Schlüssel konnte nicht abgerufen werden."
|
||||
apiKeyRefreshed = "API-Schlüssel aktualisiert"
|
||||
apiKeyRefreshedBody = "Ihr API-Schlüssel wurde erfolgreich aktualisiert."
|
||||
failedToRefreshApiKey = "API-Schlüssel konnte nicht aktualisiert werden."
|
||||
apiKeyErrorTitle = "API Key Error"
|
||||
apiKeyRefreshed = "API Key Refreshed"
|
||||
apiKeyRefreshedBody = "Your API key has been successfully refreshed."
|
||||
failedToCreateApiKey = "Failed to create API key."
|
||||
failedToFetchApiKey = "Failed to fetch API key."
|
||||
failedToRefreshApiKey = "Failed to refresh API key."
|
||||
failedToRetrieveApiKey = "Failed to retrieve API key from response."
|
||||
|
||||
[AddAttachmentsRequest]
|
||||
attachments = "Anhänge auswählen"
|
||||
@@ -5346,7 +5443,7 @@ selectedFiles = "Ausgewählte Dateien"
|
||||
submit = "Anhänge hinzufügen"
|
||||
|
||||
[AddAttachmentsRequest.tooltip.header]
|
||||
title = "Über „Anhänge hinzufügen“"
|
||||
title = "Über \"Anhänge hinzufügen\""
|
||||
|
||||
[AddAttachmentsRequest.tooltip.description]
|
||||
title = "Funktion"
|
||||
@@ -5355,7 +5452,7 @@ title = "Funktion"
|
||||
title = "Anhangs-Ergebnisse"
|
||||
|
||||
[AddAttachmentsRequest.error]
|
||||
failed = "Operation „Anhänge hinzufügen“ fehlgeschlagen"
|
||||
failed = "Operation \"Anhänge hinzufügen\" fehlgeschlagen"
|
||||
|
||||
[addAttachments.error]
|
||||
failed = "Beim Hinzufügen von Anhängen zur PDF ist ein Fehler aufgetreten."
|
||||
@@ -6473,7 +6570,6 @@ pen = "Pen"
|
||||
polygon = "Polygon"
|
||||
rectangle = "Rectangle"
|
||||
redo = "Redo"
|
||||
saveChanges = "Save Changes"
|
||||
saveFailed = "Unable to save copy"
|
||||
saveReady = "Download ready"
|
||||
savingCopy = "Preparing download..."
|
||||
@@ -6496,11 +6592,17 @@ title = "Annotate"
|
||||
underline = "Underline"
|
||||
undo = "Undo"
|
||||
unsupportedType = "This annotation type is not fully supported for editing."
|
||||
saveChanges = "Save Changes"
|
||||
|
||||
[footer]
|
||||
discord = "Discord"
|
||||
issues = "GitHub"
|
||||
|
||||
[textAlign]
|
||||
center = "Center"
|
||||
left = "Left"
|
||||
right = "Right"
|
||||
|
||||
[mobileScanner]
|
||||
addToBatch = "Add to Batch"
|
||||
back = "Back"
|
||||
@@ -6555,8 +6657,3 @@ pollingError = "Error checking for files"
|
||||
sessionCreateError = "Failed to create session"
|
||||
sessionId = "Session ID"
|
||||
title = "Upload from Mobile"
|
||||
|
||||
[textAlign]
|
||||
center = "Center"
|
||||
left = "Left"
|
||||
right = "Right"
|
||||
|
||||
@@ -367,6 +367,7 @@ advanced = "Advanced"
|
||||
title = "Security & Authentication"
|
||||
security = "Security"
|
||||
connections = "Connections"
|
||||
telegram = "Telegram"
|
||||
|
||||
[settings.licensingAnalytics]
|
||||
title = "Licensing & Analytics"
|
||||
@@ -4633,6 +4634,90 @@ description = "Automatically create user accounts on first SAML2 login"
|
||||
label = "Block Registration"
|
||||
description = "Prevent new user registration via SAML2"
|
||||
|
||||
[admin.settings.telegram]
|
||||
title = "Telegram Bot"
|
||||
description = "Configure Telegram bot connectivity, access controls, and feedback behavior."
|
||||
|
||||
[admin.settings.telegram.enabled]
|
||||
label = "Enable Telegram Bot"
|
||||
description = "Allow users to interact with Stirling PDF through your configured Telegram bot."
|
||||
|
||||
[admin.settings.telegram.botUsername]
|
||||
label = "Bot Username"
|
||||
description = "The public username of your Telegram bot."
|
||||
|
||||
[admin.settings.telegram.botToken]
|
||||
label = "Bot Token"
|
||||
description = "API token provided by BotFather for your Telegram bot."
|
||||
|
||||
[admin.settings.telegram.pipelineInboxFolder]
|
||||
label = "Inbox Folder"
|
||||
description = "Folder under the pipeline directory where incoming Telegram files are stored."
|
||||
|
||||
[admin.settings.telegram.customFolderSuffix]
|
||||
label = "Use Custom Folder Suffix"
|
||||
description = "Append the chat ID to incoming file folders to isolate uploads per chat."
|
||||
|
||||
[admin.settings.telegram.accessControl]
|
||||
title = "Access Control"
|
||||
description = "Restrict which users or channels can interact with the bot."
|
||||
|
||||
[admin.settings.telegram.enableAllowUserIDs]
|
||||
label = "Allow Specific User IDs"
|
||||
description = "When enabled, only listed user IDs can use the bot."
|
||||
|
||||
[admin.settings.telegram.allowUserIDs]
|
||||
label = "Allowed User IDs"
|
||||
description = "Enter Telegram user IDs allowed to interact with the bot."
|
||||
placeholder = "Add user ID and press enter"
|
||||
|
||||
[admin.settings.telegram.enableAllowChannelIDs]
|
||||
label = "Allow Specific Channel IDs"
|
||||
description = "When enabled, only listed channel IDs can use the bot."
|
||||
|
||||
[admin.settings.telegram.allowChannelIDs]
|
||||
label = "Allowed Channel IDs"
|
||||
description = "Enter Telegram channel IDs allowed to interact with the bot."
|
||||
placeholder = "Add channel ID and press enter"
|
||||
|
||||
[admin.settings.telegram.processing]
|
||||
title = "Processing"
|
||||
description = "Control polling intervals and processing timeouts for Telegram uploads."
|
||||
|
||||
[admin.settings.telegram.processingTimeoutSeconds]
|
||||
label = "Processing Timeout (seconds)"
|
||||
description = "Maximum time to wait for a processing job before reporting an error."
|
||||
|
||||
[admin.settings.telegram.pollingIntervalMillis]
|
||||
label = "Polling Interval (ms)"
|
||||
description = "Interval between checks for new Telegram updates."
|
||||
|
||||
[admin.settings.telegram.feedback]
|
||||
title = "Feedback Messages"
|
||||
description = "Choose when the bot should send feedback to users and channels."
|
||||
|
||||
[admin.settings.telegram.feedback.general.enabled]
|
||||
label = "Enable Feedback"
|
||||
description = "Control whether the bot sends feedback messages at all."
|
||||
|
||||
[admin.settings.telegram.feedback.channel]
|
||||
title = "Channel Feedback Rules"
|
||||
noValidDocument.label = "Show \"No valid document\" (Channel)"
|
||||
noValidDocument.description = "Suppress the no valid document response for channel uploads."
|
||||
errorProcessing.label = "Show processing errors (Channel)"
|
||||
errorProcessing.description = "Send processing error messages to channels."
|
||||
errorMessage.label = "Show error messages (Channel)"
|
||||
errorMessage.description = "Show detailed error messages for channels."
|
||||
|
||||
[admin.settings.telegram.feedback.user]
|
||||
title = "User Feedback Rules"
|
||||
noValidDocument.label = "Show \"No valid document\" (User)"
|
||||
noValidDocument.description = "Suppress the no valid document response for user uploads."
|
||||
errorProcessing.label = "Show processing errors (User)"
|
||||
errorProcessing.description = "Send processing error messages to users."
|
||||
errorMessage.label = "Show error messages (User)"
|
||||
errorMessage.description = "Show detailed error messages for users."
|
||||
|
||||
[admin.settings.connections.mobileScanner]
|
||||
label = "Mobile Phone Upload"
|
||||
enable = "Enable QR Code Upload"
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Paper, Group, Text, Button, Collapse, Stack, TextInput, Textarea, Switch, PasswordInput } from '@mantine/core';
|
||||
import {
|
||||
Paper,
|
||||
Group,
|
||||
Text,
|
||||
Button,
|
||||
Collapse,
|
||||
Stack,
|
||||
TextInput,
|
||||
Textarea,
|
||||
Switch,
|
||||
PasswordInput,
|
||||
NumberInput,
|
||||
TagsInput,
|
||||
} from '@mantine/core';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import LocalIcon from '@app/components/shared/LocalIcon';
|
||||
import { Provider, ProviderField } from '@app/components/shared/config/configSections/providerDefinitions';
|
||||
@@ -105,6 +118,36 @@ export default function ProviderCard({
|
||||
/>
|
||||
);
|
||||
|
||||
case 'number':
|
||||
return (
|
||||
<NumberInput
|
||||
key={field.key}
|
||||
label={field.label}
|
||||
description={field.description}
|
||||
placeholder={field.placeholder}
|
||||
value={value}
|
||||
onChange={(num) => handleFieldChange(field.key, num)}
|
||||
disabled={disabled}
|
||||
allowDecimal={false}
|
||||
/>
|
||||
);
|
||||
|
||||
case 'tags': {
|
||||
const tagValue = Array.isArray(value) ? value.map((val) => `${val}`) : [];
|
||||
|
||||
return (
|
||||
<TagsInput
|
||||
key={field.key}
|
||||
label={field.label}
|
||||
description={field.description}
|
||||
placeholder={field.placeholder}
|
||||
value={tagValue}
|
||||
onChange={(vals) => handleFieldChange(field.key, vals)}
|
||||
disabled={disabled}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
default:
|
||||
return (
|
||||
<TextInput
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
export type ProviderType = 'oauth2' | 'saml2';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export type ProviderType = 'oauth2' | 'saml2' | 'telegram';
|
||||
|
||||
export interface ProviderField {
|
||||
key: string;
|
||||
type: 'text' | 'password' | 'switch' | 'textarea';
|
||||
type: 'text' | 'password' | 'switch' | 'textarea' | 'number' | 'tags';
|
||||
label: string;
|
||||
description: string;
|
||||
placeholder?: string;
|
||||
@@ -231,7 +233,7 @@ export const SMTP_PROVIDER: Provider = {
|
||||
},
|
||||
{
|
||||
key: 'port',
|
||||
type: 'text',
|
||||
type: 'number',
|
||||
label: 'SMTP Port',
|
||||
description: 'The port number for SMTP connection (typically 25, 465, or 587)',
|
||||
placeholder: '587',
|
||||
@@ -258,6 +260,216 @@ export const SMTP_PROVIDER: Provider = {
|
||||
},
|
||||
],
|
||||
};
|
||||
const useTelegramProvider = (): Provider => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return {
|
||||
id: 'telegram',
|
||||
name: t('admin.settings.telegram.title', 'Telegram Bot'),
|
||||
icon: 'send-rounded',
|
||||
type: 'telegram',
|
||||
scope: t(
|
||||
'admin.settings.telegram.description',
|
||||
'Configure Telegram bot connectivity, access controls, and feedback behavior.'
|
||||
),
|
||||
fields: [
|
||||
{
|
||||
key: 'enabled',
|
||||
type: 'switch',
|
||||
label: t('admin.settings.telegram.enabled.label', 'Enable Telegram Bot'),
|
||||
description: t(
|
||||
'admin.settings.telegram.enabled.description',
|
||||
'Allow users to interact with Stirling PDF through your configured Telegram bot.'
|
||||
),
|
||||
defaultValue: false,
|
||||
},
|
||||
{
|
||||
key: 'botUsername',
|
||||
type: 'text',
|
||||
label: t('admin.settings.telegram.botUsername.label', 'Bot Username'),
|
||||
description: t(
|
||||
'admin.settings.telegram.botUsername.description',
|
||||
'The public username of your Telegram bot.'
|
||||
),
|
||||
placeholder: 'my_pdf_bot',
|
||||
},
|
||||
{
|
||||
key: 'botToken',
|
||||
type: 'password',
|
||||
label: t('admin.settings.telegram.botToken.label', 'Bot Token'),
|
||||
description: t(
|
||||
'admin.settings.telegram.botToken.description',
|
||||
'API token provided by BotFather for your Telegram bot.'
|
||||
),
|
||||
placeholder: '123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11',
|
||||
},
|
||||
{
|
||||
key: 'pipelineInboxFolder',
|
||||
type: 'text',
|
||||
label: t('admin.settings.telegram.pipelineInboxFolder.label', 'Inbox Folder'),
|
||||
description: t(
|
||||
'admin.settings.telegram.pipelineInboxFolder.description',
|
||||
'Folder under the pipeline directory where incoming Telegram files are stored.'
|
||||
),
|
||||
placeholder: 'telegram',
|
||||
},
|
||||
{
|
||||
key: 'customFolderSuffix',
|
||||
type: 'switch',
|
||||
label: t('admin.settings.telegram.customFolderSuffix.label', 'Use Custom Folder Suffix'),
|
||||
description: t(
|
||||
'admin.settings.telegram.customFolderSuffix.description',
|
||||
'Append the chat ID to incoming file folders to isolate uploads per chat.'
|
||||
),
|
||||
defaultValue: false,
|
||||
},
|
||||
{
|
||||
key: 'enableAllowUserIDs',
|
||||
type: 'switch',
|
||||
label: t('admin.settings.telegram.enableAllowUserIDs.label', 'Allow Specific User IDs'),
|
||||
description: t(
|
||||
'admin.settings.telegram.enableAllowUserIDs.description',
|
||||
'When enabled, only listed user IDs can use the bot.'
|
||||
),
|
||||
defaultValue: false,
|
||||
},
|
||||
{
|
||||
key: 'allowUserIDs',
|
||||
type: 'tags',
|
||||
label: t('admin.settings.telegram.allowUserIDs.label', 'Allowed User IDs'),
|
||||
description: t(
|
||||
'admin.settings.telegram.allowUserIDs.description',
|
||||
'Enter Telegram user IDs allowed to interact with the bot.'
|
||||
),
|
||||
placeholder: t('admin.settings.telegram.allowUserIDs.placeholder', 'Add user ID and press enter'),
|
||||
defaultValue: [],
|
||||
},
|
||||
{
|
||||
key: 'enableAllowChannelIDs',
|
||||
type: 'switch',
|
||||
label: t('admin.settings.telegram.enableAllowChannelIDs.label', 'Allow Specific Channel IDs'),
|
||||
description: t(
|
||||
'admin.settings.telegram.enableAllowChannelIDs.description',
|
||||
'When enabled, only listed channel IDs can use the bot.'
|
||||
),
|
||||
defaultValue: false,
|
||||
},
|
||||
{
|
||||
key: 'allowChannelIDs',
|
||||
type: 'tags',
|
||||
label: t('admin.settings.telegram.allowChannelIDs.label', 'Allowed Channel IDs'),
|
||||
description: t(
|
||||
'admin.settings.telegram.allowChannelIDs.description',
|
||||
'Enter Telegram channel IDs allowed to interact with the bot.'
|
||||
),
|
||||
placeholder: t('admin.settings.telegram.allowChannelIDs.placeholder', 'Add channel ID and press enter'),
|
||||
defaultValue: [],
|
||||
},
|
||||
{
|
||||
key: 'processingTimeoutSeconds',
|
||||
type: 'number',
|
||||
label: t(
|
||||
'admin.settings.telegram.processingTimeoutSeconds.label',
|
||||
'Processing Timeout (seconds)'
|
||||
),
|
||||
description: t(
|
||||
'admin.settings.telegram.processingTimeoutSeconds.description',
|
||||
'Maximum time to wait for a processing job before reporting an error.'
|
||||
),
|
||||
defaultValue: 180,
|
||||
},
|
||||
{
|
||||
key: 'pollingIntervalMillis',
|
||||
type: 'number',
|
||||
label: t('admin.settings.telegram.pollingIntervalMillis.label', 'Polling Interval (ms)'),
|
||||
description: t(
|
||||
'admin.settings.telegram.pollingIntervalMillis.description',
|
||||
'Interval between checks for new Telegram updates.'
|
||||
),
|
||||
defaultValue: 2000,
|
||||
},
|
||||
{
|
||||
key: 'feedback.general.enabled',
|
||||
type: 'switch',
|
||||
label: t('admin.settings.telegram.feedback.general.enabled.label', 'Enable Feedback'),
|
||||
description: t(
|
||||
'admin.settings.telegram.feedback.general.enabled.description',
|
||||
'Control whether the bot sends feedback messages at all.'
|
||||
),
|
||||
defaultValue: true,
|
||||
},
|
||||
{
|
||||
key: 'feedback.channel.noValidDocument',
|
||||
type: 'switch',
|
||||
label: t(
|
||||
'admin.settings.telegram.feedback.channel.noValidDocument.label',
|
||||
'Show "No valid document" (Channel)'
|
||||
),
|
||||
description: t(
|
||||
'admin.settings.telegram.feedback.channel.noValidDocument.description',
|
||||
'Suppress the no valid document response for channel uploads.'
|
||||
),
|
||||
defaultValue: false,
|
||||
},
|
||||
{
|
||||
key: 'feedback.channel.errorProcessing',
|
||||
type: 'switch',
|
||||
label: t(
|
||||
'admin.settings.telegram.feedback.channel.errorProcessing.label',
|
||||
'Show processing errors (Channel)'
|
||||
),
|
||||
description: t(
|
||||
'admin.settings.telegram.feedback.channel.errorProcessing.description',
|
||||
'Send processing error messages to channels.'
|
||||
),
|
||||
defaultValue: false,
|
||||
},
|
||||
{
|
||||
key: 'feedback.channel.errorMessage',
|
||||
type: 'switch',
|
||||
label: t(
|
||||
'admin.settings.telegram.feedback.channel.errorMessage.label',
|
||||
'Show error messages (Channel)'
|
||||
),
|
||||
description: t(
|
||||
'admin.settings.telegram.feedback.channel.errorMessage.description',
|
||||
'Show detailed error messages for channels.'
|
||||
),
|
||||
defaultValue: false,
|
||||
},
|
||||
{
|
||||
key: 'feedback.user.noValidDocument',
|
||||
type: 'switch',
|
||||
label: t('admin.settings.telegram.feedback.user.noValidDocument.label', 'Show "No valid document" (User)'),
|
||||
description: t(
|
||||
'admin.settings.telegram.feedback.user.noValidDocument.description',
|
||||
'Suppress the no valid document response for user uploads.'
|
||||
),
|
||||
defaultValue: false,
|
||||
},
|
||||
{
|
||||
key: 'feedback.user.errorProcessing',
|
||||
type: 'switch',
|
||||
label: t('admin.settings.telegram.feedback.user.errorProcessing.label', 'Show processing errors (User)'),
|
||||
description: t(
|
||||
'admin.settings.telegram.feedback.user.errorProcessing.description',
|
||||
'Send processing error messages to users.'
|
||||
),
|
||||
defaultValue: false,
|
||||
},
|
||||
{
|
||||
key: 'feedback.user.errorMessage',
|
||||
type: 'switch',
|
||||
label: t('admin.settings.telegram.feedback.user.errorMessage.label', 'Show error messages (User)'),
|
||||
description: t(
|
||||
'admin.settings.telegram.feedback.user.errorMessage.description',
|
||||
'Show detailed error messages for users.'
|
||||
),
|
||||
defaultValue: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
export const SAML2_PROVIDER: Provider = {
|
||||
id: 'saml2',
|
||||
@@ -352,4 +564,14 @@ export const SAML2_PROVIDER: Provider = {
|
||||
],
|
||||
};
|
||||
|
||||
export const ALL_PROVIDERS = [...OAUTH2_PROVIDERS, GENERIC_OAUTH2_PROVIDER, SAML2_PROVIDER, SMTP_PROVIDER];
|
||||
export const useAllProviders = (): Provider[] => {
|
||||
const telegramProvider = useTelegramProvider();
|
||||
|
||||
return [
|
||||
...OAUTH2_PROVIDERS,
|
||||
GENERIC_OAUTH2_PROVIDER,
|
||||
SAML2_PROVIDER,
|
||||
SMTP_PROVIDER,
|
||||
telegramProvider,
|
||||
];
|
||||
};
|
||||
|
||||
@@ -18,6 +18,7 @@ export const VALID_NAV_KEYS = [
|
||||
'adminGeneral',
|
||||
'adminSecurity',
|
||||
'adminConnections',
|
||||
'adminTelegram',
|
||||
'adminPrivacy',
|
||||
'adminDatabase',
|
||||
'adminAdvanced',
|
||||
@@ -33,4 +34,4 @@ export const VALID_NAV_KEYS = [
|
||||
// Derive the type from the array
|
||||
export type NavKey = typeof VALID_NAV_KEYS[number];
|
||||
|
||||
// some of these are not used yet, but appear in figma designs
|
||||
// some of these are not used yet, but appear in figma designs
|
||||
|
||||
+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