feat(notif): auto-request notif type (#2956)

pull/2957/head
TheCatLady 2 years ago committed by GitHub
parent 301f2bf7ab
commit 6c0fd40877
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -480,6 +480,10 @@ export class MediaRequest {
}
this.sendNotification(media, Notification.MEDIA_PENDING);
if (this.isAutoRequest) {
this.sendNotification(media, Notification.MEDIA_AUTO_REQUESTED);
}
}
}
@ -524,6 +528,14 @@ export class MediaRequest {
: Notification.MEDIA_APPROVED
: Notification.MEDIA_DECLINED
);
if (
this.status === MediaRequestStatus.APPROVED &&
autoApproved &&
this.isAutoRequest
) {
this.sendNotification(media, Notification.MEDIA_AUTO_REQUESTED);
}
}
}
@ -1062,6 +1074,7 @@ export class MediaRequest {
const mediaType = this.type === MediaType.MOVIE ? 'Movie' : 'Series';
let event: string | undefined;
let notifyAdmin = true;
let notifySystem = true;
switch (type) {
case Notification.MEDIA_APPROVED:
@ -1075,6 +1088,13 @@ export class MediaRequest {
case Notification.MEDIA_PENDING:
event = `New ${this.is4k ? '4K ' : ''}${mediaType} Request`;
break;
case Notification.MEDIA_AUTO_REQUESTED:
event = `${
this.is4k ? '4K ' : ''
}${mediaType} Request Automatically Submitted`;
notifyAdmin = false;
notifySystem = false;
break;
case Notification.MEDIA_AUTO_APPROVED:
event = `${
this.is4k ? '4K ' : ''
@ -1091,6 +1111,7 @@ export class MediaRequest {
media,
request: this,
notifyAdmin,
notifySystem,
notifyUser: notifyAdmin ? undefined : this.requestedBy,
event,
subject: `${movie.title}${
@ -1109,6 +1130,7 @@ export class MediaRequest {
media,
request: this,
notifyAdmin,
notifySystem,
notifyUser: notifyAdmin ? undefined : this.requestedBy,
event,
subject: `${tv.name}${

@ -9,6 +9,7 @@ import type { NotificationAgentConfig } from '../../settings';
export interface NotificationPayload {
event?: string;
subject: string;
notifySystem: boolean;
notifyAdmin: boolean;
notifyUser?: User;
media?: Media;

@ -243,7 +243,10 @@ class DiscordAgent
): Promise<boolean> {
const settings = this.getSettings();
if (!hasNotificationType(type, settings.types ?? 0)) {
if (
!payload.notifySystem ||
!hasNotificationType(type, settings.types ?? 0)
) {
return true;
}

@ -81,6 +81,11 @@ class EmailAgent
is4k ? 'in 4K ' : ''
}is pending approval:`;
break;
case Notification.MEDIA_AUTO_REQUESTED:
body = `A new request for the following ${mediaType} ${
is4k ? 'in 4K ' : ''
}was automatically submitted:`;
break;
case Notification.MEDIA_APPROVED:
body = `Your request for the following ${mediaType} ${
is4k ? 'in 4K ' : ''

@ -117,7 +117,10 @@ class GotifyAgent
): Promise<boolean> {
const settings = this.getSettings();
if (!hasNotificationType(type, settings.types ?? 0)) {
if (
!payload.notifySystem ||
!hasNotificationType(type, settings.types ?? 0)
) {
return true;
}

@ -87,7 +87,10 @@ class LunaSeaAgent
): Promise<boolean> {
const settings = this.getSettings();
if (!hasNotificationType(type, settings.types ?? 0)) {
if (
!payload.notifySystem ||
!hasNotificationType(type, settings.types ?? 0)
) {
return true;
}

@ -5,6 +5,7 @@ import {
shouldSendAdminNotification,
} from '..';
import { IssueStatus, IssueTypeName } from '../../../constants/issue';
import { MediaStatus } from '../../../constants/media';
import { getRepository } from '../../../datasource';
import { User } from '../../../entity/User';
import logger from '../../../logger';
@ -52,6 +53,12 @@ class PushbulletAgent
let status = '';
switch (type) {
case Notification.MEDIA_AUTO_REQUESTED:
status =
payload.media?.status === MediaStatus.PENDING
? 'Pending Approval'
: 'Processing';
break;
case Notification.MEDIA_PENDING:
status = 'Pending Approval';
break;
@ -104,6 +111,7 @@ class PushbulletAgent
// Send system notification
if (
payload.notifySystem &&
hasNotificationType(type, settings.types ?? 0) &&
settings.enabled &&
settings.options.accessToken

@ -5,6 +5,7 @@ import {
shouldSendAdminNotification,
} from '..';
import { IssueStatus, IssueTypeName } from '../../../constants/issue';
import { MediaStatus } from '../../../constants/media';
import { getRepository } from '../../../datasource';
import { User } from '../../../entity/User';
import logger from '../../../logger';
@ -61,6 +62,12 @@ class PushoverAgent
let status = '';
switch (type) {
case Notification.MEDIA_AUTO_REQUESTED:
status =
payload.media?.status === MediaStatus.PENDING
? 'Pending Approval'
: 'Processing';
break;
case Notification.MEDIA_PENDING:
status = 'Pending Approval';
break;
@ -135,6 +142,7 @@ class PushoverAgent
// Send system notification
if (
payload.notifySystem &&
hasNotificationType(type, settings.types ?? 0) &&
settings.enabled &&
settings.options.accessToken &&

@ -225,7 +225,10 @@ class SlackAgent
): Promise<boolean> {
const settings = this.getSettings();
if (!hasNotificationType(type, settings.types ?? 0)) {
if (
!payload.notifySystem ||
!hasNotificationType(type, settings.types ?? 0)
) {
return true;
}

@ -5,6 +5,7 @@ import {
shouldSendAdminNotification,
} from '..';
import { IssueStatus, IssueTypeName } from '../../../constants/issue';
import { MediaStatus } from '../../../constants/media';
import { getRepository } from '../../../datasource';
import { User } from '../../../entity/User';
import logger from '../../../logger';
@ -79,6 +80,12 @@ class TelegramAgent
let status = '';
switch (type) {
case Notification.MEDIA_AUTO_REQUESTED:
status =
payload.media?.status === MediaStatus.PENDING
? 'Pending Approval'
: 'Processing';
break;
case Notification.MEDIA_PENDING:
status = 'Pending Approval';
break;
@ -157,6 +164,7 @@ class TelegramAgent
// Send system notification
if (
payload.notifySystem &&
hasNotificationType(type, settings.types ?? 0) &&
settings.options.chatId
) {

@ -164,7 +164,10 @@ class WebhookAgent
): Promise<boolean> {
const settings = this.getSettings();
if (!hasNotificationType(type, settings.types ?? 0)) {
if (
!payload.notifySystem ||
!hasNotificationType(type, settings.types ?? 0)
) {
return true;
}

@ -57,6 +57,11 @@ class WebPushAgent
case Notification.TEST_NOTIFICATION:
message = payload.message;
break;
case Notification.MEDIA_AUTO_REQUESTED:
message = `Automatically submitted a new ${
is4k ? '4K ' : ''
}${mediaType} request.`;
break;
case Notification.MEDIA_APPROVED:
message = `Your ${
is4k ? '4K ' : ''

@ -16,6 +16,7 @@ export enum Notification {
ISSUE_COMMENT = 512,
ISSUE_RESOLVED = 1024,
ISSUE_REOPENED = 2048,
MEDIA_AUTO_REQUESTED = 4096,
}
export const hasNotificationType = (

@ -1,4 +1,3 @@
import { Not } from 'typeorm';
import PlexTvAPI from '../api/plextv';
import { User } from '../entity/User';
import Media from '../entity/Media';
@ -20,12 +19,12 @@ class WatchlistSync {
const userRepository = getRepository(User);
// Get users who actually have plex tokens
const users = await userRepository.find({
select: { id: true, plexToken: true, permissions: true },
where: {
plexToken: Not(''),
},
});
const users = await userRepository
.createQueryBuilder('user')
.addSelect('user.plexToken')
.leftJoinAndSelect('user.settings', 'settings')
.where("user.plexToken != ''")
.getMany();
for (const user of users) {
await this.syncUserWatchlist(user);
@ -36,7 +35,7 @@ class WatchlistSync {
if (!user.plexToken) {
logger.warn('Skipping user watchlist sync for user without plex token', {
label: 'Plex Watchlist Sync',
userId: user.id,
user: user.displayName,
});
return;
}

@ -18,6 +18,7 @@ const notificationRoutes = Router();
const sendTestNotification = async (agent: NotificationAgent, user: User) =>
await agent.send(Notification.TEST_NOTIFICATION, {
notifySystem: true,
notifyAdmin: false,
notifyUser: user,
subject: 'Test Notification',
@ -247,7 +248,7 @@ notificationRoutes.post('/webpush/test', async (req, res, next) => {
if (!req.user) {
return next({
status: 500,
message: 'User information missing from request',
message: 'User information is missing from the request.',
});
}
@ -363,7 +364,7 @@ notificationRoutes.post('/lunasea/test', async (req, res, next) => {
if (!req.user) {
return next({
status: 500,
message: 'User information missing from request',
message: 'User information is missing from the request.',
});
}
@ -384,34 +385,26 @@ notificationRoutes.get('/gotify', (_req, res) => {
res.status(200).json(settings.notifications.agents.gotify);
});
notificationRoutes.post('/gotify', (req, rest) => {
notificationRoutes.post('/gotify', (req, res) => {
const settings = getSettings();
settings.notifications.agents.gotify = req.body;
settings.save();
rest.status(200).json(settings.notifications.agents.gotify);
res.status(200).json(settings.notifications.agents.gotify);
});
notificationRoutes.post('/gotify/test', async (req, rest, next) => {
notificationRoutes.post('/gotify/test', async (req, res, next) => {
if (!req.user) {
return next({
status: 500,
message: 'User information is missing from request',
message: 'User information is missing from the request.',
});
}
const gotifyAgent = new GotifyAgent(req.body);
if (
await gotifyAgent.send(Notification.TEST_NOTIFICATION, {
notifyAdmin: false,
notifyUser: req.user,
subject: 'Test Notification',
message:
'This is a test notification! Check check, 1, 2, 3. Are we coming in clear?',
})
) {
return rest.status(204).send();
if (await sendTestNotification(gotifyAgent, req.user)) {
return res.status(204).send();
} else {
return next({
status: 500,

@ -69,6 +69,7 @@ export class IssueCommentSubscriber
media,
image,
notifyAdmin: true,
notifySystem: true,
notifyUser:
!issue.createdBy.hasPermission(Permission.MANAGE_ISSUES) &&
issue.createdBy.id !== entity.user.id

@ -84,6 +84,7 @@ export class IssueSubscriber implements EntitySubscriberInterface<Issue> {
image,
extra,
notifyAdmin: true,
notifySystem: true,
notifyUser:
!entity.createdBy.hasPermission(Permission.MANAGE_ISSUES) &&
(type === Notification.ISSUE_RESOLVED ||

@ -45,6 +45,7 @@ export class MediaSubscriber implements EntitySubscriberInterface<Media> {
{
event: `${is4k ? '4K ' : ''}Movie Request Now Available`,
notifyAdmin: false,
notifySystem: true,
notifyUser: request.requestedBy,
subject: `${movie.title}${
movie.release_date
@ -143,6 +144,7 @@ export class MediaSubscriber implements EntitySubscriberInterface<Media> {
omission: '…',
}),
notifyAdmin: false,
notifySystem: true,
notifyUser: request.requestedBy,
image: `https://image.tmdb.org/t/p/w600_and_h900_bestv2${tv.poster_path}`,
media: entity,

@ -60,6 +60,9 @@ const messages = defineMessages({
'Get notified when issues you reported are reopened.',
adminissuereopenedDescription:
'Get notified when issues are reopened by other users.',
mediaautorequested: 'Request Automatically Submitted',
mediaautorequestedDescription:
'Get notified when new media requests are automatically submitted for items on your Plex Watchlist.',
});
export const hasNotificationType = (
@ -101,6 +104,7 @@ export enum Notification {
ISSUE_COMMENT = 512,
ISSUE_RESOLVED = 1024,
ISSUE_REOPENED = 2048,
MEDIA_AUTO_REQUESTED = 4096,
}
export const ALL_NOTIFICATIONS = Object.values(Notification)
@ -191,6 +195,25 @@ const NotificationTypeSelector = ({
))));
const types: NotificationItem[] = [
{
id: 'media-auto-requested',
name: intl.formatMessage(messages.mediaautorequested),
description: intl.formatMessage(messages.mediaautorequestedDescription),
value: Notification.MEDIA_AUTO_REQUESTED,
hidden:
!user ||
(!user.settings?.watchlistSyncMovies &&
!user.settings?.watchlistSyncTv) ||
!hasPermission(
[
Permission.AUTO_REQUEST,
Permission.AUTO_REQUEST_MOVIE,
Permission.AUTO_REQUEST_TV,
],
{ type: 'or' }
),
hasNotifyUser: true,
},
{
id: 'media-requested',
name: intl.formatMessage(messages.mediarequested),

@ -31,6 +31,8 @@ export interface UserSettings {
originalLanguage?: string;
locale?: string;
notificationTypes: Partial<NotificationAgentTypes>;
watchlistSyncMovies?: boolean;
watchlistSyncTv?: boolean;
}
interface UserHookResponse {

@ -197,6 +197,8 @@
"components.NotificationTypeSelector.mediaAutoApprovedDescription": "Send notifications when users submit new media requests which are automatically approved.",
"components.NotificationTypeSelector.mediaapproved": "Request Approved",
"components.NotificationTypeSelector.mediaapprovedDescription": "Send notifications when media requests are manually approved.",
"components.NotificationTypeSelector.mediaautorequested": "Request Automatically Submitted",
"components.NotificationTypeSelector.mediaautorequestedDescription": "Get notified when new media requests are automatically submitted for items on your Plex Watchlist.",
"components.NotificationTypeSelector.mediaavailable": "Request Available",
"components.NotificationTypeSelector.mediaavailableDescription": "Send notifications when media requests become available.",
"components.NotificationTypeSelector.mediadeclined": "Request Declined",

Loading…
Cancel
Save