DefaultNotificationDistributer.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Threading.Tasks;
  5. using Abp.Configuration;
  6. using Abp.Domain.Services;
  7. using Abp.Domain.Uow;
  8. using Abp.Extensions;
  9. using Castle.Core.Internal;
  10. namespace Abp.Notifications
  11. {
  12. /// <summary>
  13. /// Used to distribute notifications to users.
  14. /// </summary>
  15. public class DefaultNotificationDistributer : DomainService, INotificationDistributer
  16. {
  17. public IRealTimeNotifier RealTimeNotifier { get; set; }
  18. private readonly INotificationDefinitionManager _notificationDefinitionManager;
  19. private readonly INotificationStore _notificationStore;
  20. private readonly IUnitOfWorkManager _unitOfWorkManager;
  21. private readonly IGuidGenerator _guidGenerator;
  22. /// <summary>
  23. /// Initializes a new instance of the <see cref="NotificationDistributionJob"/> class.
  24. /// </summary>
  25. public DefaultNotificationDistributer(
  26. INotificationDefinitionManager notificationDefinitionManager,
  27. INotificationStore notificationStore,
  28. IUnitOfWorkManager unitOfWorkManager,
  29. IGuidGenerator guidGenerator)
  30. {
  31. _notificationDefinitionManager = notificationDefinitionManager;
  32. _notificationStore = notificationStore;
  33. _unitOfWorkManager = unitOfWorkManager;
  34. _guidGenerator = guidGenerator;
  35. RealTimeNotifier = NullRealTimeNotifier.Instance;
  36. }
  37. public async Task DistributeAsync(Guid notificationId)
  38. {
  39. var notificationInfo = await _notificationStore.GetNotificationOrNullAsync(notificationId);
  40. if (notificationInfo == null)
  41. {
  42. Logger.Warn("NotificationDistributionJob can not continue since could not found notification by id: " + notificationId);
  43. return;
  44. }
  45. var users = await GetUsers(notificationInfo);
  46. var userNotifications = await SaveUserNotifications(users, notificationInfo);
  47. await _notificationStore.DeleteNotificationAsync(notificationInfo);
  48. try
  49. {
  50. await RealTimeNotifier.SendNotificationsAsync(userNotifications.ToArray());
  51. }
  52. catch (Exception ex)
  53. {
  54. Logger.Warn(ex.ToString(), ex);
  55. }
  56. }
  57. [UnitOfWork]
  58. protected virtual async Task<UserIdentifier[]> GetUsers(NotificationInfo notificationInfo)
  59. {
  60. List<UserIdentifier> userIds;
  61. if (!notificationInfo.UserIds.IsNullOrEmpty())
  62. {
  63. //Directly get from UserIds
  64. userIds = notificationInfo
  65. .UserIds
  66. .Split(",")
  67. .Select(uidAsStr => UserIdentifier.Parse(uidAsStr))
  68. .Where(uid => SettingManager.GetSettingValueForUser<bool>(NotificationSettingNames.ReceiveNotifications, uid.TenantId, uid.UserId))
  69. .ToList();
  70. }
  71. else
  72. {
  73. //Get subscribed users
  74. var tenantIds = GetTenantIds(notificationInfo);
  75. List<NotificationSubscriptionInfo> subscriptions;
  76. if (tenantIds.IsNullOrEmpty() ||
  77. (tenantIds.Length == 1 && tenantIds[0] == NotificationInfo.AllTenantIds.To<int>()))
  78. {
  79. //Get all subscribed users of all tenants
  80. subscriptions = await _notificationStore.GetSubscriptionsAsync(
  81. notificationInfo.NotificationName,
  82. notificationInfo.EntityTypeName,
  83. notificationInfo.EntityId
  84. );
  85. }
  86. else
  87. {
  88. //Get all subscribed users of specified tenant(s)
  89. subscriptions = await _notificationStore.GetSubscriptionsAsync(
  90. tenantIds,
  91. notificationInfo.NotificationName,
  92. notificationInfo.EntityTypeName,
  93. notificationInfo.EntityId
  94. );
  95. }
  96. //Remove invalid subscriptions
  97. var invalidSubscriptions = new Dictionary<Guid, NotificationSubscriptionInfo>();
  98. //TODO: Group subscriptions per tenant for potential performance improvement
  99. foreach (var subscription in subscriptions)
  100. {
  101. using (CurrentUnitOfWork.SetTenantId(subscription.TenantId))
  102. {
  103. if (!await _notificationDefinitionManager.IsAvailableAsync(notificationInfo.NotificationName, new UserIdentifier(subscription.TenantId, subscription.UserId)) ||
  104. !SettingManager.GetSettingValueForUser<bool>(NotificationSettingNames.ReceiveNotifications, subscription.TenantId, subscription.UserId))
  105. {
  106. invalidSubscriptions[subscription.Id] = subscription;
  107. }
  108. }
  109. }
  110. subscriptions.RemoveAll(s => invalidSubscriptions.ContainsKey(s.Id));
  111. //Get user ids
  112. userIds = subscriptions
  113. .Select(s => new UserIdentifier(s.TenantId, s.UserId))
  114. .ToList();
  115. }
  116. if (!notificationInfo.ExcludedUserIds.IsNullOrEmpty())
  117. {
  118. //Exclude specified users.
  119. var excludedUserIds = notificationInfo
  120. .ExcludedUserIds
  121. .Split(",")
  122. .Select(uidAsStr => UserIdentifier.Parse(uidAsStr))
  123. .ToList();
  124. userIds.RemoveAll(uid => excludedUserIds.Any(euid => euid.Equals(uid)));
  125. }
  126. return userIds.ToArray();
  127. }
  128. private static int?[] GetTenantIds(NotificationInfo notificationInfo)
  129. {
  130. if (notificationInfo.TenantIds.IsNullOrEmpty())
  131. {
  132. return null;
  133. }
  134. return notificationInfo
  135. .TenantIds
  136. .Split(",")
  137. .Select(tenantIdAsStr => tenantIdAsStr == "null" ? (int?)null : (int?)tenantIdAsStr.To<int>())
  138. .ToArray();
  139. }
  140. [UnitOfWork]
  141. protected virtual async Task<List<UserNotification>> SaveUserNotifications(UserIdentifier[] users, NotificationInfo notificationInfo)
  142. {
  143. var userNotifications = new List<UserNotification>();
  144. var tenantGroups = users.GroupBy(user => user.TenantId);
  145. foreach (var tenantGroup in tenantGroups)
  146. {
  147. using (_unitOfWorkManager.Current.SetTenantId(tenantGroup.Key))
  148. {
  149. var tenantNotificationInfo = new TenantNotificationInfo(_guidGenerator.Create(), tenantGroup.Key, notificationInfo);
  150. await _notificationStore.InsertTenantNotificationAsync(tenantNotificationInfo);
  151. await _unitOfWorkManager.Current.SaveChangesAsync(); //To get tenantNotification.Id.
  152. var tenantNotification = tenantNotificationInfo.ToTenantNotification();
  153. foreach (var user in tenantGroup)
  154. {
  155. var userNotification = new UserNotificationInfo(_guidGenerator.Create())
  156. {
  157. TenantId = tenantGroup.Key,
  158. UserId = user.UserId,
  159. TenantNotificationId = tenantNotificationInfo.Id
  160. };
  161. await _notificationStore.InsertUserNotificationAsync(userNotification);
  162. userNotifications.Add(userNotification.ToUserNotification(tenantNotification));
  163. }
  164. await CurrentUnitOfWork.SaveChangesAsync(); //To get Ids of the notifications
  165. }
  166. }
  167. return userNotifications;
  168. }
  169. }
  170. }