mirror of
https://github.com/sct/overseerr.git
synced 2025-09-17 17:24:35 +02:00
feat(notifications): add notification for declined requests
closes #663
This commit is contained in:
@@ -138,8 +138,11 @@ export class MediaRequest {
|
|||||||
* auto approved content
|
* auto approved content
|
||||||
*/
|
*/
|
||||||
@AfterUpdate()
|
@AfterUpdate()
|
||||||
private async _notifyApproved() {
|
public async notifyApprovedOrDeclined(): Promise<void> {
|
||||||
if (this.status === MediaRequestStatus.APPROVED) {
|
if (
|
||||||
|
this.status === MediaRequestStatus.APPROVED ||
|
||||||
|
this.status === MediaRequestStatus.DECLINED
|
||||||
|
) {
|
||||||
const mediaRepository = getRepository(Media);
|
const mediaRepository = getRepository(Media);
|
||||||
const media = await mediaRepository.findOne({
|
const media = await mediaRepository.findOne({
|
||||||
where: { id: this.media.id },
|
where: { id: this.media.id },
|
||||||
@@ -151,30 +154,40 @@ export class MediaRequest {
|
|||||||
const tmdb = new TheMovieDb();
|
const tmdb = new TheMovieDb();
|
||||||
if (this.media.mediaType === MediaType.MOVIE) {
|
if (this.media.mediaType === MediaType.MOVIE) {
|
||||||
const movie = await tmdb.getMovie({ movieId: this.media.tmdbId });
|
const movie = await tmdb.getMovie({ movieId: this.media.tmdbId });
|
||||||
notificationManager.sendNotification(Notification.MEDIA_APPROVED, {
|
notificationManager.sendNotification(
|
||||||
subject: movie.title,
|
this.status === MediaRequestStatus.APPROVED
|
||||||
message: movie.overview,
|
? Notification.MEDIA_APPROVED
|
||||||
image: `https://image.tmdb.org/t/p/w600_and_h900_bestv2${movie.poster_path}`,
|
: Notification.MEDIA_DECLINED,
|
||||||
notifyUser: this.requestedBy,
|
{
|
||||||
media,
|
subject: movie.title,
|
||||||
});
|
message: movie.overview,
|
||||||
|
image: `https://image.tmdb.org/t/p/w600_and_h900_bestv2${movie.poster_path}`,
|
||||||
|
notifyUser: this.requestedBy,
|
||||||
|
media,
|
||||||
|
}
|
||||||
|
);
|
||||||
} else if (this.media.mediaType === MediaType.TV) {
|
} else if (this.media.mediaType === MediaType.TV) {
|
||||||
const tv = await tmdb.getTvShow({ tvId: this.media.tmdbId });
|
const tv = await tmdb.getTvShow({ tvId: this.media.tmdbId });
|
||||||
notificationManager.sendNotification(Notification.MEDIA_APPROVED, {
|
notificationManager.sendNotification(
|
||||||
subject: tv.name,
|
this.status === MediaRequestStatus.APPROVED
|
||||||
message: tv.overview,
|
? Notification.MEDIA_APPROVED
|
||||||
image: `https://image.tmdb.org/t/p/w600_and_h900_bestv2${tv.poster_path}`,
|
: Notification.MEDIA_DECLINED,
|
||||||
notifyUser: this.requestedBy,
|
{
|
||||||
media,
|
subject: tv.name,
|
||||||
extra: [
|
message: tv.overview,
|
||||||
{
|
image: `https://image.tmdb.org/t/p/w600_and_h900_bestv2${tv.poster_path}`,
|
||||||
name: 'Seasons',
|
notifyUser: this.requestedBy,
|
||||||
value: this.seasons
|
media,
|
||||||
.map((season) => season.seasonNumber)
|
extra: [
|
||||||
.join(', '),
|
{
|
||||||
},
|
name: 'Seasons',
|
||||||
],
|
value: this.seasons
|
||||||
});
|
.map((season) => season.seasonNumber)
|
||||||
|
.join(', '),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -158,6 +158,28 @@ class DiscordAgent
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (settings.main.applicationUrl) {
|
||||||
|
fields.push({
|
||||||
|
name: 'View Media',
|
||||||
|
value: `${settings.main.applicationUrl}/${payload.media?.mediaType}/${payload.media?.tmdbId}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Notification.MEDIA_DECLINED:
|
||||||
|
color = EmbedColors.RED;
|
||||||
|
fields.push(
|
||||||
|
{
|
||||||
|
name: 'Requested By',
|
||||||
|
value: payload.notifyUser.username ?? '',
|
||||||
|
inline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Status',
|
||||||
|
value: 'Declined',
|
||||||
|
inline: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
if (settings.main.applicationUrl) {
|
if (settings.main.applicationUrl) {
|
||||||
fields.push({
|
fields.push({
|
||||||
name: 'View Media',
|
name: 'View Media',
|
||||||
|
@@ -162,6 +162,43 @@ class EmailAgent
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async sendMediaDeclinedEmail(payload: NotificationPayload) {
|
||||||
|
// This is getting main settings for the whole app
|
||||||
|
const applicationUrl = getSettings().main.applicationUrl;
|
||||||
|
try {
|
||||||
|
const email = new PreparedEmail();
|
||||||
|
|
||||||
|
await email.send({
|
||||||
|
template: path.join(
|
||||||
|
__dirname,
|
||||||
|
'../../../templates/email/media-request'
|
||||||
|
),
|
||||||
|
message: {
|
||||||
|
to: payload.notifyUser.email,
|
||||||
|
},
|
||||||
|
locals: {
|
||||||
|
body: 'Your request for the following media was declined:',
|
||||||
|
mediaName: payload.subject,
|
||||||
|
imageUrl: payload.image,
|
||||||
|
timestamp: new Date().toTimeString(),
|
||||||
|
requestedBy: payload.notifyUser.username,
|
||||||
|
actionUrl: applicationUrl
|
||||||
|
? `${applicationUrl}/${payload.media?.mediaType}/${payload.media?.tmdbId}`
|
||||||
|
: undefined,
|
||||||
|
applicationUrl,
|
||||||
|
requestType: 'Request Declined',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
logger.error('Mail notification failed to send', {
|
||||||
|
label: 'Notifications',
|
||||||
|
message: e.message,
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async sendMediaAvailableEmail(payload: NotificationPayload) {
|
private async sendMediaAvailableEmail(payload: NotificationPayload) {
|
||||||
// This is getting main settings for the whole app
|
// This is getting main settings for the whole app
|
||||||
const applicationUrl = getSettings().main.applicationUrl;
|
const applicationUrl = getSettings().main.applicationUrl;
|
||||||
|
@@ -72,6 +72,13 @@ class PushoverAgent
|
|||||||
message += `<b>Requested By</b>\n${user}\n\n`;
|
message += `<b>Requested By</b>\n${user}\n\n`;
|
||||||
message += `<b>Status</b>\nAvailable\n`;
|
message += `<b>Status</b>\nAvailable\n`;
|
||||||
break;
|
break;
|
||||||
|
case Notification.MEDIA_DECLINED:
|
||||||
|
messageTitle = 'Request Declined';
|
||||||
|
message += `${title}\n\n`;
|
||||||
|
message += `${plot}\n\n`;
|
||||||
|
message += `<b>Requested By</b>\n${user}\n\n`;
|
||||||
|
message += `<b>Status</b>\nDeclined\n`;
|
||||||
|
break;
|
||||||
case Notification.TEST_NOTIFICATION:
|
case Notification.TEST_NOTIFICATION:
|
||||||
messageTitle = 'Test Notification';
|
messageTitle = 'Test Notification';
|
||||||
message += `${title}\n\n`;
|
message += `${title}\n\n`;
|
||||||
|
@@ -96,6 +96,22 @@ class SlackAgent
|
|||||||
actionUrl = `${settings.main.applicationUrl}/${payload.media?.mediaType}/${payload.media?.tmdbId}`;
|
actionUrl = `${settings.main.applicationUrl}/${payload.media?.mediaType}/${payload.media?.tmdbId}`;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case Notification.MEDIA_DECLINED:
|
||||||
|
header = 'Request Declined';
|
||||||
|
fields.push(
|
||||||
|
{
|
||||||
|
type: 'mrkdwn',
|
||||||
|
text: `*Requested By*\n${payload.notifyUser.username ?? ''}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'mrkdwn',
|
||||||
|
text: '*Status*\nDeclined',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (settings.main.applicationUrl) {
|
||||||
|
actionUrl = `${settings.main.applicationUrl}/${payload.media?.mediaType}/${payload.media?.tmdbId}`;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case Notification.MEDIA_AVAILABLE:
|
case Notification.MEDIA_AVAILABLE:
|
||||||
header = 'Now available!';
|
header = 'Now available!';
|
||||||
fields.push(
|
fields.push(
|
||||||
|
@@ -70,6 +70,14 @@ class TelegramAgent
|
|||||||
message += `\*Requested By\*\n${user}\n\n`;
|
message += `\*Requested By\*\n${user}\n\n`;
|
||||||
message += `\*Status\*\nProcessing Request\n`;
|
message += `\*Status\*\nProcessing Request\n`;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case Notification.MEDIA_DECLINED:
|
||||||
|
message += `\*Request Declined\*\n`;
|
||||||
|
message += `${title}\n\n`;
|
||||||
|
message += `${plot}\n\n`;
|
||||||
|
message += `\*Requested By\*\n${user}\n\n`;
|
||||||
|
message += `\*Status\*\nDeclined\n`;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case Notification.MEDIA_AVAILABLE:
|
case Notification.MEDIA_AVAILABLE:
|
||||||
message += `\*Now available\\!\*\n`;
|
message += `\*Now available\\!\*\n`;
|
||||||
|
@@ -7,6 +7,7 @@ export enum Notification {
|
|||||||
MEDIA_AVAILABLE = 8,
|
MEDIA_AVAILABLE = 8,
|
||||||
MEDIA_FAILED = 16,
|
MEDIA_FAILED = 16,
|
||||||
TEST_NOTIFICATION = 32,
|
TEST_NOTIFICATION = 32,
|
||||||
|
MEDIA_DECLINED = 64,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const hasNotificationType = (
|
export const hasNotificationType = (
|
||||||
|
@@ -14,6 +14,8 @@ const messages = defineMessages({
|
|||||||
mediafailed: 'Media Failed',
|
mediafailed: 'Media Failed',
|
||||||
mediafailedDescription:
|
mediafailedDescription:
|
||||||
'Sends a notification when media fails to be added to services (Radarr/Sonarr). For certain agents, this will only send the notification to admins or users with the "Manage Requests" permission.',
|
'Sends a notification when media fails to be added to services (Radarr/Sonarr). For certain agents, this will only send the notification to admins or users with the "Manage Requests" permission.',
|
||||||
|
mediadeclined: 'Media Declined',
|
||||||
|
mediadeclinedDescription: 'Sends a notification when a request is declined.',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const hasNotificationType = (
|
export const hasNotificationType = (
|
||||||
@@ -41,6 +43,7 @@ export enum Notification {
|
|||||||
MEDIA_AVAILABLE = 8,
|
MEDIA_AVAILABLE = 8,
|
||||||
MEDIA_FAILED = 16,
|
MEDIA_FAILED = 16,
|
||||||
TEST_NOTIFICATION = 32,
|
TEST_NOTIFICATION = 32,
|
||||||
|
MEDIA_DECLINED = 64,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NotificationItem {
|
export interface NotificationItem {
|
||||||
@@ -75,6 +78,12 @@ const NotificationTypeSelector: React.FC<NotificationTypeSelectorProps> = ({
|
|||||||
description: intl.formatMessage(messages.mediaapprovedDescription),
|
description: intl.formatMessage(messages.mediaapprovedDescription),
|
||||||
value: Notification.MEDIA_APPROVED,
|
value: Notification.MEDIA_APPROVED,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'media-declined',
|
||||||
|
name: intl.formatMessage(messages.mediadeclined),
|
||||||
|
description: intl.formatMessage(messages.mediadeclinedDescription),
|
||||||
|
value: Notification.MEDIA_DECLINED,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'media-available',
|
id: 'media-available',
|
||||||
name: intl.formatMessage(messages.mediaavailable),
|
name: intl.formatMessage(messages.mediaavailable),
|
||||||
|
@@ -72,6 +72,8 @@
|
|||||||
"components.NotificationTypeSelector.mediaapprovedDescription": "Sends a notification when media is approved.",
|
"components.NotificationTypeSelector.mediaapprovedDescription": "Sends a notification when media is approved.",
|
||||||
"components.NotificationTypeSelector.mediaavailable": "Media Available",
|
"components.NotificationTypeSelector.mediaavailable": "Media Available",
|
||||||
"components.NotificationTypeSelector.mediaavailableDescription": "Sends a notification when media becomes available.",
|
"components.NotificationTypeSelector.mediaavailableDescription": "Sends a notification when media becomes available.",
|
||||||
|
"components.NotificationTypeSelector.mediadeclined": "Media Declined",
|
||||||
|
"components.NotificationTypeSelector.mediadeclinedDescription": "Sends a notification when a request is declined.",
|
||||||
"components.NotificationTypeSelector.mediafailed": "Media Failed",
|
"components.NotificationTypeSelector.mediafailed": "Media Failed",
|
||||||
"components.NotificationTypeSelector.mediafailedDescription": "Sends a notification when media fails to be added to services (Radarr/Sonarr). For certain agents, this will only send the notification to admins or users with the \"Manage Requests\" permission.",
|
"components.NotificationTypeSelector.mediafailedDescription": "Sends a notification when media fails to be added to services (Radarr/Sonarr). For certain agents, this will only send the notification to admins or users with the \"Manage Requests\" permission.",
|
||||||
"components.NotificationTypeSelector.mediarequested": "Media Requested",
|
"components.NotificationTypeSelector.mediarequested": "Media Requested",
|
||||||
|
Reference in New Issue
Block a user