feat(notifications): added telegram thread id's (#1145)
* feat(notifications): added telegram thread id's * undid unwanted formatting * chore: remove manual translations * style: conformed formatting * fix: add missing migration * fix: corrected erroneous migration
This commit is contained in:
@@ -100,6 +100,7 @@
|
||||
"options": {
|
||||
"botAPI": "",
|
||||
"chatId": "",
|
||||
"messageThreadId": "",
|
||||
"sendSilently": false
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1338,6 +1338,8 @@ components:
|
||||
type: string
|
||||
chatId:
|
||||
type: string
|
||||
messageThreadId:
|
||||
type: string
|
||||
sendSilently:
|
||||
type: boolean
|
||||
PushbulletSettings:
|
||||
@@ -1821,6 +1823,9 @@ components:
|
||||
telegramChatId:
|
||||
type: string
|
||||
nullable: true
|
||||
telegramMessageThreadId:
|
||||
type: string
|
||||
nullable: true
|
||||
telegramSendSilently:
|
||||
type: boolean
|
||||
nullable: true
|
||||
|
||||
@@ -60,6 +60,9 @@ export class UserSettings {
|
||||
@Column({ nullable: true })
|
||||
public telegramChatId?: string;
|
||||
|
||||
@Column({ nullable: true })
|
||||
public telegramMessageThreadId?: string;
|
||||
|
||||
@Column({ nullable: true })
|
||||
public telegramSendSilently?: boolean;
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ export interface UserSettingsNotificationsResponse {
|
||||
telegramEnabled?: boolean;
|
||||
telegramBotUsername?: string;
|
||||
telegramChatId?: string;
|
||||
telegramMessageThreadId?: string;
|
||||
telegramSendSilently?: boolean;
|
||||
webPushEnabled?: boolean;
|
||||
notificationTypes: Partial<NotificationAgentTypes>;
|
||||
|
||||
@@ -17,6 +17,7 @@ interface TelegramMessagePayload {
|
||||
text: string;
|
||||
parse_mode: string;
|
||||
chat_id: string;
|
||||
message_thread_id: string;
|
||||
disable_notification: boolean;
|
||||
}
|
||||
|
||||
@@ -25,6 +26,7 @@ interface TelegramPhotoPayload {
|
||||
caption: string;
|
||||
parse_mode: string;
|
||||
chat_id: string;
|
||||
message_thread_id: string;
|
||||
disable_notification: boolean;
|
||||
}
|
||||
|
||||
@@ -182,6 +184,7 @@ class TelegramAgent
|
||||
body: JSON.stringify({
|
||||
...notificationPayload,
|
||||
chat_id: settings.options.chatId,
|
||||
message_thread_id: settings.options.messageThreadId,
|
||||
disable_notification: !!settings.options.sendSilently,
|
||||
} as TelegramMessagePayload | TelegramPhotoPayload),
|
||||
});
|
||||
@@ -233,6 +236,8 @@ class TelegramAgent
|
||||
body: JSON.stringify({
|
||||
...notificationPayload,
|
||||
chat_id: payload.notifyUser.settings.telegramChatId,
|
||||
message_thread_id:
|
||||
payload.notifyUser.settings.telegramMessageThreadId,
|
||||
disable_notification:
|
||||
!!payload.notifyUser.settings.telegramSendSilently,
|
||||
} as TelegramMessagePayload | TelegramPhotoPayload),
|
||||
@@ -296,6 +301,7 @@ class TelegramAgent
|
||||
body: JSON.stringify({
|
||||
...notificationPayload,
|
||||
chat_id: user.settings.telegramChatId,
|
||||
message_thread_id: user.settings.telegramMessageThreadId,
|
||||
disable_notification: !!user.settings?.telegramSendSilently,
|
||||
} as TelegramMessagePayload | TelegramPhotoPayload),
|
||||
});
|
||||
|
||||
@@ -213,6 +213,7 @@ export interface NotificationAgentTelegram extends NotificationAgentConfig {
|
||||
botUsername?: string;
|
||||
botAPI: string;
|
||||
chatId: string;
|
||||
messageThreadId: string;
|
||||
sendSilently: boolean;
|
||||
};
|
||||
}
|
||||
@@ -423,6 +424,7 @@ class Settings {
|
||||
options: {
|
||||
botAPI: '',
|
||||
chatId: '',
|
||||
messageThreadId: '',
|
||||
sendSilently: false,
|
||||
},
|
||||
},
|
||||
|
||||
33
server/migration/1734287582736-AddTelegramMessageThreadId.ts
Normal file
33
server/migration/1734287582736-AddTelegramMessageThreadId.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import type { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class AddTelegramMessageThreadId1734287582736
|
||||
implements MigrationInterface
|
||||
{
|
||||
name = 'AddTelegramMessageThreadId1734287582736';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`CREATE TABLE "temporary_user_settings" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "locale" varchar NOT NULL DEFAULT (''), "discoverRegion" varchar, "streamingRegion" varchar, "originalLanguage" varchar, "pgpKey" varchar, "discordId" varchar, "pushbulletAccessToken" varchar, "pushoverApplicationToken" varchar, "pushoverUserKey" varchar, "pushoverSound" varchar, "telegramChatId" varchar, "telegramSendSilently" boolean, "watchlistSyncMovies" boolean, "watchlistSyncTv" boolean, "notificationTypes" text, "userId" integer, "telegramMessageThreadId" varchar, CONSTRAINT "REL_986a2b6d3c05eb4091bb8066f7" UNIQUE ("userId"), CONSTRAINT "FK_986a2b6d3c05eb4091bb8066f78" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`
|
||||
);
|
||||
await queryRunner.query(
|
||||
`INSERT INTO "temporary_user_settings"("id", "locale", "discoverRegion", "streamingRegion", "originalLanguage", "pgpKey", "discordId", "pushbulletAccessToken", "pushoverApplicationToken", "pushoverUserKey", "pushoverSound", "telegramChatId", "telegramSendSilently", "watchlistSyncMovies", "watchlistSyncTv", "notificationTypes", "userId") SELECT "id", "locale", "discoverRegion", "streamingRegion", "originalLanguage", "pgpKey", "discordId", "pushbulletAccessToken", "pushoverApplicationToken", "pushoverUserKey", "pushoverSound", "telegramChatId", "telegramSendSilently", "watchlistSyncMovies", "watchlistSyncTv", "notificationTypes", "userId" FROM "user_settings"`
|
||||
);
|
||||
await queryRunner.query(`DROP TABLE "user_settings"`);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "temporary_user_settings" RENAME TO "user_settings"`
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "user_settings" RENAME TO "temporary_user_settings"`
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE TABLE "user_settings" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "locale" varchar NOT NULL DEFAULT (''), "discoverRegion" varchar, "streamingRegion" varchar, "originalLanguage" varchar, "pgpKey" varchar, "discordId" varchar, "pushbulletAccessToken" varchar, "pushoverApplicationToken" varchar, "pushoverUserKey" varchar, "pushoverSound" varchar, "telegramChatId" varchar, "telegramSendSilently" boolean, "watchlistSyncMovies" boolean, "watchlistSyncTv" boolean, "notificationTypes" text, "userId" integer, CONSTRAINT "REL_986a2b6d3c05eb4091bb8066f7" UNIQUE ("userId"), CONSTRAINT "FK_986a2b6d3c05eb4091bb8066f78" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`
|
||||
);
|
||||
await queryRunner.query(
|
||||
`INSERT INTO "user_settings"("id", "locale", "discoverRegion", "streamingRegion", "originalLanguage", "pgpKey", "discordId", "pushbulletAccessToken", "pushoverApplicationToken", "pushoverUserKey", "pushoverSound", "telegramChatId", "telegramSendSilently", "watchlistSyncMovies", "watchlistSyncTv", "notificationTypes", "userId") SELECT "id", "locale", "discoverRegion", "streamingRegion", "originalLanguage", "pgpKey", "discordId", "pushbulletAccessToken", "pushoverApplicationToken", "pushoverUserKey", "pushoverSound", "telegramChatId", "telegramSendSilently", "watchlistSyncMovies", "watchlistSyncTv", "notificationTypes", "userId" FROM "temporary_user_settings"`
|
||||
);
|
||||
await queryRunner.query(`DROP TABLE "temporary_user_settings"`);
|
||||
}
|
||||
}
|
||||
@@ -323,6 +323,7 @@ userSettingsRoutes.get<{ id: string }, UserSettingsNotificationsResponse>(
|
||||
telegramEnabled: settings.telegram.enabled,
|
||||
telegramBotUsername: settings.telegram.options.botUsername,
|
||||
telegramChatId: user.settings?.telegramChatId,
|
||||
telegramMessageThreadId: user.settings?.telegramMessageThreadId,
|
||||
telegramSendSilently: user.settings?.telegramSendSilently,
|
||||
webPushEnabled: settings.webpush.enabled,
|
||||
notificationTypes: user.settings?.notificationTypes ?? {},
|
||||
@@ -365,6 +366,7 @@ userSettingsRoutes.post<{ id: string }, UserSettingsNotificationsResponse>(
|
||||
pushoverApplicationToken: req.body.pushoverApplicationToken,
|
||||
pushoverUserKey: req.body.pushoverUserKey,
|
||||
telegramChatId: req.body.telegramChatId,
|
||||
telegramMessageThreadId: req.body.telegramMessageThreadId,
|
||||
telegramSendSilently: req.body.telegramSendSilently,
|
||||
notificationTypes: req.body.notificationTypes,
|
||||
});
|
||||
@@ -377,6 +379,8 @@ userSettingsRoutes.post<{ id: string }, UserSettingsNotificationsResponse>(
|
||||
user.settings.pushoverUserKey = req.body.pushoverUserKey;
|
||||
user.settings.pushoverSound = req.body.pushoverSound;
|
||||
user.settings.telegramChatId = req.body.telegramChatId;
|
||||
user.settings.telegramMessageThreadId =
|
||||
req.body.telegramMessageThreadId;
|
||||
user.settings.telegramSendSilently = req.body.telegramSendSilently;
|
||||
user.settings.notificationTypes = Object.assign(
|
||||
{},
|
||||
@@ -395,6 +399,7 @@ userSettingsRoutes.post<{ id: string }, UserSettingsNotificationsResponse>(
|
||||
pushoverUserKey: user.settings.pushoverUserKey,
|
||||
pushoverSound: user.settings.pushoverSound,
|
||||
telegramChatId: user.settings.telegramChatId,
|
||||
telegramMessageThreadId: user.settings.telegramMessageThreadId,
|
||||
telegramSendSilently: user.settings.telegramSendSilently,
|
||||
notificationTypes: user.settings.notificationTypes,
|
||||
});
|
||||
|
||||
@@ -23,8 +23,13 @@ const messages = defineMessages('components.Settings.Notifications', {
|
||||
chatId: 'Chat ID',
|
||||
chatIdTip:
|
||||
'Start a chat with your bot, add <GetIdBotLink>@get_id_bot</GetIdBotLink>, and issue the <code>/my_id</code> command',
|
||||
messageThreadId: 'Thread/Topic ID',
|
||||
messageThreadIdTip:
|
||||
"If your group-chat has topics enabled, you can specify a thread/topic's ID here",
|
||||
validationBotAPIRequired: 'You must provide a bot authorization token',
|
||||
validationChatIdRequired: 'You must provide a valid chat ID',
|
||||
validationMessageThreadId:
|
||||
'The thread/topic ID must be a positive whole number',
|
||||
telegramsettingssaved: 'Telegram notification settings saved successfully!',
|
||||
telegramsettingsfailed: 'Telegram notification settings failed to save.',
|
||||
toastTelegramTestSending: 'Sending Telegram test notification…',
|
||||
@@ -64,6 +69,15 @@ const NotificationsTelegram = () => {
|
||||
/^-?\d+$/,
|
||||
intl.formatMessage(messages.validationChatIdRequired)
|
||||
),
|
||||
messageThreadId: Yup.string()
|
||||
.when(['types'], {
|
||||
is: (enabled: boolean, types: number) => enabled && !!types,
|
||||
then: Yup.string()
|
||||
.nullable()
|
||||
.required(intl.formatMessage(messages.validationMessageThreadId)),
|
||||
otherwise: Yup.string().nullable(),
|
||||
})
|
||||
.matches(/^\d+$/, intl.formatMessage(messages.validationMessageThreadId)),
|
||||
});
|
||||
|
||||
if (!data && !error) {
|
||||
@@ -78,6 +92,7 @@ const NotificationsTelegram = () => {
|
||||
botUsername: data?.options.botUsername,
|
||||
botAPI: data?.options.botAPI,
|
||||
chatId: data?.options.chatId,
|
||||
messageThreadId: data?.options.messageThreadId,
|
||||
sendSilently: data?.options.sendSilently,
|
||||
}}
|
||||
validationSchema={NotificationsTelegramSchema}
|
||||
@@ -94,6 +109,7 @@ const NotificationsTelegram = () => {
|
||||
options: {
|
||||
botAPI: values.botAPI,
|
||||
chatId: values.chatId,
|
||||
messageThreadId: values.messageThreadId,
|
||||
sendSilently: values.sendSilently,
|
||||
botUsername: values.botUsername,
|
||||
},
|
||||
@@ -151,6 +167,7 @@ const NotificationsTelegram = () => {
|
||||
options: {
|
||||
botAPI: values.botAPI,
|
||||
chatId: values.chatId,
|
||||
messageThreadId: values.messageThreadId,
|
||||
sendSilently: values.sendSilently,
|
||||
botUsername: values.botUsername,
|
||||
},
|
||||
@@ -286,6 +303,28 @@ const NotificationsTelegram = () => {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-row">
|
||||
<label htmlFor="messageThreadId" className="text-label">
|
||||
{intl.formatMessage(messages.messageThreadId)}
|
||||
<span className="label-tip">
|
||||
{intl.formatMessage(messages.messageThreadIdTip)}
|
||||
</span>
|
||||
</label>
|
||||
<div className="form-input-area">
|
||||
<div className="form-input-field">
|
||||
<Field
|
||||
id="messageThreadId"
|
||||
name="messageThreadId"
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
{errors.messageThreadId &&
|
||||
touched.messageThreadId &&
|
||||
typeof errors.messageThreadId === 'string' && (
|
||||
<div className="error">{errors.messageThreadId}</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-row">
|
||||
<label htmlFor="sendSilently" className="checkbox-label">
|
||||
<span>{intl.formatMessage(messages.sendSilently)}</span>
|
||||
|
||||
@@ -21,9 +21,14 @@ const messages = defineMessages(
|
||||
telegramChatId: 'Chat ID',
|
||||
telegramChatIdTipLong:
|
||||
'<TelegramBotLink>Start a chat</TelegramBotLink>, add <GetIdBotLink>@get_id_bot</GetIdBotLink>, and issue the <code>/my_id</code> command',
|
||||
telegramMessageThreadId: 'Thread/Topic ID',
|
||||
telegramMessageThreadIdTip:
|
||||
"If your group-chat has topics enabled, you can specify a thread/topic's ID here",
|
||||
sendSilently: 'Send Silently',
|
||||
sendSilentlyDescription: 'Send notifications with no sound',
|
||||
validationTelegramChatId: 'You must provide a valid chat ID',
|
||||
validationTelegramMessageThreadId:
|
||||
'The thread/topic ID must be a positive whole number',
|
||||
}
|
||||
);
|
||||
|
||||
@@ -53,6 +58,20 @@ const UserTelegramSettings = () => {
|
||||
/^-?\d+$/,
|
||||
intl.formatMessage(messages.validationTelegramChatId)
|
||||
),
|
||||
telegramMessageThreadId: Yup.string()
|
||||
.when(['types'], {
|
||||
is: (enabled: boolean, types: number) => enabled && !!types,
|
||||
then: Yup.string()
|
||||
.nullable()
|
||||
.required(
|
||||
intl.formatMessage(messages.validationTelegramMessageThreadId)
|
||||
),
|
||||
otherwise: Yup.string().nullable(),
|
||||
})
|
||||
.matches(
|
||||
/^\d+$/,
|
||||
intl.formatMessage(messages.validationTelegramMessageThreadId)
|
||||
),
|
||||
});
|
||||
|
||||
if (!data && !error) {
|
||||
@@ -63,6 +82,7 @@ const UserTelegramSettings = () => {
|
||||
<Formik
|
||||
initialValues={{
|
||||
telegramChatId: data?.telegramChatId,
|
||||
telegramMessageThreadId: data?.telegramMessageThreadId,
|
||||
telegramSendSilently: data?.telegramSendSilently,
|
||||
types: data?.notificationTypes.telegram ?? 0,
|
||||
}}
|
||||
@@ -84,6 +104,7 @@ const UserTelegramSettings = () => {
|
||||
pushoverApplicationToken: data?.pushoverApplicationToken,
|
||||
pushoverUserKey: data?.pushoverUserKey,
|
||||
telegramChatId: values.telegramChatId,
|
||||
telegramMessageThreadId: values.telegramMessageThreadId,
|
||||
telegramSendSilently: values.telegramSendSilently,
|
||||
notificationTypes: {
|
||||
telegram: values.types,
|
||||
@@ -162,6 +183,30 @@ const UserTelegramSettings = () => {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-row">
|
||||
<label htmlFor="telegramMessageThreadId" className="text-label">
|
||||
{intl.formatMessage(messages.telegramMessageThreadId)}
|
||||
<span className="label-tip">
|
||||
{intl.formatMessage(messages.telegramMessageThreadIdTip)}
|
||||
</span>
|
||||
</label>
|
||||
<div className="form-input-area">
|
||||
<div className="form-input-field">
|
||||
<Field
|
||||
id="telegramMessageThreadId"
|
||||
name="telegramMessageThreadId"
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
{errors.telegramMessageThreadId &&
|
||||
touched.telegramMessageThreadId &&
|
||||
typeof errors.telegramMessageThreadId === 'string' && (
|
||||
<div className="error">
|
||||
{errors.telegramMessageThreadId}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-row">
|
||||
<label htmlFor="telegramSendSilently" className="checkbox-label">
|
||||
{intl.formatMessage(messages.sendSilently)}
|
||||
|
||||
@@ -697,6 +697,8 @@
|
||||
"components.Settings.Notifications.encryptionNone": "None",
|
||||
"components.Settings.Notifications.encryptionOpportunisticTls": "Always use STARTTLS",
|
||||
"components.Settings.Notifications.encryptionTip": "In most cases, Implicit TLS uses port 465 and STARTTLS uses port 587",
|
||||
"components.Settings.Notifications.messageThreadId": "Thread/Topic ID",
|
||||
"components.Settings.Notifications.messageThreadIdTip": "If your group-chat has topics enabled, you can specify a thread/topic's ID here",
|
||||
"components.Settings.Notifications.pgpPassword": "PGP Password",
|
||||
"components.Settings.Notifications.pgpPasswordTip": "Sign encrypted email messages using <OpenPgpLink>OpenPGP</OpenPgpLink>",
|
||||
"components.Settings.Notifications.pgpPrivateKey": "PGP Private Key",
|
||||
@@ -721,6 +723,7 @@
|
||||
"components.Settings.Notifications.validationBotAPIRequired": "You must provide a bot authorization token",
|
||||
"components.Settings.Notifications.validationChatIdRequired": "You must provide a valid chat ID",
|
||||
"components.Settings.Notifications.validationEmail": "You must provide a valid email address",
|
||||
"components.Settings.Notifications.validationMessageThreadId": "The thread/topic ID must be a positive whole number",
|
||||
"components.Settings.Notifications.validationPgpPassword": "You must provide a PGP password",
|
||||
"components.Settings.Notifications.validationPgpPrivateKey": "You must provide a valid PGP private key",
|
||||
"components.Settings.Notifications.validationSmtpHostRequired": "You must provide a valid hostname or IP address",
|
||||
@@ -1288,6 +1291,8 @@
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.sound": "Notification Sound",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId": "Chat ID",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong": "<TelegramBotLink>Start a chat</TelegramBotLink>, add <GetIdBotLink>@get_id_bot</GetIdBotLink>, and issue the <code>/my_id</code> command",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadId": "Thread/Topic ID",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.telegramMessageThreadIdTip": "If your group-chat has topics enabled, you can specify a thread/topic's ID here",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed": "Telegram notification settings failed to save.",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingssaved": "Telegram notification settings saved successfully!",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.validationDiscordId": "You must provide a valid user ID",
|
||||
@@ -1296,6 +1301,7 @@
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverApplicationToken": "You must provide a valid application token",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey": "You must provide a valid user or group key",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId": "You must provide a valid chat ID",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramMessageThreadId": "The thread/topic ID must be a positive whole number",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.webpush": "Web Push",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.webpushsettingsfailed": "Web push notification settings failed to save.",
|
||||
"components.UserProfile.UserSettings.UserNotificationSettings.webpushsettingssaved": "Web push notification settings saved successfully!",
|
||||
|
||||
Reference in New Issue
Block a user