Skip to content

Commit

Permalink
Merge pull request #6730 from aspnetboilerplate/feat/6618
Browse files Browse the repository at this point in the history
Allow users to subscribe specific notifiers
  • Loading branch information
ismcagdas committed Jun 14, 2023
2 parents 2deb930 + f58c1b9 commit a5aa294
Show file tree
Hide file tree
Showing 12 changed files with 461 additions and 147 deletions.
5 changes: 4 additions & 1 deletion doc/WebSite/Notification-System.md
Expand Up @@ -56,7 +56,10 @@ persistence.
### Subscribe to Notifications

The **INotificationSubscriptionManager** provides an API to **subscribe** to
notifications. Examples:
notifications. A User can subscribe to a specific notification, to a notification related to a specific entity.
A user can also select specific notifiers when subscribing to a notification. In this way, user will not be notified by other notifiers. Full type name of the notifier must be provided when selecting a target Notifier. It can be set using `new EmailRealTimeNotifier().GetType().FullName` and accepts comma separated multiple values.

Examples:

public class MyService : ITransientDependency
{
Expand Down
3 changes: 2 additions & 1 deletion global.json
@@ -1,5 +1,6 @@
{
"sdk": {
"version": "7.0.100"
"version": "7.0.100",
"rollForward": "latestFeature"
}
}
194 changes: 131 additions & 63 deletions src/Abp.Zero.Common/Notifications/NotificationStore.cs
Expand Up @@ -6,6 +6,7 @@
using Abp.Dependency;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using Abp.Extensions;
using Abp.Linq;
using Abp.Linq.Expressions;
using Abp.Linq.Extensions;
Expand All @@ -18,7 +19,7 @@ namespace Abp.Notifications
public class NotificationStore : INotificationStore, ITransientDependency
{
public IAsyncQueryableExecuter AsyncQueryableExecuter { get; set; }

private readonly IRepository<NotificationInfo, Guid> _notificationRepository;
private readonly IRepository<TenantNotificationInfo, Guid> _tenantNotificationRepository;
private readonly IRepository<UserNotificationInfo, Guid> _userNotificationRepository;
Expand All @@ -40,7 +41,7 @@ public class NotificationStore : INotificationStore, ITransientDependency
_userNotificationRepository = userNotificationRepository;
_notificationSubscriptionRepository = notificationSubscriptionRepository;
_unitOfWorkManager = unitOfWorkManager;

AsyncQueryableExecuter = NullAsyncQueryableExecuter.Instance;
}

Expand Down Expand Up @@ -185,35 +186,43 @@ public virtual void InsertUserNotification(UserNotificationInfo userNotification
public virtual async Task<List<NotificationSubscriptionInfo>> GetSubscriptionsAsync(
string notificationName,
string entityTypeName,
string entityId)
string entityId,
string targetNotifiers)
{
return await _unitOfWorkManager.WithUnitOfWorkAsync(async () =>
{
using (_unitOfWorkManager.Current.DisableFilter(AbpDataFilters.MayHaveTenant))
{
return await _notificationSubscriptionRepository.GetAllListAsync(s =>
s.NotificationName == notificationName &&
s.EntityTypeName == entityTypeName &&
s.EntityId == entityId
var predicate = GetNotificationSubscriptionPredicate(
notificationName,
entityTypeName,
entityId,
targetNotifiers
);
return await _notificationSubscriptionRepository.GetAllListAsync(predicate);
}
});
}

public virtual List<NotificationSubscriptionInfo> GetSubscriptions(
string notificationName,
string entityTypeName,
string entityId)
string entityId,
string targetNotifiers)
{
return _unitOfWorkManager.WithUnitOfWork(() =>
{
using (_unitOfWorkManager.Current.DisableFilter(AbpDataFilters.MayHaveTenant))
{
return _notificationSubscriptionRepository.GetAllList(s =>
s.NotificationName == notificationName &&
s.EntityTypeName == entityTypeName &&
s.EntityId == entityId
var predicate = GetNotificationSubscriptionPredicate(
notificationName,
entityTypeName,
entityId,
targetNotifiers
);
return _notificationSubscriptionRepository.GetAllList(predicate);
}
});
}
Expand All @@ -222,16 +231,24 @@ public virtual void InsertUserNotification(UserNotificationInfo userNotification
int?[] tenantIds,
string notificationName,
string entityTypeName,
string entityId)
string entityId,
string targetNotifiers)
{
return await _unitOfWorkManager.WithUnitOfWorkAsync(async () =>
{
var subscriptions = new List<NotificationSubscriptionInfo>();
foreach (var tenantId in tenantIds)
{
subscriptions.AddRange(await GetSubscriptionsAsync(tenantId, notificationName, entityTypeName,
entityId));
subscriptions.AddRange(
await GetSubscriptionsAsync(
tenantId,
notificationName,
entityTypeName,
entityId,
targetNotifiers
)
);
}
return subscriptions;
Expand All @@ -242,15 +259,24 @@ public virtual void InsertUserNotification(UserNotificationInfo userNotification
int?[] tenantIds,
string notificationName,
string entityTypeName,
string entityId)
string entityId,
string targetNotifiers)
{
return _unitOfWorkManager.WithUnitOfWork(() =>
{
var subscriptions = new List<NotificationSubscriptionInfo>();
foreach (var tenantId in tenantIds)
{
subscriptions.AddRange(GetSubscriptions(tenantId, notificationName, entityTypeName, entityId));
subscriptions.AddRange(
GetSubscriptions(
tenantId,
notificationName,
entityTypeName,
entityId,
targetNotifiers
)
);
}
return subscriptions;
Expand Down Expand Up @@ -283,36 +309,68 @@ public virtual List<NotificationSubscriptionInfo> GetSubscriptions(UserIdentifie
int? tenantId,
string notificationName,
string entityTypeName,
string entityId)
string entityId,
string targetNotifiers)
{
return await _unitOfWorkManager.WithUnitOfWorkAsync(async () =>
{
using (_unitOfWorkManager.Current.SetTenantId(tenantId))
{
return await _notificationSubscriptionRepository.GetAllListAsync(s =>
s.NotificationName == notificationName &&
s.EntityTypeName == entityTypeName &&
s.EntityId == entityId
var predicate = GetNotificationSubscriptionPredicate(
notificationName,
entityTypeName,
entityId,
targetNotifiers
);
return await _notificationSubscriptionRepository.GetAllListAsync(predicate);
}
});
}

protected virtual ExpressionStarter<NotificationSubscriptionInfo> GetNotificationSubscriptionPredicate(
string notificationName, string entityTypeName,
string entityId, string targetNotifiers)
{
var predicate = PredicateBuilder.New<NotificationSubscriptionInfo>();
predicate = predicate.And(e => e.NotificationName == notificationName);
predicate = predicate.And(e => e.EntityTypeName == entityTypeName);
predicate = predicate.And(e => e.EntityId == entityId);

if (!targetNotifiers.IsNullOrEmpty())
{
var targetNotifierPredicate = PredicateBuilder.New<NotificationSubscriptionInfo>();
var targetNotifierList = targetNotifiers.Split(NotificationInfo.NotificationTargetSeparator);
foreach (var targetNotifier in targetNotifierList)
{
targetNotifierPredicate = targetNotifierPredicate.Or(e => e.TargetNotifiers.Contains(targetNotifier));
}

predicate = predicate.And(targetNotifierPredicate);
}

return predicate;
}

protected virtual List<NotificationSubscriptionInfo> GetSubscriptions(
int? tenantId,
string notificationName,
string entityTypeName,
string entityId)
string entityId,
string targetNotifiers)
{
return _unitOfWorkManager.WithUnitOfWork(() =>
{
using (_unitOfWorkManager.Current.SetTenantId(tenantId))
{
return _notificationSubscriptionRepository.GetAllList(s =>
s.NotificationName == notificationName &&
s.EntityTypeName == entityTypeName &&
s.EntityId == entityId
var predicate = GetNotificationSubscriptionPredicate(
notificationName,
entityTypeName,
entityId,
targetNotifiers
);
return _notificationSubscriptionRepository.GetAllList(predicate);
}
});
}
Expand All @@ -321,18 +379,23 @@ public virtual List<NotificationSubscriptionInfo> GetSubscriptions(UserIdentifie
UserIdentifier user,
string notificationName,
string entityTypeName,
string entityId)
string entityId,
string targetNotifiers)
{
return await _unitOfWorkManager.WithUnitOfWorkAsync(async () =>
{
using (_unitOfWorkManager.Current.SetTenantId(user.TenantId))
{
return await _notificationSubscriptionRepository.CountAsync(s =>
s.UserId == user.UserId &&
s.NotificationName == notificationName &&
s.EntityTypeName == entityTypeName &&
s.EntityId == entityId
) > 0;
var predicate = GetNotificationSubscriptionPredicate(
notificationName,
entityTypeName,
entityId,
targetNotifiers
);
predicate = predicate.And(e => e.UserId == user.UserId);
return await _notificationSubscriptionRepository.CountAsync(predicate) > 0;
}
});
}
Expand All @@ -341,18 +404,23 @@ public virtual List<NotificationSubscriptionInfo> GetSubscriptions(UserIdentifie
UserIdentifier user,
string notificationName,
string entityTypeName,
string entityId)
string entityId,
string targetNotifiers)
{
return _unitOfWorkManager.WithUnitOfWork(() =>
{
using (_unitOfWorkManager.Current.SetTenantId(user.TenantId))
{
return _notificationSubscriptionRepository.Count(s =>
s.UserId == user.UserId &&
s.NotificationName == notificationName &&
s.EntityTypeName == entityTypeName &&
s.EntityId == entityId
) > 0;
var predicate = GetNotificationSubscriptionPredicate(
notificationName,
entityTypeName,
entityId,
targetNotifiers
);
predicate = predicate.And(e => e.UserId == user.UserId);
return _notificationSubscriptionRepository.Count(predicate) > 0;
}
});
}
Expand Down Expand Up @@ -756,18 +824,17 @@ public virtual void InsertTenantNotification(TenantNotificationInfo tenantNotifi

public virtual async Task DeleteNotificationAsync(NotificationInfo notification)
{
await _unitOfWorkManager.WithUnitOfWorkAsync(async () => await _notificationRepository.DeleteAsync(notification));
await _unitOfWorkManager.WithUnitOfWorkAsync(async () =>
await _notificationRepository.DeleteAsync(notification));
}

public virtual void DeleteNotification(NotificationInfo notification)
{
_unitOfWorkManager.WithUnitOfWork(() =>
{
_notificationRepository.Delete(notification);
});
_unitOfWorkManager.WithUnitOfWork(() => { _notificationRepository.Delete(notification); });
}

public async Task<List<GetNotificationsCreatedByUserOutput>> GetNotificationsPublishedByUserAsync(UserIdentifier user, string notificationName, DateTime? startDate, DateTime? endDate)
public async Task<List<GetNotificationsCreatedByUserOutput>> GetNotificationsPublishedByUserAsync(
UserIdentifier user, string notificationName, DateTime? startDate, DateTime? endDate)
{
return await _unitOfWorkManager.WithUnitOfWorkAsync(async () =>
{
Expand All @@ -789,25 +856,26 @@ public async Task<List<GetNotificationsCreatedByUserOutput>> GetNotificationsPub
}
var result = new List<GetNotificationsCreatedByUserOutput>();
var unPublishedNotifications = await AsyncQueryableExecuter.ToListAsync(queryForNotPublishedNotifications
.Select(x =>
new GetNotificationsCreatedByUserOutput()
{
Data = x.Data,
Severity = x.Severity,
NotificationName = x.NotificationName,
DataTypeName = x.DataTypeName,
IsPublished = false,
CreationTime = x.CreationTime
})
var unPublishedNotifications = await AsyncQueryableExecuter.ToListAsync(
queryForNotPublishedNotifications
.Select(x =>
new GetNotificationsCreatedByUserOutput()
{
Data = x.Data,
Severity = x.Severity,
NotificationName = x.NotificationName,
DataTypeName = x.DataTypeName,
IsPublished = false,
CreationTime = x.CreationTime
})
);
result.AddRange(unPublishedNotifications);
var queryForPublishedNotifications = _tenantNotificationRepository.GetAll()
.Where(n => n.CreatorUserId == user.UserId && n.NotificationName == notificationName);
if (startDate.HasValue)
{
queryForPublishedNotifications = queryForPublishedNotifications
Expand All @@ -822,7 +890,7 @@ public async Task<List<GetNotificationsCreatedByUserOutput>> GetNotificationsPub
queryForPublishedNotifications = queryForPublishedNotifications
.OrderByDescending(n => n.CreationTime);
var publishedNotifications = await AsyncQueryableExecuter.ToListAsync(queryForPublishedNotifications
.Select(x =>
new GetNotificationsCreatedByUserOutput()
Expand All @@ -842,4 +910,4 @@ public async Task<List<GetNotificationsCreatedByUserOutput>> GetNotificationsPub
});
}
}
}
}

0 comments on commit a5aa294

Please sign in to comment.