Add notification handling in editObject and utility functions
Some checks failed
farmcontrol/farmcontrol-ws/pipeline/head There was a failure building this commit
Some checks failed
farmcontrol/farmcontrol-ws/pipeline/head There was a failure building this commit
- Introduced notification functionality in the editObject method to notify users of changes when editing objects, enhancing user awareness of updates. - Added utility functions for creating and managing notifications, including omitSensitive for filtering sensitive data and notificationUserFromOwner for user retrieval based on owner type. - Updated SocketHost to support the new notify parameter, ensuring notifications can be triggered during object edits.
This commit is contained in:
parent
6e74e0dfec
commit
c36765cc47
@ -3,6 +3,7 @@ import {
|
||||
deleteAuditLog,
|
||||
expandObjectIds,
|
||||
editAuditLog,
|
||||
editNotification,
|
||||
distributeUpdate,
|
||||
newAuditLog,
|
||||
distributeNew,
|
||||
@ -423,7 +424,8 @@ export const editObject = async ({
|
||||
owner = undefined,
|
||||
ownerType = undefined,
|
||||
populate = [],
|
||||
auditLog = true
|
||||
auditLog = true,
|
||||
notify = true
|
||||
}) => {
|
||||
try {
|
||||
// Determine parentType from model name
|
||||
@ -464,6 +466,24 @@ export const editObject = async ({
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
notify == true &&
|
||||
owner != undefined &&
|
||||
ownerType != undefined &&
|
||||
parentType !== 'notification' &&
|
||||
parentType !== 'auditLog' &&
|
||||
parentType !== 'userNotifier'
|
||||
) {
|
||||
await editNotification(
|
||||
previousExpandedObject,
|
||||
newExpandedObject,
|
||||
id,
|
||||
parentType,
|
||||
owner,
|
||||
ownerType
|
||||
);
|
||||
}
|
||||
|
||||
// Distribute update
|
||||
await distributeUpdate(updateData, id, parentType);
|
||||
|
||||
|
||||
@ -1,9 +1,51 @@
|
||||
import { ObjectId } from 'mongodb';
|
||||
import { auditLogModel } from './schemas/management/auditlog.schema.js';
|
||||
import { notificationModel } from './schemas/misc/notification.schema.js';
|
||||
import { userNotifierModel } from './schemas/misc/usernotifier.schema.js';
|
||||
import { models } from './schemas/models.js';
|
||||
import { natsServer } from './nats.js';
|
||||
|
||||
import { customAlphabet } from 'nanoid';
|
||||
|
||||
const NOTIFICATION_EXCLUDED_MODELS = ['notification', 'userNotifier', 'auditLog'];
|
||||
const SENSITIVE_KEYS = ['secret'];
|
||||
|
||||
function omitSensitive(obj) {
|
||||
if (obj == null || typeof obj !== 'object') return obj;
|
||||
if (Array.isArray(obj)) return obj.map(omitSensitive);
|
||||
const result = {};
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
if (SENSITIVE_KEYS.includes(key)) continue;
|
||||
result[key] = omitSensitive(value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function getModelEntryByType(parentType) {
|
||||
return Object.values(models).find(
|
||||
entry => entry.type === parentType || entry.model?.modelName === parentType
|
||||
);
|
||||
}
|
||||
|
||||
function notificationUserFromOwner(owner, ownerType) {
|
||||
if (!owner) return null;
|
||||
if (ownerType === 'user') {
|
||||
return owner;
|
||||
}
|
||||
if (ownerType === 'host') {
|
||||
return {
|
||||
_id: owner._id,
|
||||
firstName: owner.name ?? 'unknown',
|
||||
lastName: ''
|
||||
};
|
||||
}
|
||||
return {
|
||||
_id: owner._id,
|
||||
firstName: owner.name ?? owner.firstName ?? 'unknown',
|
||||
lastName: owner.lastName ?? ''
|
||||
};
|
||||
}
|
||||
|
||||
const ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||
export const generateId = () => {
|
||||
// 10 characters
|
||||
@ -444,6 +486,86 @@ async function distributeNew(id, type) {
|
||||
await natsServer.publish(`${type}s.new`, id);
|
||||
}
|
||||
|
||||
async function editNotification(
|
||||
oldValue,
|
||||
newValue,
|
||||
parentId,
|
||||
parentType,
|
||||
owner,
|
||||
ownerType
|
||||
) {
|
||||
if (NOTIFICATION_EXCLUDED_MODELS.includes(parentType)) return;
|
||||
|
||||
const modelEntry = getModelEntryByType(parentType);
|
||||
const user = notificationUserFromOwner(owner, ownerType);
|
||||
const objectName =
|
||||
oldValue?.name ?? newValue?.name ?? modelEntry?.label ?? parentType;
|
||||
const changedOldValues = omitSensitive(getChangedValues(oldValue, newValue, true));
|
||||
const changedNewValues = omitSensitive(getChangedValues(oldValue, newValue, false));
|
||||
|
||||
if (
|
||||
Object.keys(changedOldValues).length === 0 ||
|
||||
Object.keys(changedNewValues).length === 0
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
await notfiyObjectUserNotifiers(
|
||||
parentId,
|
||||
parentType,
|
||||
`${objectName} edited by ${user?.firstName ?? 'unknown'} ${user?.lastName ?? ''}`,
|
||||
`The ${parentType} ${parentId} has been updated.`,
|
||||
'editObject',
|
||||
{
|
||||
old: changedOldValues,
|
||||
new: changedNewValues,
|
||||
objectType: parentType,
|
||||
object: { _id: String(parentId ?? '') },
|
||||
user: {
|
||||
_id: String(user?._id ?? ''),
|
||||
firstName: user?.firstName,
|
||||
lastName: user?.lastName
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
async function notfiyObjectUserNotifiers(
|
||||
id,
|
||||
objectType,
|
||||
title,
|
||||
message,
|
||||
type = 'info',
|
||||
metadata
|
||||
) {
|
||||
const userNotifiers = await userNotifierModel
|
||||
.find({ object: id, objectType })
|
||||
.populate('user');
|
||||
for (const userNotifier of userNotifiers) {
|
||||
await createNotification(
|
||||
userNotifier.user._id,
|
||||
title,
|
||||
message,
|
||||
type,
|
||||
metadata
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function createNotification(user, title, message, type = 'info', metadata) {
|
||||
const notification = new notificationModel({
|
||||
user,
|
||||
title,
|
||||
message,
|
||||
type,
|
||||
metadata: omitSensitive(metadata ?? {})
|
||||
});
|
||||
await notification.save();
|
||||
const value = notification.toJSON ? notification.toJSON() : notification;
|
||||
await natsServer.publish(`notifications.${user._id ?? user}`, value);
|
||||
return notification;
|
||||
}
|
||||
|
||||
function flatternObjectIds(object) {
|
||||
if (!object || typeof object !== 'object') {
|
||||
return object;
|
||||
@ -546,6 +668,9 @@ export {
|
||||
distributeUpdate,
|
||||
distributeNew,
|
||||
distributeStats,
|
||||
editNotification,
|
||||
notfiyObjectUserNotifiers,
|
||||
createNotification,
|
||||
getFilter, // <-- add here
|
||||
convertPropertiesString
|
||||
};
|
||||
|
||||
@ -172,7 +172,8 @@ export class SocketHost {
|
||||
populate: data.populate,
|
||||
owner: this.host,
|
||||
ownerType: 'host',
|
||||
auditLog: data?.auditLog
|
||||
auditLog: data?.auditLog,
|
||||
notify: data?.notify
|
||||
});
|
||||
callback(object);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user