Recv/lib/workers/notification.js

242 lines
5.6 KiB
JavaScript

const async = require('async');
const nodemailer = require('nodemailer');
const Email = require('email-templates');
const fs = require('mz/fs');
const path = require('path');
const getPaths = require('get-paths');
const AbstractIntervalWorker = require('./abstractintervalworker');
const NotificationType = require('../repository/notification').NotificationType;
const _ = require('lodash');
function humanFileSize(bytes, si)
{
var thresh = si ? 1000 : 1024;
if(Math.abs(bytes) < thresh)
{
return bytes + ' B';
}
var units = si
? ['kB','MB','GB','TB','PB','EB','ZB','YB']
: ['KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB'];
var u = -1;
do
{
bytes /= thresh;
++u;
}
while(Math.abs(bytes) >= thresh && u < units.length - 1);
return bytes.toFixed(1) + ' ' + units[u];
}
class NotificationWorker extends AbstractIntervalWorker
{
constructor(repository)
{
super();
this.repository = repository;
}
async tick()
{
var self = this;
var notifications = await self.repository.notifications.list();
return new Promise((resolve, reject) =>
{
async.eachOfSeries(notifications,
async (item) => { await self.handleNotification(item) },
(err) =>
{
if (err)
reject(err);
else
resolve();
});
})
}
async handleNotification(notification)
{
let self = this;
let user = await self.repository.users.get(notification.userId);
if (user === null || !user.email)
return;
switch (notification.type)
{
case NotificationType.UploadComplete:
await self.sendUploadNotification(notification, user);
break;
case NotificationType.CodeMoved:
await self.sendCodeMovedNotification(notification, user);
break;
}
}
getDefaultLocals(user)
{
return {
// Data
user: user,
// Configuration
adminUrl: config.notifications.adminUrl,
// Helper functions
humanFileSize: humanFileSize
}
}
async sendUploadNotification(notification, user)
{
let self = this;
let locals = self.getDefaultLocals(user);
locals.upload = await self.repository.uploads.get(notification.uploadId);
if (locals.upload === null)
return;
await self.sendNotification(notification, user, locals, 'uploadnotification');
}
async sendCodeMovedNotification(notification, user)
{
let self = this;
let locals = self.getDefaultLocals(user);
locals.uploads = await self.repository.uploads.listForCode(notification.codeId);
if (locals.uploads === null || locals.uploads.length == 0)
return;
locals.fileCount = 0;
_.forEach(locals.uploads, (upload) =>
{
locals.fileCount += upload.files.length;
});
locals.prevUser = {
userId: null,
name: ''
};
if (notification.metadata !== null)
{
let resolveUser = async (userId) =>
{
if (!userId)
return null;
let user = await self.repository.users.get(userId);
if (user !== null)
{
return {
userId: userId,
name: user.name
}
}
};
locals.prevUser = await resolveUser(notification.metadata.prevUserId);
locals.assignUser = await resolveUser(notification.metadata.assignUserId);
}
await self.sendNotification(notification, user, locals, 'movednotification');
}
async sendNotification(notification, user, locals, template)
{
let self = this;
return new Promise((resolve, reject) =>
{
const email = new Email({
message: {
from: config.notifications.mail.from
},
send: true,
preview: false,
transport: nodemailer.createTransport(config.notifications.mail.transport),
views: {
options: {
extension: 'ejs'
}
}
});
// Override the default template locator with one that checks
// the custom folder first, then falls back to the configured folder
let getTemplatePathFromRoot = function(root, view, ext)
{
return new Promise(async (resolve, reject) => {
try {
const paths = await getPaths(
root,
view,
ext
);
const filePath = path.resolve(root, paths.rel);
resolve({ filePath, paths });
} catch (err) {
reject(err);
}
});
};
email.getTemplatePath = async function(view)
{
try
{
return await getTemplatePathFromRoot(path.resolve('custom/emails'), view, this.config.views.options.extension);
}
catch (err)
{
return await getTemplatePathFromRoot(this.config.views.root, view, this.config.views.options.extension);
}
};
email
.send({
template: template,
message: {
to: user.email
},
locals: locals
})
.then(async () =>
{
await self.repository.notifications.delete(notification.id);
console.log('Notification sent to: ' + user.email);
resolve();
})
.catch(async (error) =>
{
console.log(error);
notification.attempt++;
if (notification.attempt > config.notifications.maxAttempts)
await self.repository.notifications.delete(notification.id);
else
await self.repository.notifications.update(notification);
resolve();
});
});
}
}
module.exports = NotificationWorker;