DTP Social Engine
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

137 lines
3.7 KiB

// user-notification.js
// Copyright (C) 2022 DTP Technologies, LLC
// License: Apache-2.0
'use strict';
const path = require('path');
const mongoose = require('mongoose');
const UserNotification = mongoose.model('UserNotification');
const pug = require('pug');
const { SiteService } = require('../../lib/site-lib');
class UserNotificationService extends SiteService {
constructor (dtp) {
super(dtp, module.exports);
this.populateUserNotification = [
{
path: 'user',
select: '_id username username_lc displayName picture',
},
{
path: 'event',
populate: [
{
path: 'attachment',
},
],
},
];
}
async start ( ) {
await super.start();
this.templates = { };
this.templates.notification = pug.compileFile(path.join(this.dtp.config.root, 'app', 'views', 'notification', 'components', 'notification-standalone.pug'));
}
middleware (options) {
options = Object.assign({
withNotifications: false,
}, options || { });
return async (req, res, next) => {
res.locals.middleware = res.locals.middleware || { };
const data = res.locals.middleware.notifications = { };
if (!req.user) {
// requests with no user don't matter to this middleware
return next();
}
try {
data.newCount = await this.getNewCountForUser(req.user);
if (options.withNotifications) {
data.new = await this.getForUser(req.user, { skip: 0, cpp: 10 });
}
return next();
} catch (error) {
this.log.error('failed to populate route with notifications data', { error });
return next(error);
}
};
}
async create (user, event) {
const notification = new UserNotification();
notification.created = event.created;
notification.user = user._id;
notification.status = 'new';
notification.event = event._id;
await notification.save();
await this.dtp.redis.hincrby(`user:${user._id}:notification`, 'newCount', 1);
return notification.toObject();
}
async getNewCountForUser (user) {
const userKey = `user:${user._id}:notification`;
let count;
const value = await this.dtp.redis.hget(userKey, 'newCount');
if (!value) {
count = await UserNotification.countDocuments({ user: user._id, status: 'new' });
await this.dtp.redis.hset(userKey, 'newCount', count);
return count;
}
count = parseInt(value, 10);
if (count < 0) {
count = await UserNotification.countDocuments({ user: user._id, status: 'new' });
await this.dtp.redis.hset(userKey, 'newCount', count);
}
return count;
}
async getForUser (user, pagination) {
const notifications = await UserNotification
.find({ user: user._id })
.sort({ created: -1 })
.skip(pagination.skip)
.limit(pagination.cpp)
.populate(this.populateUserNotification)
.lean();
const newNotifications = notifications.filter((notif) => notif.status === 'new');
if (newNotifications.length > 0) {
await UserNotification.updateMany(
{ _id: { $in: newNotifications.map((notif) => notif._id) } },
{ $set: { status: 'seen' } },
);
await this.dtp.redis.hincrby(
`user:${user._id}:notification`,
'newCount',
-(newNotifications.length),
);
}
return notifications;
}
async getById (notificationId) {
const notification = await UserNotification
.findById(notificationId)
.populate(this.populateUserNotification)
.lean();
return notification;
}
}
module.exports = {
name: 'userNotification',
slug: 'user-notification',
create: (dtp) => { return new UserNotificationService(dtp); },
};