Base solution for your next web application
Open Closed

Sending notifications to specific users #3607


User avatar
0
jseger created

I have an IApplicationService that does some work. I want to notify users that the work has completed. For example, content has been updated.

Now, I was going to inject my own NotificationProvider into my app service and send a message to users within the same organization.

My understanding is that if I publish a notification it will get sent to everyone who has subscribed. But if I explicitly publish a notification to a user, they will get it whether they subscribed or not. Is this correct?

What would be the best way to publish a notification to users that have subscribed that are also in the same organization.? Oh, and also have permissions to get that notification?


8 Answer(s)
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    If you mean Tenant by organization, then you can check this document for sending a notification to all subscribed users of a Tenant <a class="postlink" href="https://aspnetboilerplate.com/Pages/Documents/Notification-System#publish-notifications">https://aspnetboilerplate.com/Pages/Doc ... ifications</a>.

    You can also define permissionDependency for your notification, see <a class="postlink" href="https://aspnetboilerplate.com/Pages/Documents/Notification-System#notification-definitions">https://aspnetboilerplate.com/Pages/Doc ... efinitions</a>

    If you want to send notification to users in a OrganizationUnit, then it is not possible by default. You need to get all users in that Organization Unit, then send one by one.

    Thanks.

  • User Avatar
    0
    jseger created

    Yes to each user in an organization.

    My question is, if I simply loop over all the users in an organization and send the notification explicitly, will the notification service respect the Subscribe/Unsubscribe options. In other words, if I send a notification to a user who has not subscribed AND who does not have permissions for that notification, will he get the notification?

  • User Avatar
    0
    jseger created

    This is what I'm thinking.... I haven't tried it yet. I'm about to. I created another AppService called ContentNotificationAppService. I'll call this on the client after a successful content creation. Is this the right direction? Rather than injecting some notification service in my ContentAppService?? Below is the method from ContentNoficationAppService.

    public async Task ContentSubmitted(EntityDto<Guid> input) { var content = await _contents.GetAsync(input.Id); var org = await _organizations.GetAsync(content.OrganizationUnitId);

            var users = await _userManager.GetUsersInOrganizationUnit(org, false);
            var currentUser = await _userManager.GetUserByIdAsync(AbpSession.GetUserId());
    
            List&lt;UserIdentifier&gt; userIds = new List&lt;UserIdentifier&gt;();
    
            foreach(var user in users) {
                if(user.Id == currentUser.Id) {
                    // we don't need to send a notification to ourselves
                    continue;
                }
    
                // we need to see if this is a manager within our organization
                bool isManager = await _userManager.IsGrantedAsync(user.Id, AppPermissions.Pages_Content_ManageContent);
                bool isSubscribed = await _notificationSubcriptionManager.IsSubscribedAsync(user.ToUserIdentifier(), ContentAppNotificationNames.ContentSubmitted);
    
                if(isManager && isSubscribed) {
                    userIds.Add(user.ToUserIdentifier());
                }
            }
    
            if (userIds.Count > 0) {
                // send the notification to the users
                await _notificationPublisher.PublishAsync(
                    ContentAppNotificationNames.ContentSubmitted,
                    data: new MessageNotificationData($"{currentUser.FullName} has submitted some content."),
                    userIds: userIds.ToArray());
            }
        }
    
  • User Avatar
    0
    jseger created

    BTW, my managers might be in parent organizations. So I need to go up the tree first. Is this a good way to do it?

    var org = await _organizations.GetAsync(header.OrganizationUnitId); // go up the organization tree while(org.Parent != null) { org = org.Parent; } // now that we're on the top, get the users var users = await _userManager.GetUsersInOrganizationUnit(org, true);

    ***************************** [EDIT] *********************************** This is not the correct way to get managers of an organization. Obviously, it will get ALL the users within the tenant!!

    This works though. I will probably make this an extension method since I frequently need to find managers within parent organizations.

    List<User> users = new List<User>();
    
                // go up the organization tree
                do {
                    var ous = await _userManager.GetUsersInOrganizationUnit(org, false);
                    users.AddRange(ous);
                    org = org.Parent;
                }
                while (org != null);
    
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    Yes, it is a good way I think. When you send a notification to a user, user's subscription to that notification and user's permission is considered.

    If your app service is not called from UI but from other app services, then it is better to convert it to a domain service. But if it is called from UI, then it is good to have this as an app service.

    Thanks.

  • User Avatar
    0
    jseger created

    Ok great. I'm running into an angular injection error.

    I named my service IContentNotificationAppService. I tried to inject 'abp.services.app.contentNotification'. It complains that it cannot find 'abp.services.app.contentNotificationProvider'.

    Is this due to some convention?

  • User Avatar
    0
    jseger created

    Nevermind..... forgot to inherit IApplicationService.

  • User Avatar
    0
    ismcagdas created
    Support Team

    Ok :)