Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow users to subscribe specific notifiers #6730

Merged
merged 4 commits into from Jun 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
});
}
}
}
}