mirror of
https://github.com/sct/overseerr.git
synced 2025-09-17 17:24:35 +02:00
feat(notif): issue notifications (#2242)
* feat(notif): issue notifications * refactor: dedupe test notification strings * fix: webhook key parsing * fix(notif): skip send for admin who requested on behalf of another user * fix(notif): send comment notifs to admins when other admins reply * fix(notif): also send resolved notifs to admins, and reopened notifs to issue creator * fix: don't send duplicate notifications * fix(lang): tweak notification description strings * fix(notif): tweak Slack notification styling * fix(notif): tweak Pushbullet & Telegram notification styling * docs: reformat webhooks page * fix(notif): add missing issue_type & issue_status variables to LunaSea notif payloads * fix: explicitly attach media & issue objects where applicable * fix(notif): correctly notify both notifyUser and managers where applicable * fix: update default webhook payload for new installs * fix(notif): add missing comment_message to LunaSea notif payload * refactor(sw): simplify notificationclick event listener logic * fix(notif): add missing event description for MEDIA_AVAILABLE notifications
This commit is contained in:
@@ -1,10 +1,13 @@
|
||||
import axios from 'axios';
|
||||
import { getRepository } from 'typeorm';
|
||||
import { hasNotificationType, Notification } from '..';
|
||||
import { MediaType } from '../../../constants/media';
|
||||
import {
|
||||
hasNotificationType,
|
||||
Notification,
|
||||
shouldSendAdminNotification,
|
||||
} from '..';
|
||||
import { IssueStatus, IssueTypeName } from '../../../constants/issue';
|
||||
import { User } from '../../../entity/User';
|
||||
import logger from '../../../logger';
|
||||
import { Permission } from '../../permissions';
|
||||
import {
|
||||
getSettings,
|
||||
NotificationAgentKey,
|
||||
@@ -61,95 +64,74 @@ class TelegramAgent
|
||||
type: Notification,
|
||||
payload: NotificationPayload
|
||||
): Partial<TelegramMessagePayload | TelegramPhotoPayload> {
|
||||
const settings = getSettings();
|
||||
let message = '';
|
||||
|
||||
const title = this.escapeText(payload.subject);
|
||||
const plot = this.escapeText(payload.message);
|
||||
const user = this.escapeText(payload.request?.requestedBy.displayName);
|
||||
const applicationTitle = this.escapeText(settings.main.applicationTitle);
|
||||
const { applicationUrl, applicationTitle } = getSettings().main;
|
||||
|
||||
/* eslint-disable no-useless-escape */
|
||||
switch (type) {
|
||||
case Notification.MEDIA_PENDING:
|
||||
message += `\*New ${
|
||||
payload.media?.mediaType === MediaType.TV ? 'Series' : 'Movie'
|
||||
} Request\*`;
|
||||
message += `\n\n\*${title}\*`;
|
||||
if (plot) {
|
||||
message += `\n${plot}`;
|
||||
}
|
||||
message += `\n\n\*Requested By\*\n${user}`;
|
||||
message += `\n\n\*Status\*\nPending Approval`;
|
||||
break;
|
||||
case Notification.MEDIA_APPROVED:
|
||||
message += `\*${
|
||||
payload.media?.mediaType === MediaType.TV ? 'Series' : 'Movie'
|
||||
} Request Approved\*`;
|
||||
message += `\n\n\*${title}\*`;
|
||||
if (plot) {
|
||||
message += `\n${plot}`;
|
||||
}
|
||||
message += `\n\n\*Requested By\*\n${user}`;
|
||||
message += `\n\n\*Status\*\nProcessing`;
|
||||
break;
|
||||
case Notification.MEDIA_AUTO_APPROVED:
|
||||
message += `\*${
|
||||
payload.media?.mediaType === MediaType.TV ? 'Series' : 'Movie'
|
||||
} Request Automatically Approved\*`;
|
||||
message += `\n\n\*${title}\*`;
|
||||
if (plot) {
|
||||
message += `\n${plot}`;
|
||||
}
|
||||
message += `\n\n\*Requested By\*\n${user}`;
|
||||
message += `\n\n\*Status\*\nProcessing`;
|
||||
break;
|
||||
case Notification.MEDIA_AVAILABLE:
|
||||
message += `\*${
|
||||
payload.media?.mediaType === MediaType.TV ? 'Series' : 'Movie'
|
||||
} Now Available\*`;
|
||||
message += `\n\n\*${title}\*`;
|
||||
if (plot) {
|
||||
message += `\n${plot}`;
|
||||
}
|
||||
message += `\n\n\*Requested By\*\n${user}`;
|
||||
message += `\n\n\*Status\*\nAvailable`;
|
||||
break;
|
||||
case Notification.MEDIA_DECLINED:
|
||||
message += `\*${
|
||||
payload.media?.mediaType === MediaType.TV ? 'Series' : 'Movie'
|
||||
} Request Declined\*`;
|
||||
message += `\n\n\*${title}\*`;
|
||||
if (plot) {
|
||||
message += `\n${plot}`;
|
||||
}
|
||||
message += `\n\n\*Requested By\*\n${user}`;
|
||||
message += `\n\n\*Status\*\nDeclined`;
|
||||
break;
|
||||
case Notification.MEDIA_FAILED:
|
||||
message += `\*Failed ${
|
||||
payload.media?.mediaType === MediaType.TV ? 'Series' : 'Movie'
|
||||
} Request\*`;
|
||||
message += `\n\n\*${title}\*`;
|
||||
if (plot) {
|
||||
message += `\n${plot}`;
|
||||
}
|
||||
message += `\n\n\*Requested By\*\n${user}`;
|
||||
message += `\n\n\*Status\*\nFailed`;
|
||||
break;
|
||||
case Notification.TEST_NOTIFICATION:
|
||||
message += `\*Test Notification\*`;
|
||||
message += `\n\n${plot}`;
|
||||
break;
|
||||
let message = `\*${this.escapeText(
|
||||
payload.event ? `${payload.event} - ${payload.subject}` : payload.subject
|
||||
)}\*`;
|
||||
if (payload.message) {
|
||||
message += `\n${this.escapeText(payload.message)}`;
|
||||
}
|
||||
|
||||
if (payload.request) {
|
||||
message += `\n\n\*Requested By:\* ${this.escapeText(
|
||||
payload.request?.requestedBy.displayName
|
||||
)}`;
|
||||
|
||||
let status = '';
|
||||
switch (type) {
|
||||
case Notification.MEDIA_PENDING:
|
||||
status = 'Pending Approval';
|
||||
break;
|
||||
case Notification.MEDIA_APPROVED:
|
||||
case Notification.MEDIA_AUTO_APPROVED:
|
||||
status = 'Processing';
|
||||
break;
|
||||
case Notification.MEDIA_AVAILABLE:
|
||||
status = 'Available';
|
||||
break;
|
||||
case Notification.MEDIA_DECLINED:
|
||||
status = 'Declined';
|
||||
break;
|
||||
case Notification.MEDIA_FAILED:
|
||||
status = 'Failed';
|
||||
break;
|
||||
}
|
||||
|
||||
if (status) {
|
||||
message += `\n\*Request Status:\* ${status}`;
|
||||
}
|
||||
} else if (payload.comment) {
|
||||
message += `\n\n\*Comment from ${this.escapeText(
|
||||
payload.comment.user.displayName
|
||||
)}:\* ${this.escapeText(payload.comment.message)}`;
|
||||
} else if (payload.issue) {
|
||||
message += `\n\n\*Reported By:\* ${this.escapeText(
|
||||
payload.issue.createdBy.displayName
|
||||
)}`;
|
||||
message += `\n\*Issue Type:\* ${IssueTypeName[payload.issue.issueType]}`;
|
||||
message += `\n\*Issue Status:\* ${
|
||||
payload.issue.status === IssueStatus.OPEN ? 'Open' : 'Resolved'
|
||||
}`;
|
||||
}
|
||||
|
||||
for (const extra of payload.extra ?? []) {
|
||||
message += `\n\n\*${extra.name}\*\n${extra.value}`;
|
||||
message += `\n\*${extra.name}:\* ${extra.value}`;
|
||||
}
|
||||
|
||||
if (settings.main.applicationUrl && payload.media) {
|
||||
const actionUrl = `${settings.main.applicationUrl}/${payload.media.mediaType}/${payload.media.tmdbId}`;
|
||||
message += `\n\n\[Open in ${applicationTitle}\]\(${actionUrl}\)`;
|
||||
const url = applicationUrl
|
||||
? payload.issue
|
||||
? `${applicationUrl}/issue/${payload.issue.id}`
|
||||
: payload.media
|
||||
? `${applicationUrl}/${payload.media.mediaType}/${payload.media.tmdbId}`
|
||||
: undefined
|
||||
: undefined;
|
||||
|
||||
if (url) {
|
||||
message += `\n\n\[View ${
|
||||
payload.issue ? 'Issue' : 'Media'
|
||||
} in ${this.escapeText(applicationTitle)}\]\(${url}\)`;
|
||||
}
|
||||
/* eslint-enable */
|
||||
|
||||
@@ -206,7 +188,6 @@ class TelegramAgent
|
||||
}
|
||||
|
||||
if (payload.notifyUser) {
|
||||
// Send notification to the user who submitted the request
|
||||
if (
|
||||
payload.notifyUser.settings?.hasNotificationType(
|
||||
NotificationAgentKey.TELEGRAM,
|
||||
@@ -242,8 +223,9 @@ class TelegramAgent
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Send notifications to all users with the Manage Requests permission
|
||||
}
|
||||
|
||||
if (payload.notifyAdmin) {
|
||||
const userRepository = getRepository(User);
|
||||
const users = await userRepository.find();
|
||||
|
||||
@@ -251,14 +233,10 @@ class TelegramAgent
|
||||
users
|
||||
.filter(
|
||||
(user) =>
|
||||
user.hasPermission(Permission.MANAGE_REQUESTS) &&
|
||||
user.settings?.hasNotificationType(
|
||||
NotificationAgentKey.TELEGRAM,
|
||||
type
|
||||
) &&
|
||||
// Check if it's the user's own auto-approved request
|
||||
(type !== Notification.MEDIA_AUTO_APPROVED ||
|
||||
user.id !== payload.request?.requestedBy.id)
|
||||
) && shouldSendAdminNotification(type, user, payload)
|
||||
)
|
||||
.map(async (user) => {
|
||||
if (
|
||||
|
Reference in New Issue
Block a user