no ui yet built to configure it and currently only handles MEDIA_PENDING notification typespull/183/head
parent
0601b44687
commit
0962392e39
@ -0,0 +1,106 @@
|
|||||||
|
import type { NotificationAgent, NotificationPayload } from './agent';
|
||||||
|
import { Notification } from '..';
|
||||||
|
import path from 'path';
|
||||||
|
import { getSettings } from '../../settings';
|
||||||
|
import nodemailer from 'nodemailer';
|
||||||
|
import Email from 'email-templates';
|
||||||
|
import logger from '../../../logger';
|
||||||
|
import { getRepository } from 'typeorm';
|
||||||
|
import { User } from '../../../entity/User';
|
||||||
|
import { hasPermission, Permission } from '../../permissions';
|
||||||
|
|
||||||
|
class EmailAgent implements NotificationAgent {
|
||||||
|
public shouldSend(type: Notification): boolean {
|
||||||
|
const settings = getSettings();
|
||||||
|
|
||||||
|
if (settings.notifications.agents.email.enabled) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getSmtpTransport() {
|
||||||
|
const emailSettings = getSettings().notifications.agents.email.options;
|
||||||
|
|
||||||
|
return nodemailer.createTransport({
|
||||||
|
host: emailSettings.smtpHost,
|
||||||
|
port: emailSettings.smtpPort,
|
||||||
|
secure: emailSettings.secure,
|
||||||
|
auth: {
|
||||||
|
user: emailSettings.authUser,
|
||||||
|
pass: emailSettings.authPass,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private getNewEmail() {
|
||||||
|
return new Email({
|
||||||
|
message: {
|
||||||
|
from: 'no-reply@os.sct.dev',
|
||||||
|
},
|
||||||
|
send: true,
|
||||||
|
transport: this.getSmtpTransport(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async sendMediaRequestEmail(payload: NotificationPayload) {
|
||||||
|
const settings = getSettings().main;
|
||||||
|
try {
|
||||||
|
const userRepository = getRepository(User);
|
||||||
|
const users = await userRepository.find();
|
||||||
|
|
||||||
|
// Send to all users with the manage requests permission (or admins)
|
||||||
|
users
|
||||||
|
.filter((user) => user.hasPermission(Permission.MANAGE_REQUESTS))
|
||||||
|
.forEach((user) => {
|
||||||
|
const email = this.getNewEmail();
|
||||||
|
logger.debug('Sending email notification', {
|
||||||
|
label: 'Notifications',
|
||||||
|
});
|
||||||
|
|
||||||
|
email.send({
|
||||||
|
template: path.join(
|
||||||
|
__dirname,
|
||||||
|
'../../../templates/email/media-request'
|
||||||
|
),
|
||||||
|
message: {
|
||||||
|
to: user.email,
|
||||||
|
},
|
||||||
|
locals: {
|
||||||
|
body: 'A user has requested new media!',
|
||||||
|
mediaName: payload.subject,
|
||||||
|
imageUrl: payload.image,
|
||||||
|
timestamp: new Date().toTimeString(),
|
||||||
|
requestedBy: payload.notifyUser.username,
|
||||||
|
actionUrl: settings.applicationUrl,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
logger.error('Mail notification failed to send', {
|
||||||
|
label: 'Notifications',
|
||||||
|
message: e.message,
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async send(
|
||||||
|
type: Notification,
|
||||||
|
payload: NotificationPayload
|
||||||
|
): Promise<boolean> {
|
||||||
|
logger.debug('Sending email notification', { label: 'Notifications' });
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case Notification.MEDIA_PENDING:
|
||||||
|
this.sendMediaRequestEmail(payload);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EmailAgent;
|
@ -0,0 +1,114 @@
|
|||||||
|
doctype html
|
||||||
|
head
|
||||||
|
meta(charset='utf-8')
|
||||||
|
meta(name='x-apple-disable-message-reformatting')
|
||||||
|
meta(http-equiv='x-ua-compatible' content='ie=edge')
|
||||||
|
meta(name='viewport' content='width=device-width, initial-scale=1')
|
||||||
|
meta(name='format-detection' content='telephone=no, date=no, address=no, email=no')
|
||||||
|
link(href='https://fonts.googleapis.com/css?family=Nunito+Sans:400,700&display=swap' rel='stylesheet' media='screen')
|
||||||
|
//if mso
|
||||||
|
xml
|
||||||
|
o:officedocumentsettings
|
||||||
|
o:pixelsperinch 96
|
||||||
|
style.
|
||||||
|
td,
|
||||||
|
th,
|
||||||
|
div,
|
||||||
|
p,
|
||||||
|
a,
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
|
font-family: 'Segoe UI', sans-serif;
|
||||||
|
mso-line-height-rule: exactly;
|
||||||
|
}
|
||||||
|
style.
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.sm-w-full {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div(role='article' aria-roledescription='email' aria-label='' lang='en')
|
||||||
|
table(style="\
|
||||||
|
background-color: #f2f4f6;\
|
||||||
|
font-family: 'Nunito Sans', -apple-system, 'Segoe UI', sans-serif;\
|
||||||
|
width: 100%;\
|
||||||
|
" width='100%' bgcolor='#f2f4f6' cellpadding='0' cellspacing='0' role='presentation')
|
||||||
|
tr
|
||||||
|
td(align='center')
|
||||||
|
table(style='width: 100%' width='100%' cellpadding='0' cellspacing='0' role='presentation')
|
||||||
|
tr
|
||||||
|
td(align='center' style='\
|
||||||
|
font-size: 16px;\
|
||||||
|
padding-top: 25px;\
|
||||||
|
padding-bottom: 25px;\
|
||||||
|
text-align: center;\
|
||||||
|
')
|
||||||
|
a(href='https://example.com' style='\
|
||||||
|
text-shadow: 0 1px 0 #ffffff;\
|
||||||
|
font-weight: 700;\
|
||||||
|
font-size: 16px;\
|
||||||
|
color: #a8aaaf;\
|
||||||
|
text-decoration: none;\
|
||||||
|
')
|
||||||
|
| Overseerr
|
||||||
|
tr
|
||||||
|
td(style='width: 100%' width='100%')
|
||||||
|
table.sm-w-full(align='center' style='\
|
||||||
|
background-color: #ffffff;\
|
||||||
|
margin-left: auto;\
|
||||||
|
margin-right: auto;\
|
||||||
|
width: 570px;\
|
||||||
|
' width='570' bgcolor='#ffffff' cellpadding='0' cellspacing='0' role='presentation')
|
||||||
|
tr
|
||||||
|
td(style='padding: 45px')
|
||||||
|
div(style='font-size: 16px')
|
||||||
|
| #{body}
|
||||||
|
br
|
||||||
|
br
|
||||||
|
p(style='margin-top: 4px; text-align: center')
|
||||||
|
| #{mediaName}
|
||||||
|
table(cellpadding='0' cellspacing='0' role='presentation')
|
||||||
|
tr
|
||||||
|
td
|
||||||
|
table(cellpadding='0' cellspacing='0' role='presentation')
|
||||||
|
img(src=imageUrl alt='')
|
||||||
|
p
|
||||||
|
p(style='\
|
||||||
|
font-size: 16px;\
|
||||||
|
line-height: 24px;\
|
||||||
|
margin-top: 6px;\
|
||||||
|
margin-bottom: 20px;\
|
||||||
|
color: #51545e;\
|
||||||
|
')
|
||||||
|
| Requested by #{requestedBy} at #{timestamp}
|
||||||
|
p(style='\
|
||||||
|
font-size: 13px;\
|
||||||
|
line-height: 24px;\
|
||||||
|
margin-top: 6px;\
|
||||||
|
margin-bottom: 20px;\
|
||||||
|
color: #51545e;\
|
||||||
|
')
|
||||||
|
a(href=actionUrl style='color: #3869d4') Open Overseerr
|
||||||
|
tr
|
||||||
|
td
|
||||||
|
table.sm-w-full(align='center' style='\
|
||||||
|
margin-left: auto;\
|
||||||
|
margin-right: auto;\
|
||||||
|
text-align: center;\
|
||||||
|
width: 570px;\
|
||||||
|
' width='570' cellpadding='0' cellspacing='0' role='presentation')
|
||||||
|
tr
|
||||||
|
td(align='center' style='font-size: 16px; padding: 45px')
|
||||||
|
p(style='\
|
||||||
|
font-size: 13px;\
|
||||||
|
line-height: 24px;\
|
||||||
|
margin-top: 6px;\
|
||||||
|
margin-bottom: 20px;\
|
||||||
|
text-align: center;\
|
||||||
|
color: #a8aaaf;\
|
||||||
|
')
|
||||||
|
| Overseerr.
|
@ -0,0 +1,224 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html
|
||||||
|
lang="en"
|
||||||
|
xmlns:v="urn:schemas-microsoft-com:vml"
|
||||||
|
xmlns:o="urn:schemas-microsoft-com:office:office"
|
||||||
|
>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="x-apple-disable-message-reformatting" />
|
||||||
|
<meta http-equiv="x-ua-compatible" content="ie=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<meta
|
||||||
|
name="format-detection"
|
||||||
|
content="telephone=no, date=no, address=no, email=no"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
href="https://fonts.googleapis.com/css?family=Nunito+Sans:400,700&amp;display=swap"
|
||||||
|
rel="stylesheet"
|
||||||
|
media="screen"
|
||||||
|
/>
|
||||||
|
<!--[if mso]>
|
||||||
|
<xml
|
||||||
|
><o:OfficeDocumentSettings
|
||||||
|
><o:PixelsPerInch>96</o:PixelsPerInch></o:OfficeDocumentSettings
|
||||||
|
></xml
|
||||||
|
>
|
||||||
|
<style>
|
||||||
|
td,
|
||||||
|
th,
|
||||||
|
div,
|
||||||
|
p,
|
||||||
|
a,
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
|
font-family: 'Segoe UI', sans-serif;
|
||||||
|
mso-line-height-rule: exactly;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<![endif]-->
|
||||||
|
<style>
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.sm-w-full {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body
|
||||||
|
style="
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
word-break: break-word;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
background-color: #f2f4f6;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<div role="article" aria-roledescription="email" aria-label="" lang="en">
|
||||||
|
<table
|
||||||
|
style="
|
||||||
|
background-color: #f2f4f6;
|
||||||
|
font-family: 'Nunito Sans', -apple-system, 'Segoe UI', sans-serif;
|
||||||
|
width: 100%;
|
||||||
|
"
|
||||||
|
width="100%"
|
||||||
|
bgcolor="#f2f4f6"
|
||||||
|
cellpadding="0"
|
||||||
|
cellspacing="0"
|
||||||
|
role="presentation"
|
||||||
|
>
|
||||||
|
<tr>
|
||||||
|
<td align="center">
|
||||||
|
<table
|
||||||
|
style="width: 100%"
|
||||||
|
width="100%"
|
||||||
|
cellpadding="0"
|
||||||
|
cellspacing="0"
|
||||||
|
role="presentation"
|
||||||
|
>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
align="center"
|
||||||
|
style="
|
||||||
|
font-size: 16px;
|
||||||
|
padding-top: 25px;
|
||||||
|
padding-bottom: 25px;
|
||||||
|
text-align: center;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="https://example.com"
|
||||||
|
style="
|
||||||
|
text-shadow: 0 1px 0 #ffffff;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #a8aaaf;
|
||||||
|
text-decoration: none;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
Overseerr
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="width: 100%" width="100%">
|
||||||
|
<table
|
||||||
|
align="center"
|
||||||
|
class="sm-w-full"
|
||||||
|
style="
|
||||||
|
background-color: #ffffff;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
width: 570px;
|
||||||
|
"
|
||||||
|
width="570"
|
||||||
|
bgcolor="#ffffff"
|
||||||
|
cellpadding="0"
|
||||||
|
cellspacing="0"
|
||||||
|
role="presentation"
|
||||||
|
>
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 45px">
|
||||||
|
<div style="font-size: 16px">
|
||||||
|
{{body}}
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<p style="margin-top: 4px; text-align: center">
|
||||||
|
{{media_name}
|
||||||
|
</p>
|
||||||
|
<table
|
||||||
|
cellpadding="0"
|
||||||
|
cellspacing="0"
|
||||||
|
role="presentation"
|
||||||
|
>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<table
|
||||||
|
cellpadding="0"
|
||||||
|
cellspacing="0"
|
||||||
|
role="presentation"
|
||||||
|
>
|
||||||
|
<img src="{{image_url}}" alt="" />
|
||||||
|
<p></p>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<p
|
||||||
|
style="
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 24px;
|
||||||
|
margin-top: 6px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
color: #51545e;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
Requested by {{requester_name}} at {{timestamp}}
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
style="
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 24px;
|
||||||
|
margin-top: 6px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
color: #51545e;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<a href="{{action_url}}" style="color: #3869d4"
|
||||||
|
>Open detail page</a
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<table
|
||||||
|
align="center"
|
||||||
|
class="sm-w-full"
|
||||||
|
style="
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
text-align: center;
|
||||||
|
width: 570px;
|
||||||
|
"
|
||||||
|
width="570"
|
||||||
|
cellpadding="0"
|
||||||
|
cellspacing="0"
|
||||||
|
role="presentation"
|
||||||
|
>
|
||||||
|
<tr>
|
||||||
|
<td align="center" style="font-size: 16px; padding: 45px">
|
||||||
|
<p
|
||||||
|
style="
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 24px;
|
||||||
|
margin-top: 6px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
text-align: center;
|
||||||
|
color: #a8aaaf;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
Overseerr.
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1 @@
|
|||||||
|
= `New Request: ${mediaName} - Overseerr`
|
Loading…
Reference in new issue