Support notifications for multiple root nodes (#13805)

This commit is contained in:
Kenn Jacobsen
2023-02-10 10:49:39 +01:00
committed by GitHub
parent 7d9e07ff7c
commit 45f8ffcd0b

View File

@@ -76,7 +76,8 @@ public class NotificationService : INotificationService
Func<(IUser user, NotificationEmailSubjectParams subject), string> createSubject, Func<(IUser user, NotificationEmailSubjectParams subject), string> createSubject,
Func<(IUser user, NotificationEmailBodyParams body, bool isHtml), string> createBody) Func<(IUser user, NotificationEmailBodyParams body, bool isHtml), string> createBody)
{ {
var entitiesL = entities.ToList(); // sort the entities explicitly by path to handle notification inheritance (see comment below)
var entitiesL = entities.OrderBy(entity => entity.Path).ToList();
// exit if there are no entities // exit if there are no entities
if (entitiesL.Count == 0) if (entitiesL.Count == 0)
@@ -84,11 +85,11 @@ public class NotificationService : INotificationService
return; return;
} }
// put all entity's paths into a list with the same indices // create a dictionary of entity paths by entity ID
var paths = entitiesL.Select(x => var pathsByEntityId = entitiesL.ToDictionary(
x.Path.Split(Constants.CharArrays.Comma).Select(s => int.Parse(s, CultureInfo.InvariantCulture)) entity => entity.Id,
.ToArray()) entity => entity.Path.Split(Constants.CharArrays.Comma)
.ToArray(); .Select(s => int.Parse(s, CultureInfo.InvariantCulture)).ToArray());
// lazily get versions // lazily get versions
var prevVersionDictionary = new Dictionary<int, IContentBase?>(); var prevVersionDictionary = new Dictionary<int, IContentBase?>();
@@ -106,47 +107,32 @@ public class NotificationService : INotificationService
break; break;
} }
var i = 0;
foreach (IUser user in users) foreach (IUser user in users)
{ {
// continue if there's no notification for this user Notification[] userNotifications = notifications.Where(n => n.UserId == user.Id).ToArray();
if (notifications[i].UserId != user.Id) foreach (Notification notification in userNotifications)
{ {
continue; // next user // notifications are inherited down the tree - find the topmost entity
} // relevant to this notification (entity list is sorted by path)
IContent? entityForNotification = entitiesL
.FirstOrDefault(entity =>
pathsByEntityId.TryGetValue(entity.Id, out var path) &&
path.Contains(notification.EntityId));
for (var j = 0; j < entitiesL.Count; j++) if (entityForNotification == null)
{
IContent content = entitiesL[j];
var path = paths[j];
// test if the notification applies to the path ie to this entity
if (path.Contains(notifications[i].EntityId) == false)
{ {
continue; // next entity continue;
} }
if (prevVersionDictionary.ContainsKey(content.Id) == false) if (prevVersionDictionary.ContainsKey(entityForNotification.Id) == false)
{ {
prevVersionDictionary[content.Id] = GetPreviousVersion(content.Id); prevVersionDictionary[entityForNotification.Id] = GetPreviousVersion(entityForNotification.Id);
} }
// queue notification // queue notification
NotificationRequest req = CreateNotificationRequest(operatingUser, user, content, prevVersionDictionary[content.Id], actionName, siteUri, createSubject, createBody); NotificationRequest req = CreateNotificationRequest(operatingUser, user, entityForNotification, prevVersionDictionary[entityForNotification.Id], actionName, siteUri, createSubject, createBody);
Enqueue(req); Enqueue(req);
} break;
// skip other notifications for this user, essentially this means moving i to the next index of notifications
// for the next user.
do
{
i++;
}
while (i < notifications.Count && notifications[i].UserId == user.Id);
if (i >= notifications.Count)
{
break; // break if no more notifications
} }
} }