src/app/core/user/inactive/inactive-user.job.ts
import { Job } from 'agenda';
import _ from 'lodash';
import { DateTime } from 'luxon';
import { FilterQuery } from 'mongoose';
import { config, emailService, auditService } from '../../../../dependencies';
import { logger } from '../../../../lib/logger';
import { JobService } from '../../../common/agenda/job-service';
import { User, UserDocument } from '../user.model';
/**
* alert users whose accounts have been inactive for 30-89 days. Remove accounts that have been inactive for 90+ days
*/
export default class InactiveUsersJobService implements JobService {
async sendEmail(user, emailConfig) {
// This current DateTime may be a millisecond or two later than user.lastLogin due to Luxon's precision, so we round down to the number of days.
const numOfDays = Math.floor(
DateTime.now().diff(DateTime.fromMillis(user.lastLogin)).as('days')
);
try {
const mailOptions = await emailService.generateMailOptions(
user,
null,
emailConfig,
{
daysAgo: numOfDays
},
{},
{
to: user.email
}
);
await emailService.sendMail(mailOptions);
logger.debug('Sent team request email');
} catch (error) {
// Log the error but this shouldn't block
logger.error('Failure sending email.', { err: error });
}
}
async deactivationAlert(dQuery: FilterQuery<UserDocument>) {
const deactivatedUsers = await User.find(dQuery).exec();
if (_.isArray(deactivatedUsers)) {
const promises = deactivatedUsers.map(async (user) => {
const originalUser = user.auditCopy();
user.roles.admin = false;
user.roles.user = false;
user.markModified('roles');
await user.save();
await this.sendEmail(user, config.get('coreEmails.userDeactivate'));
await auditService.audit(
'deactivation due to inactivity',
'user',
'deactivation',
null,
{ before: originalUser, after: user.auditCopy() },
null
);
});
return Promise.all(promises);
}
}
async inactivityAlert(dQuery: FilterQuery<UserDocument>) {
const inactiveUsers = await User.find(dQuery).exec();
return Promise.all(
inactiveUsers.map((user) =>
this.sendEmail(user, config.get('coreEmails.userInactivity'))
)
);
}
async run(job: Job) {
const alertQueries = job.attrs.data.alertIntervals.map((interval) => ({
lastLogin: {
$lte: DateTime.now().minus({ milliseconds: interval }).toJSDate(),
$gt: DateTime.now()
.minus({ milliseconds: interval, days: 1 })
.toJSDate()
},
'roles.user': true
}));
const deactivateQuery = {
lastLogin: {
$lte: DateTime.now()
.minus({ milliseconds: job.attrs.data.deactivateAfter })
.toJSDate()
},
'roles.user': true
};
await Promise.all([
this.deactivationAlert(deactivateQuery),
...alertQueries.map((query) => this.inactivityAlert(query))
]).then();
}
}