mirror of
https://github.com/bitwarden/server
synced 2025-12-14 15:23:42 +00:00
[PM-10564] Push notification updates to other clients (#5057)
* PM-10600: Notification push notification * PM-10600: Sending to specific client types for relay push notifications * PM-10600: Sending to specific client types for other clients * PM-10600: Send push notification on notification creation * PM-10600: Explicit group names * PM-10600: Id typos * PM-10600: Revert global push notifications * PM-10600: Added DeviceType claim * PM-10600: Sent to organization typo * PM-10600: UT coverage * PM-10600: Small refactor, UTs coverage * PM-10600: UTs coverage * PM-10600: Startup fix * PM-10600: Test fix * PM-10600: Required attribute, organization group for push notification fix * PM-10600: UT coverage * PM-10600: Fix Mobile devices not registering to organization push notifications We only register devices for organization push notifications when the organization is being created. This does not work, since we have a use case (Notification Center) of delivering notifications to all users of organization. This fixes it, by adding the organization id tag when device registers for push notifications. * PM-10600: Unit Test coverage for NotificationHubPushRegistrationService Fixed IFeatureService substitute mocking for Android tests. Added user part of organization test with organizationId tags expectation. * PM-10600: Unit Tests fix to NotificationHubPushRegistrationService after merge conflict * PM-10600: Organization push notifications not sending to mobile device from self-hosted. Self-hosted instance uses relay to register the mobile device against Bitwarden Cloud Api. Only the self-hosted server knows client's organization membership, which means it needs to pass in the organization id's information to the relay. Similarly, for Bitwarden Cloud, the organizaton id will come directly from the server. * PM-10600: Fix self-hosted organization notification not being received by mobile device. When mobile device registers on self-hosted through the relay, every single id, like user id, device id and now organization id needs to be prefixed with the installation id. This have been missing in the PushController that handles this for organization id. * PM-10600: Broken NotificationsController integration test Device type is now part of JWT access token, so the notification center results in the integration test are now scoped to client type web and all. * PM-10600: Merge conflicts fix * merge conflict fix * PM-10600: Push notification with full notification center content. Notification Center push notification now includes all the fields. * PM-10564: Push notification updates to other clients Cherry-picked and squashed commits:d9711b60316e69c8a0ce01c814595e3885885d5f1285a7e994fcf346985f28ff53c29357804ae27c1c9339b686* null check fix * logging using template formatting
This commit is contained in:
@@ -29,4 +29,5 @@ public enum PushType : byte
|
|||||||
SyncOrganizationCollectionSettingChanged = 19,
|
SyncOrganizationCollectionSettingChanged = 19,
|
||||||
|
|
||||||
SyncNotification = 20,
|
SyncNotification = 20,
|
||||||
|
SyncNotificationStatus = 21
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
using Bit.Core.Enums;
|
#nullable enable
|
||||||
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.NotificationCenter.Enums;
|
using Bit.Core.NotificationCenter.Enums;
|
||||||
|
|
||||||
namespace Bit.Core.Models;
|
namespace Bit.Core.Models;
|
||||||
|
|
||||||
public class PushNotificationData<T>
|
public class PushNotificationData<T>
|
||||||
{
|
{
|
||||||
public PushNotificationData(PushType type, T payload, string contextId)
|
public PushNotificationData(PushType type, T payload, string? contextId)
|
||||||
{
|
{
|
||||||
Type = type;
|
Type = type;
|
||||||
Payload = payload;
|
Payload = payload;
|
||||||
@@ -14,7 +15,7 @@ public class PushNotificationData<T>
|
|||||||
|
|
||||||
public PushType Type { get; set; }
|
public PushType Type { get; set; }
|
||||||
public T Payload { get; set; }
|
public T Payload { get; set; }
|
||||||
public string ContextId { get; set; }
|
public string? ContextId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SyncCipherPushNotification
|
public class SyncCipherPushNotification
|
||||||
@@ -22,7 +23,7 @@ public class SyncCipherPushNotification
|
|||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public Guid? UserId { get; set; }
|
public Guid? UserId { get; set; }
|
||||||
public Guid? OrganizationId { get; set; }
|
public Guid? OrganizationId { get; set; }
|
||||||
public IEnumerable<Guid> CollectionIds { get; set; }
|
public IEnumerable<Guid>? CollectionIds { get; set; }
|
||||||
public DateTime RevisionDate { get; set; }
|
public DateTime RevisionDate { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +47,6 @@ public class SyncSendPushNotification
|
|||||||
public DateTime RevisionDate { get; set; }
|
public DateTime RevisionDate { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
#nullable enable
|
|
||||||
public class NotificationPushNotification
|
public class NotificationPushNotification
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
@@ -59,8 +59,9 @@ public class NotificationPushNotification
|
|||||||
public string? Body { get; set; }
|
public string? Body { get; set; }
|
||||||
public DateTime CreationDate { get; set; }
|
public DateTime CreationDate { get; set; }
|
||||||
public DateTime RevisionDate { get; set; }
|
public DateTime RevisionDate { get; set; }
|
||||||
|
public DateTime? ReadDate { get; set; }
|
||||||
|
public DateTime? DeletedDate { get; set; }
|
||||||
}
|
}
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
public class AuthRequestPushNotification
|
public class AuthRequestPushNotification
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Bit.Core.NotificationCenter.Authorization;
|
|||||||
using Bit.Core.NotificationCenter.Commands.Interfaces;
|
using Bit.Core.NotificationCenter.Commands.Interfaces;
|
||||||
using Bit.Core.NotificationCenter.Entities;
|
using Bit.Core.NotificationCenter.Entities;
|
||||||
using Bit.Core.NotificationCenter.Repositories;
|
using Bit.Core.NotificationCenter.Repositories;
|
||||||
|
using Bit.Core.Platform.Push;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
|
||||||
@@ -16,16 +17,19 @@ public class CreateNotificationStatusCommand : ICreateNotificationStatusCommand
|
|||||||
private readonly IAuthorizationService _authorizationService;
|
private readonly IAuthorizationService _authorizationService;
|
||||||
private readonly INotificationRepository _notificationRepository;
|
private readonly INotificationRepository _notificationRepository;
|
||||||
private readonly INotificationStatusRepository _notificationStatusRepository;
|
private readonly INotificationStatusRepository _notificationStatusRepository;
|
||||||
|
private readonly IPushNotificationService _pushNotificationService;
|
||||||
|
|
||||||
public CreateNotificationStatusCommand(ICurrentContext currentContext,
|
public CreateNotificationStatusCommand(ICurrentContext currentContext,
|
||||||
IAuthorizationService authorizationService,
|
IAuthorizationService authorizationService,
|
||||||
INotificationRepository notificationRepository,
|
INotificationRepository notificationRepository,
|
||||||
INotificationStatusRepository notificationStatusRepository)
|
INotificationStatusRepository notificationStatusRepository,
|
||||||
|
IPushNotificationService pushNotificationService)
|
||||||
{
|
{
|
||||||
_currentContext = currentContext;
|
_currentContext = currentContext;
|
||||||
_authorizationService = authorizationService;
|
_authorizationService = authorizationService;
|
||||||
_notificationRepository = notificationRepository;
|
_notificationRepository = notificationRepository;
|
||||||
_notificationStatusRepository = notificationStatusRepository;
|
_notificationStatusRepository = notificationStatusRepository;
|
||||||
|
_pushNotificationService = pushNotificationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<NotificationStatus> CreateAsync(NotificationStatus notificationStatus)
|
public async Task<NotificationStatus> CreateAsync(NotificationStatus notificationStatus)
|
||||||
@@ -42,6 +46,10 @@ public class CreateNotificationStatusCommand : ICreateNotificationStatusCommand
|
|||||||
await _authorizationService.AuthorizeOrThrowAsync(_currentContext.HttpContext.User, notificationStatus,
|
await _authorizationService.AuthorizeOrThrowAsync(_currentContext.HttpContext.User, notificationStatus,
|
||||||
NotificationStatusOperations.Create);
|
NotificationStatusOperations.Create);
|
||||||
|
|
||||||
return await _notificationStatusRepository.CreateAsync(notificationStatus);
|
var newNotificationStatus = await _notificationStatusRepository.CreateAsync(notificationStatus);
|
||||||
|
|
||||||
|
await _pushNotificationService.PushNotificationStatusAsync(notification, newNotificationStatus);
|
||||||
|
|
||||||
|
return newNotificationStatus;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Bit.Core.NotificationCenter.Authorization;
|
|||||||
using Bit.Core.NotificationCenter.Commands.Interfaces;
|
using Bit.Core.NotificationCenter.Commands.Interfaces;
|
||||||
using Bit.Core.NotificationCenter.Entities;
|
using Bit.Core.NotificationCenter.Entities;
|
||||||
using Bit.Core.NotificationCenter.Repositories;
|
using Bit.Core.NotificationCenter.Repositories;
|
||||||
|
using Bit.Core.Platform.Push;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
|
||||||
@@ -16,16 +17,19 @@ public class MarkNotificationDeletedCommand : IMarkNotificationDeletedCommand
|
|||||||
private readonly IAuthorizationService _authorizationService;
|
private readonly IAuthorizationService _authorizationService;
|
||||||
private readonly INotificationRepository _notificationRepository;
|
private readonly INotificationRepository _notificationRepository;
|
||||||
private readonly INotificationStatusRepository _notificationStatusRepository;
|
private readonly INotificationStatusRepository _notificationStatusRepository;
|
||||||
|
private readonly IPushNotificationService _pushNotificationService;
|
||||||
|
|
||||||
public MarkNotificationDeletedCommand(ICurrentContext currentContext,
|
public MarkNotificationDeletedCommand(ICurrentContext currentContext,
|
||||||
IAuthorizationService authorizationService,
|
IAuthorizationService authorizationService,
|
||||||
INotificationRepository notificationRepository,
|
INotificationRepository notificationRepository,
|
||||||
INotificationStatusRepository notificationStatusRepository)
|
INotificationStatusRepository notificationStatusRepository,
|
||||||
|
IPushNotificationService pushNotificationService)
|
||||||
{
|
{
|
||||||
_currentContext = currentContext;
|
_currentContext = currentContext;
|
||||||
_authorizationService = authorizationService;
|
_authorizationService = authorizationService;
|
||||||
_notificationRepository = notificationRepository;
|
_notificationRepository = notificationRepository;
|
||||||
_notificationStatusRepository = notificationStatusRepository;
|
_notificationStatusRepository = notificationStatusRepository;
|
||||||
|
_pushNotificationService = pushNotificationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task MarkDeletedAsync(Guid notificationId)
|
public async Task MarkDeletedAsync(Guid notificationId)
|
||||||
@@ -59,7 +63,9 @@ public class MarkNotificationDeletedCommand : IMarkNotificationDeletedCommand
|
|||||||
await _authorizationService.AuthorizeOrThrowAsync(_currentContext.HttpContext.User, notificationStatus,
|
await _authorizationService.AuthorizeOrThrowAsync(_currentContext.HttpContext.User, notificationStatus,
|
||||||
NotificationStatusOperations.Create);
|
NotificationStatusOperations.Create);
|
||||||
|
|
||||||
await _notificationStatusRepository.CreateAsync(notificationStatus);
|
var newNotificationStatus = await _notificationStatusRepository.CreateAsync(notificationStatus);
|
||||||
|
|
||||||
|
await _pushNotificationService.PushNotificationStatusAsync(notification, newNotificationStatus);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -69,6 +75,8 @@ public class MarkNotificationDeletedCommand : IMarkNotificationDeletedCommand
|
|||||||
notificationStatus.DeletedDate = DateTime.UtcNow;
|
notificationStatus.DeletedDate = DateTime.UtcNow;
|
||||||
|
|
||||||
await _notificationStatusRepository.UpdateAsync(notificationStatus);
|
await _notificationStatusRepository.UpdateAsync(notificationStatus);
|
||||||
|
|
||||||
|
await _pushNotificationService.PushNotificationStatusAsync(notification, notificationStatus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Bit.Core.NotificationCenter.Authorization;
|
|||||||
using Bit.Core.NotificationCenter.Commands.Interfaces;
|
using Bit.Core.NotificationCenter.Commands.Interfaces;
|
||||||
using Bit.Core.NotificationCenter.Entities;
|
using Bit.Core.NotificationCenter.Entities;
|
||||||
using Bit.Core.NotificationCenter.Repositories;
|
using Bit.Core.NotificationCenter.Repositories;
|
||||||
|
using Bit.Core.Platform.Push;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
|
||||||
@@ -16,16 +17,19 @@ public class MarkNotificationReadCommand : IMarkNotificationReadCommand
|
|||||||
private readonly IAuthorizationService _authorizationService;
|
private readonly IAuthorizationService _authorizationService;
|
||||||
private readonly INotificationRepository _notificationRepository;
|
private readonly INotificationRepository _notificationRepository;
|
||||||
private readonly INotificationStatusRepository _notificationStatusRepository;
|
private readonly INotificationStatusRepository _notificationStatusRepository;
|
||||||
|
private readonly IPushNotificationService _pushNotificationService;
|
||||||
|
|
||||||
public MarkNotificationReadCommand(ICurrentContext currentContext,
|
public MarkNotificationReadCommand(ICurrentContext currentContext,
|
||||||
IAuthorizationService authorizationService,
|
IAuthorizationService authorizationService,
|
||||||
INotificationRepository notificationRepository,
|
INotificationRepository notificationRepository,
|
||||||
INotificationStatusRepository notificationStatusRepository)
|
INotificationStatusRepository notificationStatusRepository,
|
||||||
|
IPushNotificationService pushNotificationService)
|
||||||
{
|
{
|
||||||
_currentContext = currentContext;
|
_currentContext = currentContext;
|
||||||
_authorizationService = authorizationService;
|
_authorizationService = authorizationService;
|
||||||
_notificationRepository = notificationRepository;
|
_notificationRepository = notificationRepository;
|
||||||
_notificationStatusRepository = notificationStatusRepository;
|
_notificationStatusRepository = notificationStatusRepository;
|
||||||
|
_pushNotificationService = pushNotificationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task MarkReadAsync(Guid notificationId)
|
public async Task MarkReadAsync(Guid notificationId)
|
||||||
@@ -59,7 +63,9 @@ public class MarkNotificationReadCommand : IMarkNotificationReadCommand
|
|||||||
await _authorizationService.AuthorizeOrThrowAsync(_currentContext.HttpContext.User, notificationStatus,
|
await _authorizationService.AuthorizeOrThrowAsync(_currentContext.HttpContext.User, notificationStatus,
|
||||||
NotificationStatusOperations.Create);
|
NotificationStatusOperations.Create);
|
||||||
|
|
||||||
await _notificationStatusRepository.CreateAsync(notificationStatus);
|
var newNotificationStatus = await _notificationStatusRepository.CreateAsync(notificationStatus);
|
||||||
|
|
||||||
|
await _pushNotificationService.PushNotificationStatusAsync(notification, newNotificationStatus);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -69,6 +75,8 @@ public class MarkNotificationReadCommand : IMarkNotificationReadCommand
|
|||||||
notificationStatus.ReadDate = DateTime.UtcNow;
|
notificationStatus.ReadDate = DateTime.UtcNow;
|
||||||
|
|
||||||
await _notificationStatusRepository.UpdateAsync(notificationStatus);
|
await _notificationStatusRepository.UpdateAsync(notificationStatus);
|
||||||
|
|
||||||
|
await _pushNotificationService.PushNotificationStatusAsync(notification, notificationStatus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Bit.Core.NotificationCenter.Authorization;
|
|||||||
using Bit.Core.NotificationCenter.Commands.Interfaces;
|
using Bit.Core.NotificationCenter.Commands.Interfaces;
|
||||||
using Bit.Core.NotificationCenter.Entities;
|
using Bit.Core.NotificationCenter.Entities;
|
||||||
using Bit.Core.NotificationCenter.Repositories;
|
using Bit.Core.NotificationCenter.Repositories;
|
||||||
|
using Bit.Core.Platform.Push;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
|
||||||
@@ -15,14 +16,17 @@ public class UpdateNotificationCommand : IUpdateNotificationCommand
|
|||||||
private readonly ICurrentContext _currentContext;
|
private readonly ICurrentContext _currentContext;
|
||||||
private readonly IAuthorizationService _authorizationService;
|
private readonly IAuthorizationService _authorizationService;
|
||||||
private readonly INotificationRepository _notificationRepository;
|
private readonly INotificationRepository _notificationRepository;
|
||||||
|
private readonly IPushNotificationService _pushNotificationService;
|
||||||
|
|
||||||
public UpdateNotificationCommand(ICurrentContext currentContext,
|
public UpdateNotificationCommand(ICurrentContext currentContext,
|
||||||
IAuthorizationService authorizationService,
|
IAuthorizationService authorizationService,
|
||||||
INotificationRepository notificationRepository)
|
INotificationRepository notificationRepository,
|
||||||
|
IPushNotificationService pushNotificationService)
|
||||||
{
|
{
|
||||||
_currentContext = currentContext;
|
_currentContext = currentContext;
|
||||||
_authorizationService = authorizationService;
|
_authorizationService = authorizationService;
|
||||||
_notificationRepository = notificationRepository;
|
_notificationRepository = notificationRepository;
|
||||||
|
_pushNotificationService = pushNotificationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UpdateAsync(Notification notificationToUpdate)
|
public async Task UpdateAsync(Notification notificationToUpdate)
|
||||||
@@ -43,5 +47,7 @@ public class UpdateNotificationCommand : IUpdateNotificationCommand
|
|||||||
notification.RevisionDate = DateTime.UtcNow;
|
notification.RevisionDate = DateTime.UtcNow;
|
||||||
|
|
||||||
await _notificationRepository.ReplaceAsync(notification);
|
await _notificationRepository.ReplaceAsync(notification);
|
||||||
|
|
||||||
|
await _pushNotificationService.PushNotificationAsync(notification);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Text.Json;
|
#nullable enable
|
||||||
|
using System.Text.Json;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Bit.Core.AdminConsole.Entities;
|
using Bit.Core.AdminConsole.Entities;
|
||||||
using Bit.Core.Auth.Entities;
|
using Bit.Core.Auth.Entities;
|
||||||
@@ -6,6 +7,7 @@ using Bit.Core.Context;
|
|||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models;
|
using Bit.Core.Models;
|
||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
|
using Bit.Core.NotificationCenter.Entities;
|
||||||
using Bit.Core.Platform.Push;
|
using Bit.Core.Platform.Push;
|
||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
using Bit.Core.Tools.Entities;
|
using Bit.Core.Tools.Entities;
|
||||||
@@ -51,7 +53,7 @@ public class NotificationHubPushNotificationService : IPushNotificationService
|
|||||||
await PushCipherAsync(cipher, PushType.SyncLoginDelete, null);
|
await PushCipherAsync(cipher, PushType.SyncLoginDelete, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task PushCipherAsync(Cipher cipher, PushType type, IEnumerable<Guid> collectionIds)
|
private async Task PushCipherAsync(Cipher cipher, PushType type, IEnumerable<Guid>? collectionIds)
|
||||||
{
|
{
|
||||||
if (cipher.OrganizationId.HasValue)
|
if (cipher.OrganizationId.HasValue)
|
||||||
{
|
{
|
||||||
@@ -209,6 +211,36 @@ public class NotificationHubPushNotificationService : IPushNotificationService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task PushNotificationStatusAsync(Notification notification, NotificationStatus notificationStatus)
|
||||||
|
{
|
||||||
|
var message = new NotificationPushNotification
|
||||||
|
{
|
||||||
|
Id = notification.Id,
|
||||||
|
Priority = notification.Priority,
|
||||||
|
Global = notification.Global,
|
||||||
|
ClientType = notification.ClientType,
|
||||||
|
UserId = notification.UserId,
|
||||||
|
OrganizationId = notification.OrganizationId,
|
||||||
|
Title = notification.Title,
|
||||||
|
Body = notification.Body,
|
||||||
|
CreationDate = notification.CreationDate,
|
||||||
|
RevisionDate = notification.RevisionDate,
|
||||||
|
ReadDate = notificationStatus.ReadDate,
|
||||||
|
DeletedDate = notificationStatus.DeletedDate
|
||||||
|
};
|
||||||
|
|
||||||
|
if (notification.UserId.HasValue)
|
||||||
|
{
|
||||||
|
await SendPayloadToUserAsync(notification.UserId.Value, PushType.SyncNotificationStatus, message, true,
|
||||||
|
notification.ClientType);
|
||||||
|
}
|
||||||
|
else if (notification.OrganizationId.HasValue)
|
||||||
|
{
|
||||||
|
await SendPayloadToOrganizationAsync(notification.OrganizationId.Value, PushType.SyncNotificationStatus, message,
|
||||||
|
true, notification.ClientType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task PushAuthRequestAsync(AuthRequest authRequest, PushType type)
|
private async Task PushAuthRequestAsync(AuthRequest authRequest, PushType type)
|
||||||
{
|
{
|
||||||
var message = new AuthRequestPushNotification { Id = authRequest.Id, UserId = authRequest.UserId };
|
var message = new AuthRequestPushNotification { Id = authRequest.Id, UserId = authRequest.UserId };
|
||||||
@@ -230,8 +262,8 @@ public class NotificationHubPushNotificationService : IPushNotificationService
|
|||||||
GetContextIdentifier(excludeCurrentContext), clientType: clientType);
|
GetContextIdentifier(excludeCurrentContext), clientType: clientType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SendPayloadToUserAsync(string userId, PushType type, object payload, string identifier,
|
public async Task SendPayloadToUserAsync(string userId, PushType type, object payload, string? identifier,
|
||||||
string deviceId = null, ClientType? clientType = null)
|
string? deviceId = null, ClientType? clientType = null)
|
||||||
{
|
{
|
||||||
var tag = BuildTag($"template:payload_userId:{SanitizeTagInput(userId)}", identifier, clientType);
|
var tag = BuildTag($"template:payload_userId:{SanitizeTagInput(userId)}", identifier, clientType);
|
||||||
await SendPayloadAsync(tag, type, payload);
|
await SendPayloadAsync(tag, type, payload);
|
||||||
@@ -241,8 +273,8 @@ public class NotificationHubPushNotificationService : IPushNotificationService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SendPayloadToOrganizationAsync(string orgId, PushType type, object payload, string identifier,
|
public async Task SendPayloadToOrganizationAsync(string orgId, PushType type, object payload, string? identifier,
|
||||||
string deviceId = null, ClientType? clientType = null)
|
string? deviceId = null, ClientType? clientType = null)
|
||||||
{
|
{
|
||||||
var tag = BuildTag($"template:payload && organizationId:{SanitizeTagInput(orgId)}", identifier, clientType);
|
var tag = BuildTag($"template:payload && organizationId:{SanitizeTagInput(orgId)}", identifier, clientType);
|
||||||
await SendPayloadAsync(tag, type, payload);
|
await SendPayloadAsync(tag, type, payload);
|
||||||
@@ -277,7 +309,7 @@ public class NotificationHubPushNotificationService : IPushNotificationService
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
private string GetContextIdentifier(bool excludeCurrentContext)
|
private string? GetContextIdentifier(bool excludeCurrentContext)
|
||||||
{
|
{
|
||||||
if (!excludeCurrentContext)
|
if (!excludeCurrentContext)
|
||||||
{
|
{
|
||||||
@@ -285,11 +317,11 @@ public class NotificationHubPushNotificationService : IPushNotificationService
|
|||||||
}
|
}
|
||||||
|
|
||||||
var currentContext =
|
var currentContext =
|
||||||
_httpContextAccessor?.HttpContext?.RequestServices.GetService(typeof(ICurrentContext)) as ICurrentContext;
|
_httpContextAccessor.HttpContext?.RequestServices.GetService(typeof(ICurrentContext)) as ICurrentContext;
|
||||||
return currentContext?.DeviceIdentifier;
|
return currentContext?.DeviceIdentifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string BuildTag(string tag, string identifier, ClientType? clientType)
|
private string BuildTag(string tag, string? identifier, ClientType? clientType)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrWhiteSpace(identifier))
|
if (!string.IsNullOrWhiteSpace(identifier))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Text.Json;
|
#nullable enable
|
||||||
|
using System.Text.Json;
|
||||||
using Azure.Storage.Queues;
|
using Azure.Storage.Queues;
|
||||||
using Bit.Core.AdminConsole.Entities;
|
using Bit.Core.AdminConsole.Entities;
|
||||||
using Bit.Core.Auth.Entities;
|
using Bit.Core.Auth.Entities;
|
||||||
@@ -42,7 +43,7 @@ public class AzureQueuePushNotificationService : IPushNotificationService
|
|||||||
await PushCipherAsync(cipher, PushType.SyncLoginDelete, null);
|
await PushCipherAsync(cipher, PushType.SyncLoginDelete, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task PushCipherAsync(Cipher cipher, PushType type, IEnumerable<Guid> collectionIds)
|
private async Task PushCipherAsync(Cipher cipher, PushType type, IEnumerable<Guid>? collectionIds)
|
||||||
{
|
{
|
||||||
if (cipher.OrganizationId.HasValue)
|
if (cipher.OrganizationId.HasValue)
|
||||||
{
|
{
|
||||||
@@ -184,6 +185,27 @@ public class AzureQueuePushNotificationService : IPushNotificationService
|
|||||||
await SendMessageAsync(PushType.SyncNotification, message, true);
|
await SendMessageAsync(PushType.SyncNotification, message, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task PushNotificationStatusAsync(Notification notification, NotificationStatus notificationStatus)
|
||||||
|
{
|
||||||
|
var message = new NotificationPushNotification
|
||||||
|
{
|
||||||
|
Id = notification.Id,
|
||||||
|
Priority = notification.Priority,
|
||||||
|
Global = notification.Global,
|
||||||
|
ClientType = notification.ClientType,
|
||||||
|
UserId = notification.UserId,
|
||||||
|
OrganizationId = notification.OrganizationId,
|
||||||
|
Title = notification.Title,
|
||||||
|
Body = notification.Body,
|
||||||
|
CreationDate = notification.CreationDate,
|
||||||
|
RevisionDate = notification.RevisionDate,
|
||||||
|
ReadDate = notificationStatus.ReadDate,
|
||||||
|
DeletedDate = notificationStatus.DeletedDate
|
||||||
|
};
|
||||||
|
|
||||||
|
await SendMessageAsync(PushType.SyncNotificationStatus, message, true);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task PushSendAsync(Send send, PushType type)
|
private async Task PushSendAsync(Send send, PushType type)
|
||||||
{
|
{
|
||||||
if (send.UserId.HasValue)
|
if (send.UserId.HasValue)
|
||||||
@@ -207,7 +229,7 @@ public class AzureQueuePushNotificationService : IPushNotificationService
|
|||||||
await _queueClient.SendMessageAsync(message);
|
await _queueClient.SendMessageAsync(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetContextIdentifier(bool excludeCurrentContext)
|
private string? GetContextIdentifier(bool excludeCurrentContext)
|
||||||
{
|
{
|
||||||
if (!excludeCurrentContext)
|
if (!excludeCurrentContext)
|
||||||
{
|
{
|
||||||
@@ -219,15 +241,15 @@ public class AzureQueuePushNotificationService : IPushNotificationService
|
|||||||
return currentContext?.DeviceIdentifier;
|
return currentContext?.DeviceIdentifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SendPayloadToUserAsync(string userId, PushType type, object payload, string identifier,
|
public Task SendPayloadToUserAsync(string userId, PushType type, object payload, string? identifier,
|
||||||
string deviceId = null, ClientType? clientType = null)
|
string? deviceId = null, ClientType? clientType = null)
|
||||||
{
|
{
|
||||||
// Noop
|
// Noop
|
||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SendPayloadToOrganizationAsync(string orgId, PushType type, object payload, string identifier,
|
public Task SendPayloadToOrganizationAsync(string orgId, PushType type, object payload, string? identifier,
|
||||||
string deviceId = null, ClientType? clientType = null)
|
string? deviceId = null, ClientType? clientType = null)
|
||||||
{
|
{
|
||||||
// Noop
|
// Noop
|
||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Bit.Core.AdminConsole.Entities;
|
#nullable enable
|
||||||
|
using Bit.Core.AdminConsole.Entities;
|
||||||
using Bit.Core.Auth.Entities;
|
using Bit.Core.Auth.Entities;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.NotificationCenter.Entities;
|
using Bit.Core.NotificationCenter.Entities;
|
||||||
@@ -25,12 +26,13 @@ public interface IPushNotificationService
|
|||||||
Task PushSyncSendUpdateAsync(Send send);
|
Task PushSyncSendUpdateAsync(Send send);
|
||||||
Task PushSyncSendDeleteAsync(Send send);
|
Task PushSyncSendDeleteAsync(Send send);
|
||||||
Task PushNotificationAsync(Notification notification);
|
Task PushNotificationAsync(Notification notification);
|
||||||
|
Task PushNotificationStatusAsync(Notification notification, NotificationStatus notificationStatus);
|
||||||
Task PushAuthRequestAsync(AuthRequest authRequest);
|
Task PushAuthRequestAsync(AuthRequest authRequest);
|
||||||
Task PushAuthRequestResponseAsync(AuthRequest authRequest);
|
Task PushAuthRequestResponseAsync(AuthRequest authRequest);
|
||||||
Task PushSyncOrganizationStatusAsync(Organization organization);
|
Task PushSyncOrganizationStatusAsync(Organization organization);
|
||||||
Task PushSyncOrganizationCollectionManagementSettingsAsync(Organization organization);
|
Task PushSyncOrganizationCollectionManagementSettingsAsync(Organization organization);
|
||||||
Task SendPayloadToUserAsync(string userId, PushType type, object payload, string identifier,
|
Task SendPayloadToUserAsync(string userId, PushType type, object payload, string? identifier,
|
||||||
string deviceId = null, ClientType? clientType = null);
|
string? deviceId = null, ClientType? clientType = null);
|
||||||
Task SendPayloadToOrganizationAsync(string orgId, PushType type, object payload, string identifier,
|
Task SendPayloadToOrganizationAsync(string orgId, PushType type, object payload, string? identifier,
|
||||||
string deviceId = null, ClientType? clientType = null);
|
string? deviceId = null, ClientType? clientType = null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Bit.Core.AdminConsole.Entities;
|
#nullable enable
|
||||||
|
using Bit.Core.AdminConsole.Entities;
|
||||||
using Bit.Core.Auth.Entities;
|
using Bit.Core.Auth.Entities;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.NotificationCenter.Entities;
|
using Bit.Core.NotificationCenter.Entities;
|
||||||
@@ -24,7 +25,7 @@ public class MultiServicePushNotificationService : IPushNotificationService
|
|||||||
|
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_logger.LogInformation("Hub services: {Services}", _services.Count());
|
_logger.LogInformation("Hub services: {Services}", _services.Count());
|
||||||
globalSettings?.NotificationHubPool?.NotificationHubs?.ForEach(hub =>
|
globalSettings.NotificationHubPool?.NotificationHubs?.ForEach(hub =>
|
||||||
{
|
{
|
||||||
_logger.LogInformation("HubName: {HubName}, EnableSendTracing: {EnableSendTracing}, RegistrationStartDate: {RegistrationStartDate}, RegistrationEndDate: {RegistrationEndDate}", hub.HubName, hub.EnableSendTracing, hub.RegistrationStartDate, hub.RegistrationEndDate);
|
_logger.LogInformation("HubName: {HubName}, EnableSendTracing: {EnableSendTracing}, RegistrationStartDate: {RegistrationStartDate}, RegistrationEndDate: {RegistrationEndDate}", hub.HubName, hub.EnableSendTracing, hub.RegistrationStartDate, hub.RegistrationEndDate);
|
||||||
});
|
});
|
||||||
@@ -150,15 +151,21 @@ public class MultiServicePushNotificationService : IPushNotificationService
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SendPayloadToUserAsync(string userId, PushType type, object payload, string identifier,
|
public Task PushNotificationStatusAsync(Notification notification, NotificationStatus notificationStatus)
|
||||||
string deviceId = null, ClientType? clientType = null)
|
{
|
||||||
|
PushToServices((s) => s.PushNotificationStatusAsync(notification, notificationStatus));
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task SendPayloadToUserAsync(string userId, PushType type, object payload, string? identifier,
|
||||||
|
string? deviceId = null, ClientType? clientType = null)
|
||||||
{
|
{
|
||||||
PushToServices((s) => s.SendPayloadToUserAsync(userId, type, payload, identifier, deviceId, clientType));
|
PushToServices((s) => s.SendPayloadToUserAsync(userId, type, payload, identifier, deviceId, clientType));
|
||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SendPayloadToOrganizationAsync(string orgId, PushType type, object payload, string identifier,
|
public Task SendPayloadToOrganizationAsync(string orgId, PushType type, object payload, string? identifier,
|
||||||
string deviceId = null, ClientType? clientType = null)
|
string? deviceId = null, ClientType? clientType = null)
|
||||||
{
|
{
|
||||||
PushToServices((s) => s.SendPayloadToOrganizationAsync(orgId, type, payload, identifier, deviceId, clientType));
|
PushToServices((s) => s.SendPayloadToOrganizationAsync(orgId, type, payload, identifier, deviceId, clientType));
|
||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
@@ -166,12 +173,16 @@ public class MultiServicePushNotificationService : IPushNotificationService
|
|||||||
|
|
||||||
private void PushToServices(Func<IPushNotificationService, Task> pushFunc)
|
private void PushToServices(Func<IPushNotificationService, Task> pushFunc)
|
||||||
{
|
{
|
||||||
if (_services != null)
|
if (!_services.Any())
|
||||||
{
|
{
|
||||||
|
_logger.LogWarning("No services found to push notification");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var service in _services)
|
foreach (var service in _services)
|
||||||
{
|
{
|
||||||
|
_logger.LogDebug("Pushing notification to service {ServiceName}", service.GetType().Name);
|
||||||
pushFunc(service);
|
pushFunc(service);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Bit.Core.AdminConsole.Entities;
|
#nullable enable
|
||||||
|
using Bit.Core.AdminConsole.Entities;
|
||||||
using Bit.Core.Auth.Entities;
|
using Bit.Core.Auth.Entities;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.NotificationCenter.Entities;
|
using Bit.Core.NotificationCenter.Entities;
|
||||||
@@ -84,8 +85,8 @@ public class NoopPushNotificationService : IPushNotificationService
|
|||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SendPayloadToOrganizationAsync(string orgId, PushType type, object payload, string identifier,
|
public Task SendPayloadToOrganizationAsync(string orgId, PushType type, object payload, string? identifier,
|
||||||
string deviceId = null, ClientType? clientType = null)
|
string? deviceId = null, ClientType? clientType = null)
|
||||||
{
|
{
|
||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
}
|
}
|
||||||
@@ -107,11 +108,14 @@ public class NoopPushNotificationService : IPushNotificationService
|
|||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SendPayloadToUserAsync(string userId, PushType type, object payload, string identifier,
|
public Task SendPayloadToUserAsync(string userId, PushType type, object payload, string? identifier,
|
||||||
string deviceId = null, ClientType? clientType = null)
|
string? deviceId = null, ClientType? clientType = null)
|
||||||
{
|
{
|
||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task PushNotificationAsync(Notification notification) => Task.CompletedTask;
|
public Task PushNotificationAsync(Notification notification) => Task.CompletedTask;
|
||||||
|
|
||||||
|
public Task PushNotificationStatusAsync(Notification notification, NotificationStatus notificationStatus) =>
|
||||||
|
Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Bit.Core.AdminConsole.Entities;
|
#nullable enable
|
||||||
|
using Bit.Core.AdminConsole.Entities;
|
||||||
using Bit.Core.Auth.Entities;
|
using Bit.Core.Auth.Entities;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
@@ -16,7 +17,6 @@ namespace Bit.Core.Platform.Push;
|
|||||||
|
|
||||||
public class NotificationsApiPushNotificationService : BaseIdentityClientService, IPushNotificationService
|
public class NotificationsApiPushNotificationService : BaseIdentityClientService, IPushNotificationService
|
||||||
{
|
{
|
||||||
private readonly GlobalSettings _globalSettings;
|
|
||||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||||
|
|
||||||
public NotificationsApiPushNotificationService(
|
public NotificationsApiPushNotificationService(
|
||||||
@@ -33,7 +33,6 @@ public class NotificationsApiPushNotificationService : BaseIdentityClientService
|
|||||||
globalSettings.InternalIdentityKey,
|
globalSettings.InternalIdentityKey,
|
||||||
logger)
|
logger)
|
||||||
{
|
{
|
||||||
_globalSettings = globalSettings;
|
|
||||||
_httpContextAccessor = httpContextAccessor;
|
_httpContextAccessor = httpContextAccessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,7 +51,7 @@ public class NotificationsApiPushNotificationService : BaseIdentityClientService
|
|||||||
await PushCipherAsync(cipher, PushType.SyncLoginDelete, null);
|
await PushCipherAsync(cipher, PushType.SyncLoginDelete, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task PushCipherAsync(Cipher cipher, PushType type, IEnumerable<Guid> collectionIds)
|
private async Task PushCipherAsync(Cipher cipher, PushType type, IEnumerable<Guid>? collectionIds)
|
||||||
{
|
{
|
||||||
if (cipher.OrganizationId.HasValue)
|
if (cipher.OrganizationId.HasValue)
|
||||||
{
|
{
|
||||||
@@ -203,6 +202,27 @@ public class NotificationsApiPushNotificationService : BaseIdentityClientService
|
|||||||
await SendMessageAsync(PushType.SyncNotification, message, true);
|
await SendMessageAsync(PushType.SyncNotification, message, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task PushNotificationStatusAsync(Notification notification, NotificationStatus notificationStatus)
|
||||||
|
{
|
||||||
|
var message = new NotificationPushNotification
|
||||||
|
{
|
||||||
|
Id = notification.Id,
|
||||||
|
Priority = notification.Priority,
|
||||||
|
Global = notification.Global,
|
||||||
|
ClientType = notification.ClientType,
|
||||||
|
UserId = notification.UserId,
|
||||||
|
OrganizationId = notification.OrganizationId,
|
||||||
|
Title = notification.Title,
|
||||||
|
Body = notification.Body,
|
||||||
|
CreationDate = notification.CreationDate,
|
||||||
|
RevisionDate = notification.RevisionDate,
|
||||||
|
ReadDate = notificationStatus.ReadDate,
|
||||||
|
DeletedDate = notificationStatus.DeletedDate
|
||||||
|
};
|
||||||
|
|
||||||
|
await SendMessageAsync(PushType.SyncNotificationStatus, message, true);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task PushSendAsync(Send send, PushType type)
|
private async Task PushSendAsync(Send send, PushType type)
|
||||||
{
|
{
|
||||||
if (send.UserId.HasValue)
|
if (send.UserId.HasValue)
|
||||||
@@ -225,7 +245,7 @@ public class NotificationsApiPushNotificationService : BaseIdentityClientService
|
|||||||
await SendAsync(HttpMethod.Post, "send", request);
|
await SendAsync(HttpMethod.Post, "send", request);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetContextIdentifier(bool excludeCurrentContext)
|
private string? GetContextIdentifier(bool excludeCurrentContext)
|
||||||
{
|
{
|
||||||
if (!excludeCurrentContext)
|
if (!excludeCurrentContext)
|
||||||
{
|
{
|
||||||
@@ -233,19 +253,19 @@ public class NotificationsApiPushNotificationService : BaseIdentityClientService
|
|||||||
}
|
}
|
||||||
|
|
||||||
var currentContext =
|
var currentContext =
|
||||||
_httpContextAccessor?.HttpContext?.RequestServices.GetService(typeof(ICurrentContext)) as ICurrentContext;
|
_httpContextAccessor.HttpContext?.RequestServices.GetService(typeof(ICurrentContext)) as ICurrentContext;
|
||||||
return currentContext?.DeviceIdentifier;
|
return currentContext?.DeviceIdentifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SendPayloadToUserAsync(string userId, PushType type, object payload, string identifier,
|
public Task SendPayloadToUserAsync(string userId, PushType type, object payload, string? identifier,
|
||||||
string deviceId = null, ClientType? clientType = null)
|
string? deviceId = null, ClientType? clientType = null)
|
||||||
{
|
{
|
||||||
// Noop
|
// Noop
|
||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SendPayloadToOrganizationAsync(string orgId, PushType type, object payload, string identifier,
|
public Task SendPayloadToOrganizationAsync(string orgId, PushType type, object payload, string? identifier,
|
||||||
string deviceId = null, ClientType? clientType = null)
|
string? deviceId = null, ClientType? clientType = null)
|
||||||
{
|
{
|
||||||
// Noop
|
// Noop
|
||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Bit.Core.AdminConsole.Entities;
|
#nullable enable
|
||||||
|
using Bit.Core.AdminConsole.Entities;
|
||||||
using Bit.Core.Auth.Entities;
|
using Bit.Core.Auth.Entities;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
@@ -55,7 +56,7 @@ public class RelayPushNotificationService : BaseIdentityClientService, IPushNoti
|
|||||||
await PushCipherAsync(cipher, PushType.SyncLoginDelete, null);
|
await PushCipherAsync(cipher, PushType.SyncLoginDelete, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task PushCipherAsync(Cipher cipher, PushType type, IEnumerable<Guid> collectionIds)
|
private async Task PushCipherAsync(Cipher cipher, PushType type, IEnumerable<Guid>? collectionIds)
|
||||||
{
|
{
|
||||||
if (cipher.OrganizationId.HasValue)
|
if (cipher.OrganizationId.HasValue)
|
||||||
{
|
{
|
||||||
@@ -219,6 +220,36 @@ public class RelayPushNotificationService : BaseIdentityClientService, IPushNoti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task PushNotificationStatusAsync(Notification notification, NotificationStatus notificationStatus)
|
||||||
|
{
|
||||||
|
var message = new NotificationPushNotification
|
||||||
|
{
|
||||||
|
Id = notification.Id,
|
||||||
|
Priority = notification.Priority,
|
||||||
|
Global = notification.Global,
|
||||||
|
ClientType = notification.ClientType,
|
||||||
|
UserId = notification.UserId,
|
||||||
|
OrganizationId = notification.OrganizationId,
|
||||||
|
Title = notification.Title,
|
||||||
|
Body = notification.Body,
|
||||||
|
CreationDate = notification.CreationDate,
|
||||||
|
RevisionDate = notification.RevisionDate,
|
||||||
|
ReadDate = notificationStatus.ReadDate,
|
||||||
|
DeletedDate = notificationStatus.DeletedDate
|
||||||
|
};
|
||||||
|
|
||||||
|
if (notification.UserId.HasValue)
|
||||||
|
{
|
||||||
|
await SendPayloadToUserAsync(notification.UserId.Value, PushType.SyncNotificationStatus, message, true,
|
||||||
|
notification.ClientType);
|
||||||
|
}
|
||||||
|
else if (notification.OrganizationId.HasValue)
|
||||||
|
{
|
||||||
|
await SendPayloadToOrganizationAsync(notification.OrganizationId.Value, PushType.SyncNotificationStatus, message,
|
||||||
|
true, notification.ClientType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task PushSyncOrganizationStatusAsync(Organization organization)
|
public async Task PushSyncOrganizationStatusAsync(Organization organization)
|
||||||
{
|
{
|
||||||
var message = new OrganizationStatusPushNotification
|
var message = new OrganizationStatusPushNotification
|
||||||
@@ -277,7 +308,7 @@ public class RelayPushNotificationService : BaseIdentityClientService, IPushNoti
|
|||||||
private async Task AddCurrentContextAsync(PushSendRequestModel request, bool addIdentifier)
|
private async Task AddCurrentContextAsync(PushSendRequestModel request, bool addIdentifier)
|
||||||
{
|
{
|
||||||
var currentContext =
|
var currentContext =
|
||||||
_httpContextAccessor?.HttpContext?.RequestServices.GetService(typeof(ICurrentContext)) as ICurrentContext;
|
_httpContextAccessor.HttpContext?.RequestServices.GetService(typeof(ICurrentContext)) as ICurrentContext;
|
||||||
if (!string.IsNullOrWhiteSpace(currentContext?.DeviceIdentifier))
|
if (!string.IsNullOrWhiteSpace(currentContext?.DeviceIdentifier))
|
||||||
{
|
{
|
||||||
var device = await _deviceRepository.GetByIdentifierAsync(currentContext.DeviceIdentifier);
|
var device = await _deviceRepository.GetByIdentifierAsync(currentContext.DeviceIdentifier);
|
||||||
@@ -293,14 +324,14 @@ public class RelayPushNotificationService : BaseIdentityClientService, IPushNoti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SendPayloadToUserAsync(string userId, PushType type, object payload, string identifier,
|
public Task SendPayloadToUserAsync(string userId, PushType type, object payload, string? identifier,
|
||||||
string deviceId = null, ClientType? clientType = null)
|
string? deviceId = null, ClientType? clientType = null)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SendPayloadToOrganizationAsync(string orgId, PushType type, object payload, string identifier,
|
public Task SendPayloadToOrganizationAsync(string orgId, PushType type, object payload, string? identifier,
|
||||||
string deviceId = null, ClientType? clientType = null)
|
string? deviceId = null, ClientType? clientType = null)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ public static class HubHelpers
|
|||||||
.SendAsync("ReceiveMessage", organizationCollectionSettingsChangedNotification, cancellationToken);
|
.SendAsync("ReceiveMessage", organizationCollectionSettingsChangedNotification, cancellationToken);
|
||||||
break;
|
break;
|
||||||
case PushType.SyncNotification:
|
case PushType.SyncNotification:
|
||||||
|
case PushType.SyncNotificationStatus:
|
||||||
var syncNotification =
|
var syncNotification =
|
||||||
JsonSerializer.Deserialize<PushNotificationData<NotificationPushNotification>>(
|
JsonSerializer.Deserialize<PushNotificationData<NotificationPushNotification>>(
|
||||||
notificationJson, _deserializerOptions);
|
notificationJson, _deserializerOptions);
|
||||||
|
|||||||
@@ -41,6 +41,12 @@ public class CreateNotificationCommandTest
|
|||||||
Setup(sutProvider, notification, authorized: false);
|
Setup(sutProvider, notification, authorized: false);
|
||||||
|
|
||||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.CreateAsync(notification));
|
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.CreateAsync(notification));
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationAsync(Arg.Any<Notification>());
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationStatusAsync(Arg.Any<Notification>(), Arg.Any<NotificationStatus>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
@@ -59,5 +65,8 @@ public class CreateNotificationCommandTest
|
|||||||
await sutProvider.GetDependency<IPushNotificationService>()
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
.Received(1)
|
.Received(1)
|
||||||
.PushNotificationAsync(newNotification);
|
.PushNotificationAsync(newNotification);
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationStatusAsync(Arg.Any<Notification>(), Arg.Any<NotificationStatus>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Bit.Core.NotificationCenter.Authorization;
|
|||||||
using Bit.Core.NotificationCenter.Commands;
|
using Bit.Core.NotificationCenter.Commands;
|
||||||
using Bit.Core.NotificationCenter.Entities;
|
using Bit.Core.NotificationCenter.Entities;
|
||||||
using Bit.Core.NotificationCenter.Repositories;
|
using Bit.Core.NotificationCenter.Repositories;
|
||||||
|
using Bit.Core.Platform.Push;
|
||||||
using Bit.Core.Test.NotificationCenter.AutoFixture;
|
using Bit.Core.Test.NotificationCenter.AutoFixture;
|
||||||
using Bit.Test.Common.AutoFixture;
|
using Bit.Test.Common.AutoFixture;
|
||||||
using Bit.Test.Common.AutoFixture.Attributes;
|
using Bit.Test.Common.AutoFixture.Attributes;
|
||||||
@@ -50,6 +51,12 @@ public class CreateNotificationStatusCommandTest
|
|||||||
Setup(sutProvider, notification: null, notificationStatus, true, true);
|
Setup(sutProvider, notification: null, notificationStatus, true, true);
|
||||||
|
|
||||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.CreateAsync(notificationStatus));
|
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.CreateAsync(notificationStatus));
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationStatusAsync(Arg.Any<Notification>(), Arg.Any<NotificationStatus>());
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationAsync(Arg.Any<Notification>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
@@ -61,6 +68,12 @@ public class CreateNotificationStatusCommandTest
|
|||||||
Setup(sutProvider, notification, notificationStatus, authorizedNotification: false, true);
|
Setup(sutProvider, notification, notificationStatus, authorizedNotification: false, true);
|
||||||
|
|
||||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.CreateAsync(notificationStatus));
|
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.CreateAsync(notificationStatus));
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationStatusAsync(Arg.Any<Notification>(), Arg.Any<NotificationStatus>());
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationAsync(Arg.Any<Notification>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
@@ -72,6 +85,12 @@ public class CreateNotificationStatusCommandTest
|
|||||||
Setup(sutProvider, notification, notificationStatus, true, authorizedCreate: false);
|
Setup(sutProvider, notification, notificationStatus, true, authorizedCreate: false);
|
||||||
|
|
||||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.CreateAsync(notificationStatus));
|
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.CreateAsync(notificationStatus));
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationStatusAsync(Arg.Any<Notification>(), Arg.Any<NotificationStatus>());
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationAsync(Arg.Any<Notification>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
@@ -85,5 +104,11 @@ public class CreateNotificationStatusCommandTest
|
|||||||
var newNotificationStatus = await sutProvider.Sut.CreateAsync(notificationStatus);
|
var newNotificationStatus = await sutProvider.Sut.CreateAsync(notificationStatus);
|
||||||
|
|
||||||
Assert.Equal(notificationStatus, newNotificationStatus);
|
Assert.Equal(notificationStatus, newNotificationStatus);
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(1)
|
||||||
|
.PushNotificationStatusAsync(notification, notificationStatus);
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationAsync(Arg.Any<Notification>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using Bit.Core.NotificationCenter.Authorization;
|
|||||||
using Bit.Core.NotificationCenter.Commands;
|
using Bit.Core.NotificationCenter.Commands;
|
||||||
using Bit.Core.NotificationCenter.Entities;
|
using Bit.Core.NotificationCenter.Entities;
|
||||||
using Bit.Core.NotificationCenter.Repositories;
|
using Bit.Core.NotificationCenter.Repositories;
|
||||||
|
using Bit.Core.Platform.Push;
|
||||||
using Bit.Core.Test.NotificationCenter.AutoFixture;
|
using Bit.Core.Test.NotificationCenter.AutoFixture;
|
||||||
using Bit.Test.Common.AutoFixture;
|
using Bit.Test.Common.AutoFixture;
|
||||||
using Bit.Test.Common.AutoFixture.Attributes;
|
using Bit.Test.Common.AutoFixture.Attributes;
|
||||||
@@ -63,6 +64,12 @@ public class MarkNotificationDeletedCommandTest
|
|||||||
Setup(sutProvider, notificationId, userId: null, notification, notificationStatus, true, true, true);
|
Setup(sutProvider, notificationId, userId: null, notification, notificationStatus, true, true, true);
|
||||||
|
|
||||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.MarkDeletedAsync(notificationId));
|
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.MarkDeletedAsync(notificationId));
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationStatusAsync(Arg.Any<Notification>(), Arg.Any<NotificationStatus>());
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationAsync(Arg.Any<Notification>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
@@ -74,6 +81,12 @@ public class MarkNotificationDeletedCommandTest
|
|||||||
Setup(sutProvider, notificationId, userId, notification: null, notificationStatus, true, true, true);
|
Setup(sutProvider, notificationId, userId, notification: null, notificationStatus, true, true, true);
|
||||||
|
|
||||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.MarkDeletedAsync(notificationId));
|
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.MarkDeletedAsync(notificationId));
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationStatusAsync(Arg.Any<Notification>(), Arg.Any<NotificationStatus>());
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationAsync(Arg.Any<Notification>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
@@ -86,6 +99,12 @@ public class MarkNotificationDeletedCommandTest
|
|||||||
true, true);
|
true, true);
|
||||||
|
|
||||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.MarkDeletedAsync(notificationId));
|
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.MarkDeletedAsync(notificationId));
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationStatusAsync(Arg.Any<Notification>(), Arg.Any<NotificationStatus>());
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationAsync(Arg.Any<Notification>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
@@ -98,6 +117,12 @@ public class MarkNotificationDeletedCommandTest
|
|||||||
authorizedCreate: false, true);
|
authorizedCreate: false, true);
|
||||||
|
|
||||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.MarkDeletedAsync(notificationId));
|
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.MarkDeletedAsync(notificationId));
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationStatusAsync(Arg.Any<Notification>(), Arg.Any<NotificationStatus>());
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationAsync(Arg.Any<Notification>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
@@ -110,6 +135,12 @@ public class MarkNotificationDeletedCommandTest
|
|||||||
authorizedUpdate: false);
|
authorizedUpdate: false);
|
||||||
|
|
||||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.MarkDeletedAsync(notificationId));
|
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.MarkDeletedAsync(notificationId));
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationStatusAsync(Arg.Any<Notification>(), Arg.Any<NotificationStatus>());
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationAsync(Arg.Any<Notification>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
@@ -119,13 +150,25 @@ public class MarkNotificationDeletedCommandTest
|
|||||||
Guid notificationId, Guid userId, Notification notification)
|
Guid notificationId, Guid userId, Notification notification)
|
||||||
{
|
{
|
||||||
Setup(sutProvider, notificationId, userId, notification, notificationStatus: null, true, true, true);
|
Setup(sutProvider, notificationId, userId, notification, notificationStatus: null, true, true, true);
|
||||||
|
var expectedNotificationStatus = new NotificationStatus
|
||||||
|
{
|
||||||
|
NotificationId = notificationId,
|
||||||
|
UserId = userId,
|
||||||
|
ReadDate = null,
|
||||||
|
DeletedDate = DateTime.UtcNow
|
||||||
|
};
|
||||||
|
|
||||||
await sutProvider.Sut.MarkDeletedAsync(notificationId);
|
await sutProvider.Sut.MarkDeletedAsync(notificationId);
|
||||||
|
|
||||||
await sutProvider.GetDependency<INotificationStatusRepository>().Received(1)
|
await sutProvider.GetDependency<INotificationStatusRepository>().Received(1)
|
||||||
.CreateAsync(Arg.Is<NotificationStatus>(ns =>
|
.CreateAsync(Arg.Do<NotificationStatus>(ns => AssertNotificationStatus(expectedNotificationStatus, ns)));
|
||||||
ns.NotificationId == notificationId && ns.UserId == userId && !ns.ReadDate.HasValue &&
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
ns.DeletedDate.HasValue && DateTime.UtcNow - ns.DeletedDate.Value < TimeSpan.FromMinutes(1)));
|
.Received(1)
|
||||||
|
.PushNotificationStatusAsync(notification,
|
||||||
|
Arg.Do<NotificationStatus>(ns => AssertNotificationStatus(expectedNotificationStatus, ns)));
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationAsync(Arg.Any<Notification>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
@@ -134,18 +177,30 @@ public class MarkNotificationDeletedCommandTest
|
|||||||
SutProvider<MarkNotificationDeletedCommand> sutProvider,
|
SutProvider<MarkNotificationDeletedCommand> sutProvider,
|
||||||
Guid notificationId, Guid userId, Notification notification, NotificationStatus notificationStatus)
|
Guid notificationId, Guid userId, Notification notification, NotificationStatus notificationStatus)
|
||||||
{
|
{
|
||||||
var deletedDate = notificationStatus.DeletedDate;
|
|
||||||
|
|
||||||
Setup(sutProvider, notificationId, userId, notification, notificationStatus, true, true, true);
|
Setup(sutProvider, notificationId, userId, notification, notificationStatus, true, true, true);
|
||||||
|
|
||||||
await sutProvider.Sut.MarkDeletedAsync(notificationId);
|
await sutProvider.Sut.MarkDeletedAsync(notificationId);
|
||||||
|
|
||||||
await sutProvider.GetDependency<INotificationStatusRepository>().Received(1)
|
await sutProvider.GetDependency<INotificationStatusRepository>().Received(1)
|
||||||
.UpdateAsync(Arg.Is<NotificationStatus>(ns =>
|
.UpdateAsync(Arg.Do<NotificationStatus>(ns => AssertNotificationStatus(notificationStatus, ns)));
|
||||||
ns.Equals(notificationStatus) &&
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
ns.NotificationId == notificationStatus.NotificationId && ns.UserId == notificationStatus.UserId &&
|
.Received(1)
|
||||||
ns.ReadDate == notificationStatus.ReadDate && ns.DeletedDate != deletedDate &&
|
.PushNotificationStatusAsync(notification,
|
||||||
ns.DeletedDate.HasValue &&
|
Arg.Do<NotificationStatus>(ns => AssertNotificationStatus(notificationStatus, ns)));
|
||||||
DateTime.UtcNow - ns.DeletedDate.Value < TimeSpan.FromMinutes(1)));
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationAsync(Arg.Any<Notification>());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AssertNotificationStatus(NotificationStatus expectedNotificationStatus,
|
||||||
|
NotificationStatus? actualNotificationStatus)
|
||||||
|
{
|
||||||
|
Assert.NotNull(actualNotificationStatus);
|
||||||
|
Assert.Equal(expectedNotificationStatus.NotificationId, actualNotificationStatus.NotificationId);
|
||||||
|
Assert.Equal(expectedNotificationStatus.UserId, actualNotificationStatus.UserId);
|
||||||
|
Assert.Equal(expectedNotificationStatus.ReadDate, actualNotificationStatus.ReadDate);
|
||||||
|
Assert.NotEqual(expectedNotificationStatus.DeletedDate, actualNotificationStatus.DeletedDate);
|
||||||
|
Assert.NotNull(actualNotificationStatus.DeletedDate);
|
||||||
|
Assert.Equal(DateTime.UtcNow, actualNotificationStatus.DeletedDate.Value, TimeSpan.FromMinutes(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using Bit.Core.NotificationCenter.Authorization;
|
|||||||
using Bit.Core.NotificationCenter.Commands;
|
using Bit.Core.NotificationCenter.Commands;
|
||||||
using Bit.Core.NotificationCenter.Entities;
|
using Bit.Core.NotificationCenter.Entities;
|
||||||
using Bit.Core.NotificationCenter.Repositories;
|
using Bit.Core.NotificationCenter.Repositories;
|
||||||
|
using Bit.Core.Platform.Push;
|
||||||
using Bit.Core.Test.NotificationCenter.AutoFixture;
|
using Bit.Core.Test.NotificationCenter.AutoFixture;
|
||||||
using Bit.Test.Common.AutoFixture;
|
using Bit.Test.Common.AutoFixture;
|
||||||
using Bit.Test.Common.AutoFixture.Attributes;
|
using Bit.Test.Common.AutoFixture.Attributes;
|
||||||
@@ -63,6 +64,12 @@ public class MarkNotificationReadCommandTest
|
|||||||
Setup(sutProvider, notificationId, userId: null, notification, notificationStatus, true, true, true);
|
Setup(sutProvider, notificationId, userId: null, notification, notificationStatus, true, true, true);
|
||||||
|
|
||||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.MarkReadAsync(notificationId));
|
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.MarkReadAsync(notificationId));
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationStatusAsync(Arg.Any<Notification>(), Arg.Any<NotificationStatus>());
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationAsync(Arg.Any<Notification>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
@@ -74,6 +81,12 @@ public class MarkNotificationReadCommandTest
|
|||||||
Setup(sutProvider, notificationId, userId, notification: null, notificationStatus, true, true, true);
|
Setup(sutProvider, notificationId, userId, notification: null, notificationStatus, true, true, true);
|
||||||
|
|
||||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.MarkReadAsync(notificationId));
|
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.MarkReadAsync(notificationId));
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationStatusAsync(Arg.Any<Notification>(), Arg.Any<NotificationStatus>());
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationAsync(Arg.Any<Notification>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
@@ -86,6 +99,12 @@ public class MarkNotificationReadCommandTest
|
|||||||
true, true);
|
true, true);
|
||||||
|
|
||||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.MarkReadAsync(notificationId));
|
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.MarkReadAsync(notificationId));
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationStatusAsync(Arg.Any<Notification>(), Arg.Any<NotificationStatus>());
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationAsync(Arg.Any<Notification>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
@@ -98,6 +117,12 @@ public class MarkNotificationReadCommandTest
|
|||||||
authorizedCreate: false, true);
|
authorizedCreate: false, true);
|
||||||
|
|
||||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.MarkReadAsync(notificationId));
|
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.MarkReadAsync(notificationId));
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationStatusAsync(Arg.Any<Notification>(), Arg.Any<NotificationStatus>());
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationAsync(Arg.Any<Notification>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
@@ -110,6 +135,12 @@ public class MarkNotificationReadCommandTest
|
|||||||
authorizedUpdate: false);
|
authorizedUpdate: false);
|
||||||
|
|
||||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.MarkReadAsync(notificationId));
|
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.MarkReadAsync(notificationId));
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationStatusAsync(Arg.Any<Notification>(), Arg.Any<NotificationStatus>());
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationAsync(Arg.Any<Notification>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
@@ -119,13 +150,25 @@ public class MarkNotificationReadCommandTest
|
|||||||
Guid notificationId, Guid userId, Notification notification)
|
Guid notificationId, Guid userId, Notification notification)
|
||||||
{
|
{
|
||||||
Setup(sutProvider, notificationId, userId, notification, notificationStatus: null, true, true, true);
|
Setup(sutProvider, notificationId, userId, notification, notificationStatus: null, true, true, true);
|
||||||
|
var expectedNotificationStatus = new NotificationStatus
|
||||||
|
{
|
||||||
|
NotificationId = notificationId,
|
||||||
|
UserId = userId,
|
||||||
|
ReadDate = DateTime.UtcNow,
|
||||||
|
DeletedDate = null
|
||||||
|
};
|
||||||
|
|
||||||
await sutProvider.Sut.MarkReadAsync(notificationId);
|
await sutProvider.Sut.MarkReadAsync(notificationId);
|
||||||
|
|
||||||
await sutProvider.GetDependency<INotificationStatusRepository>().Received(1)
|
await sutProvider.GetDependency<INotificationStatusRepository>().Received(1)
|
||||||
.CreateAsync(Arg.Is<NotificationStatus>(ns =>
|
.CreateAsync(Arg.Do<NotificationStatus>(ns => AssertNotificationStatus(expectedNotificationStatus, ns)));
|
||||||
ns.NotificationId == notificationId && ns.UserId == userId && !ns.DeletedDate.HasValue &&
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
ns.ReadDate.HasValue && DateTime.UtcNow - ns.ReadDate.Value < TimeSpan.FromMinutes(1)));
|
.Received(1)
|
||||||
|
.PushNotificationStatusAsync(notification,
|
||||||
|
Arg.Do<NotificationStatus>(ns => AssertNotificationStatus(expectedNotificationStatus, ns)));
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationAsync(Arg.Any<Notification>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
@@ -134,18 +177,30 @@ public class MarkNotificationReadCommandTest
|
|||||||
SutProvider<MarkNotificationReadCommand> sutProvider,
|
SutProvider<MarkNotificationReadCommand> sutProvider,
|
||||||
Guid notificationId, Guid userId, Notification notification, NotificationStatus notificationStatus)
|
Guid notificationId, Guid userId, Notification notification, NotificationStatus notificationStatus)
|
||||||
{
|
{
|
||||||
var readDate = notificationStatus.ReadDate;
|
|
||||||
|
|
||||||
Setup(sutProvider, notificationId, userId, notification, notificationStatus, true, true, true);
|
Setup(sutProvider, notificationId, userId, notification, notificationStatus, true, true, true);
|
||||||
|
|
||||||
await sutProvider.Sut.MarkReadAsync(notificationId);
|
await sutProvider.Sut.MarkReadAsync(notificationId);
|
||||||
|
|
||||||
await sutProvider.GetDependency<INotificationStatusRepository>().Received(1)
|
await sutProvider.GetDependency<INotificationStatusRepository>().Received(1)
|
||||||
.UpdateAsync(Arg.Is<NotificationStatus>(ns =>
|
.UpdateAsync(Arg.Do<NotificationStatus>(ns => AssertNotificationStatus(notificationStatus, ns)));
|
||||||
ns.Equals(notificationStatus) &&
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
ns.NotificationId == notificationStatus.NotificationId && ns.UserId == notificationStatus.UserId &&
|
.Received(1)
|
||||||
ns.DeletedDate == notificationStatus.DeletedDate && ns.ReadDate != readDate &&
|
.PushNotificationStatusAsync(notification,
|
||||||
ns.ReadDate.HasValue &&
|
Arg.Do<NotificationStatus>(ns => AssertNotificationStatus(notificationStatus, ns)));
|
||||||
DateTime.UtcNow - ns.ReadDate.Value < TimeSpan.FromMinutes(1)));
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationAsync(Arg.Any<Notification>());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AssertNotificationStatus(NotificationStatus expectedNotificationStatus,
|
||||||
|
NotificationStatus? actualNotificationStatus)
|
||||||
|
{
|
||||||
|
Assert.NotNull(actualNotificationStatus);
|
||||||
|
Assert.Equal(expectedNotificationStatus.NotificationId, actualNotificationStatus.NotificationId);
|
||||||
|
Assert.Equal(expectedNotificationStatus.UserId, actualNotificationStatus.UserId);
|
||||||
|
Assert.NotEqual(expectedNotificationStatus.ReadDate, actualNotificationStatus.ReadDate);
|
||||||
|
Assert.NotNull(actualNotificationStatus.ReadDate);
|
||||||
|
Assert.Equal(DateTime.UtcNow, actualNotificationStatus.ReadDate.Value, TimeSpan.FromMinutes(1));
|
||||||
|
Assert.Equal(expectedNotificationStatus.DeletedDate, actualNotificationStatus.DeletedDate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using Bit.Core.NotificationCenter.Commands;
|
|||||||
using Bit.Core.NotificationCenter.Entities;
|
using Bit.Core.NotificationCenter.Entities;
|
||||||
using Bit.Core.NotificationCenter.Enums;
|
using Bit.Core.NotificationCenter.Enums;
|
||||||
using Bit.Core.NotificationCenter.Repositories;
|
using Bit.Core.NotificationCenter.Repositories;
|
||||||
|
using Bit.Core.Platform.Push;
|
||||||
using Bit.Core.Test.NotificationCenter.AutoFixture;
|
using Bit.Core.Test.NotificationCenter.AutoFixture;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Bit.Test.Common.AutoFixture;
|
using Bit.Test.Common.AutoFixture;
|
||||||
@@ -45,6 +46,12 @@ public class UpdateNotificationCommandTest
|
|||||||
Setup(sutProvider, notification.Id, notification: null, true);
|
Setup(sutProvider, notification.Id, notification: null, true);
|
||||||
|
|
||||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.UpdateAsync(notification));
|
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.UpdateAsync(notification));
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationAsync(Arg.Any<Notification>());
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationStatusAsync(Arg.Any<Notification>(), Arg.Any<NotificationStatus>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
@@ -56,6 +63,12 @@ public class UpdateNotificationCommandTest
|
|||||||
Setup(sutProvider, notification.Id, notification, authorized: false);
|
Setup(sutProvider, notification.Id, notification, authorized: false);
|
||||||
|
|
||||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.UpdateAsync(notification));
|
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.UpdateAsync(notification));
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationAsync(Arg.Any<Notification>());
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationStatusAsync(Arg.Any<Notification>(), Arg.Any<NotificationStatus>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
@@ -91,5 +104,11 @@ public class UpdateNotificationCommandTest
|
|||||||
n.Priority == notificationToUpdate.Priority && n.ClientType == notificationToUpdate.ClientType &&
|
n.Priority == notificationToUpdate.Priority && n.ClientType == notificationToUpdate.ClientType &&
|
||||||
n.Title == notificationToUpdate.Title && n.Body == notificationToUpdate.Body &&
|
n.Title == notificationToUpdate.Title && n.Body == notificationToUpdate.Body &&
|
||||||
DateTime.UtcNow - n.RevisionDate < TimeSpan.FromMinutes(1)));
|
DateTime.UtcNow - n.RevisionDate < TimeSpan.FromMinutes(1)));
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(1)
|
||||||
|
.PushNotificationAsync(notification);
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>()
|
||||||
|
.Received(0)
|
||||||
|
.PushNotificationStatusAsync(Arg.Any<Notification>(), Arg.Any<NotificationStatus>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,12 +15,13 @@ using Xunit;
|
|||||||
namespace Bit.Core.Test.NotificationHub;
|
namespace Bit.Core.Test.NotificationHub;
|
||||||
|
|
||||||
[SutProviderCustomize]
|
[SutProviderCustomize]
|
||||||
|
[NotificationStatusCustomize]
|
||||||
public class NotificationHubPushNotificationServiceTests
|
public class NotificationHubPushNotificationServiceTests
|
||||||
{
|
{
|
||||||
[Theory]
|
[Theory]
|
||||||
[BitAutoData]
|
[BitAutoData]
|
||||||
[NotificationCustomize]
|
[NotificationCustomize]
|
||||||
public async void PushNotificationAsync_Global_NotSent(
|
public async Task PushNotificationAsync_Global_NotSent(
|
||||||
SutProvider<NotificationHubPushNotificationService> sutProvider, Notification notification)
|
SutProvider<NotificationHubPushNotificationService> sutProvider, Notification notification)
|
||||||
{
|
{
|
||||||
await sutProvider.Sut.PushNotificationAsync(notification);
|
await sutProvider.Sut.PushNotificationAsync(notification);
|
||||||
@@ -39,7 +40,7 @@ public class NotificationHubPushNotificationServiceTests
|
|||||||
[BitAutoData(false)]
|
[BitAutoData(false)]
|
||||||
[BitAutoData(true)]
|
[BitAutoData(true)]
|
||||||
[NotificationCustomize(false)]
|
[NotificationCustomize(false)]
|
||||||
public async void PushNotificationAsync_UserIdProvidedClientTypeAll_SentToUser(
|
public async Task PushNotificationAsync_UserIdProvidedClientTypeAll_SentToUser(
|
||||||
bool organizationIdNull, SutProvider<NotificationHubPushNotificationService> sutProvider,
|
bool organizationIdNull, SutProvider<NotificationHubPushNotificationService> sutProvider,
|
||||||
Notification notification)
|
Notification notification)
|
||||||
{
|
{
|
||||||
@@ -49,11 +50,12 @@ public class NotificationHubPushNotificationServiceTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
notification.ClientType = ClientType.All;
|
notification.ClientType = ClientType.All;
|
||||||
var expectedSyncNotification = ToSyncNotificationPushNotification(notification);
|
var expectedNotification = ToNotificationPushNotification(notification, null);
|
||||||
|
|
||||||
await sutProvider.Sut.PushNotificationAsync(notification);
|
await sutProvider.Sut.PushNotificationAsync(notification);
|
||||||
|
|
||||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotification, expectedSyncNotification,
|
await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotification,
|
||||||
|
expectedNotification,
|
||||||
$"(template:payload_userId:{notification.UserId})");
|
$"(template:payload_userId:{notification.UserId})");
|
||||||
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
||||||
.Received(0)
|
.Received(0)
|
||||||
@@ -61,30 +63,46 @@ public class NotificationHubPushNotificationServiceTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[BitAutoData(false, ClientType.Browser)]
|
[BitAutoData(ClientType.Browser)]
|
||||||
[BitAutoData(false, ClientType.Desktop)]
|
[BitAutoData(ClientType.Desktop)]
|
||||||
[BitAutoData(false, ClientType.Web)]
|
[BitAutoData(ClientType.Web)]
|
||||||
[BitAutoData(false, ClientType.Mobile)]
|
[BitAutoData(ClientType.Mobile)]
|
||||||
[BitAutoData(true, ClientType.Browser)]
|
|
||||||
[BitAutoData(true, ClientType.Desktop)]
|
|
||||||
[BitAutoData(true, ClientType.Web)]
|
|
||||||
[BitAutoData(true, ClientType.Mobile)]
|
|
||||||
[NotificationCustomize(false)]
|
[NotificationCustomize(false)]
|
||||||
public async void PushNotificationAsync_UserIdProvidedClientTypeNotAll_SentToUser(bool organizationIdNull,
|
public async Task PushNotificationAsync_UserIdProvidedOrganizationIdNullClientTypeNotAll_SentToUser(
|
||||||
ClientType clientType, SutProvider<NotificationHubPushNotificationService> sutProvider,
|
ClientType clientType, SutProvider<NotificationHubPushNotificationService> sutProvider,
|
||||||
Notification notification)
|
Notification notification)
|
||||||
{
|
|
||||||
if (organizationIdNull)
|
|
||||||
{
|
{
|
||||||
notification.OrganizationId = null;
|
notification.OrganizationId = null;
|
||||||
}
|
|
||||||
|
|
||||||
notification.ClientType = clientType;
|
notification.ClientType = clientType;
|
||||||
var expectedSyncNotification = ToSyncNotificationPushNotification(notification);
|
var expectedNotification = ToNotificationPushNotification(notification, null);
|
||||||
|
|
||||||
await sutProvider.Sut.PushNotificationAsync(notification);
|
await sutProvider.Sut.PushNotificationAsync(notification);
|
||||||
|
|
||||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotification, expectedSyncNotification,
|
await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotification,
|
||||||
|
expectedNotification,
|
||||||
|
$"(template:payload_userId:{notification.UserId} && clientType:{clientType})");
|
||||||
|
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
||||||
|
.Received(0)
|
||||||
|
.UpsertAsync(Arg.Any<InstallationDeviceEntity>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData(ClientType.Browser)]
|
||||||
|
[BitAutoData(ClientType.Desktop)]
|
||||||
|
[BitAutoData(ClientType.Web)]
|
||||||
|
[BitAutoData(ClientType.Mobile)]
|
||||||
|
[NotificationCustomize(false)]
|
||||||
|
public async Task PushNotificationAsync_UserIdProvidedOrganizationIdProvidedClientTypeNotAll_SentToUser(
|
||||||
|
ClientType clientType, SutProvider<NotificationHubPushNotificationService> sutProvider,
|
||||||
|
Notification notification)
|
||||||
|
{
|
||||||
|
notification.ClientType = clientType;
|
||||||
|
var expectedNotification = ToNotificationPushNotification(notification, null);
|
||||||
|
|
||||||
|
await sutProvider.Sut.PushNotificationAsync(notification);
|
||||||
|
|
||||||
|
await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotification,
|
||||||
|
expectedNotification,
|
||||||
$"(template:payload_userId:{notification.UserId} && clientType:{clientType})");
|
$"(template:payload_userId:{notification.UserId} && clientType:{clientType})");
|
||||||
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
||||||
.Received(0)
|
.Received(0)
|
||||||
@@ -94,16 +112,17 @@ public class NotificationHubPushNotificationServiceTests
|
|||||||
[Theory]
|
[Theory]
|
||||||
[BitAutoData]
|
[BitAutoData]
|
||||||
[NotificationCustomize(false)]
|
[NotificationCustomize(false)]
|
||||||
public async void PushNotificationAsync_UserIdNullOrganizationIdProvidedClientTypeAll_SentToOrganization(
|
public async Task PushNotificationAsync_UserIdNullOrganizationIdProvidedClientTypeAll_SentToOrganization(
|
||||||
SutProvider<NotificationHubPushNotificationService> sutProvider, Notification notification)
|
SutProvider<NotificationHubPushNotificationService> sutProvider, Notification notification)
|
||||||
{
|
{
|
||||||
notification.UserId = null;
|
notification.UserId = null;
|
||||||
notification.ClientType = ClientType.All;
|
notification.ClientType = ClientType.All;
|
||||||
var expectedSyncNotification = ToSyncNotificationPushNotification(notification);
|
var expectedNotification = ToNotificationPushNotification(notification, null);
|
||||||
|
|
||||||
await sutProvider.Sut.PushNotificationAsync(notification);
|
await sutProvider.Sut.PushNotificationAsync(notification);
|
||||||
|
|
||||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotification, expectedSyncNotification,
|
await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotification,
|
||||||
|
expectedNotification,
|
||||||
$"(template:payload && organizationId:{notification.OrganizationId})");
|
$"(template:payload && organizationId:{notification.OrganizationId})");
|
||||||
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
||||||
.Received(0)
|
.Received(0)
|
||||||
@@ -116,18 +135,156 @@ public class NotificationHubPushNotificationServiceTests
|
|||||||
[BitAutoData(ClientType.Web)]
|
[BitAutoData(ClientType.Web)]
|
||||||
[BitAutoData(ClientType.Mobile)]
|
[BitAutoData(ClientType.Mobile)]
|
||||||
[NotificationCustomize(false)]
|
[NotificationCustomize(false)]
|
||||||
public async void PushNotificationAsync_UserIdNullOrganizationIdProvidedClientTypeNotAll_SentToOrganization(
|
public async Task PushNotificationAsync_UserIdNullOrganizationIdProvidedClientTypeNotAll_SentToOrganization(
|
||||||
ClientType clientType, SutProvider<NotificationHubPushNotificationService> sutProvider,
|
ClientType clientType, SutProvider<NotificationHubPushNotificationService> sutProvider,
|
||||||
Notification notification)
|
Notification notification)
|
||||||
{
|
{
|
||||||
notification.UserId = null;
|
notification.UserId = null;
|
||||||
notification.ClientType = clientType;
|
notification.ClientType = clientType;
|
||||||
|
var expectedNotification = ToNotificationPushNotification(notification, null);
|
||||||
var expectedSyncNotification = ToSyncNotificationPushNotification(notification);
|
|
||||||
|
|
||||||
await sutProvider.Sut.PushNotificationAsync(notification);
|
await sutProvider.Sut.PushNotificationAsync(notification);
|
||||||
|
|
||||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotification, expectedSyncNotification,
|
await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotification,
|
||||||
|
expectedNotification,
|
||||||
|
$"(template:payload && organizationId:{notification.OrganizationId} && clientType:{clientType})");
|
||||||
|
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
||||||
|
.Received(0)
|
||||||
|
.UpsertAsync(Arg.Any<InstallationDeviceEntity>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData]
|
||||||
|
[NotificationCustomize]
|
||||||
|
public async Task PushNotificationStatusAsync_Global_NotSent(
|
||||||
|
SutProvider<NotificationHubPushNotificationService> sutProvider, Notification notification,
|
||||||
|
NotificationStatus notificationStatus)
|
||||||
|
{
|
||||||
|
await sutProvider.Sut.PushNotificationStatusAsync(notification, notificationStatus);
|
||||||
|
|
||||||
|
await sutProvider.GetDependency<INotificationHubPool>()
|
||||||
|
.Received(0)
|
||||||
|
.AllClients
|
||||||
|
.Received(0)
|
||||||
|
.SendTemplateNotificationAsync(Arg.Any<IDictionary<string, string>>(), Arg.Any<string>());
|
||||||
|
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
||||||
|
.Received(0)
|
||||||
|
.UpsertAsync(Arg.Any<InstallationDeviceEntity>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData(false)]
|
||||||
|
[BitAutoData(true)]
|
||||||
|
[NotificationCustomize(false)]
|
||||||
|
public async Task PushNotificationStatusAsync_UserIdProvidedClientTypeAll_SentToUser(
|
||||||
|
bool organizationIdNull, SutProvider<NotificationHubPushNotificationService> sutProvider,
|
||||||
|
Notification notification, NotificationStatus notificationStatus)
|
||||||
|
{
|
||||||
|
if (organizationIdNull)
|
||||||
|
{
|
||||||
|
notification.OrganizationId = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
notification.ClientType = ClientType.All;
|
||||||
|
var expectedNotification = ToNotificationPushNotification(notification, notificationStatus);
|
||||||
|
|
||||||
|
await sutProvider.Sut.PushNotificationStatusAsync(notification, notificationStatus);
|
||||||
|
|
||||||
|
await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotificationStatus,
|
||||||
|
expectedNotification,
|
||||||
|
$"(template:payload_userId:{notification.UserId})");
|
||||||
|
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
||||||
|
.Received(0)
|
||||||
|
.UpsertAsync(Arg.Any<InstallationDeviceEntity>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData(ClientType.Browser)]
|
||||||
|
[BitAutoData(ClientType.Desktop)]
|
||||||
|
[BitAutoData(ClientType.Web)]
|
||||||
|
[BitAutoData(ClientType.Mobile)]
|
||||||
|
[NotificationCustomize(false)]
|
||||||
|
public async Task PushNotificationStatusAsync_UserIdProvidedOrganizationIdNullClientTypeNotAll_SentToUser(
|
||||||
|
ClientType clientType, SutProvider<NotificationHubPushNotificationService> sutProvider,
|
||||||
|
Notification notification, NotificationStatus notificationStatus)
|
||||||
|
{
|
||||||
|
notification.OrganizationId = null;
|
||||||
|
notification.ClientType = clientType;
|
||||||
|
var expectedNotification = ToNotificationPushNotification(notification, notificationStatus);
|
||||||
|
|
||||||
|
await sutProvider.Sut.PushNotificationStatusAsync(notification, notificationStatus);
|
||||||
|
|
||||||
|
await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotificationStatus,
|
||||||
|
expectedNotification,
|
||||||
|
$"(template:payload_userId:{notification.UserId} && clientType:{clientType})");
|
||||||
|
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
||||||
|
.Received(0)
|
||||||
|
.UpsertAsync(Arg.Any<InstallationDeviceEntity>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData(ClientType.Browser)]
|
||||||
|
[BitAutoData(ClientType.Desktop)]
|
||||||
|
[BitAutoData(ClientType.Web)]
|
||||||
|
[BitAutoData(ClientType.Mobile)]
|
||||||
|
[NotificationCustomize(false)]
|
||||||
|
public async Task PushNotificationStatusAsync_UserIdProvidedOrganizationIdProvidedClientTypeNotAll_SentToUser(
|
||||||
|
ClientType clientType, SutProvider<NotificationHubPushNotificationService> sutProvider,
|
||||||
|
Notification notification, NotificationStatus notificationStatus)
|
||||||
|
{
|
||||||
|
notification.ClientType = clientType;
|
||||||
|
var expectedNotification = ToNotificationPushNotification(notification, notificationStatus);
|
||||||
|
|
||||||
|
await sutProvider.Sut.PushNotificationStatusAsync(notification, notificationStatus);
|
||||||
|
|
||||||
|
await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotificationStatus,
|
||||||
|
expectedNotification,
|
||||||
|
$"(template:payload_userId:{notification.UserId} && clientType:{clientType})");
|
||||||
|
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
||||||
|
.Received(0)
|
||||||
|
.UpsertAsync(Arg.Any<InstallationDeviceEntity>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData]
|
||||||
|
[NotificationCustomize(false)]
|
||||||
|
public async Task PushNotificationStatusAsync_UserIdNullOrganizationIdProvidedClientTypeAll_SentToOrganization(
|
||||||
|
SutProvider<NotificationHubPushNotificationService> sutProvider, Notification notification,
|
||||||
|
NotificationStatus notificationStatus)
|
||||||
|
{
|
||||||
|
notification.UserId = null;
|
||||||
|
notification.ClientType = ClientType.All;
|
||||||
|
var expectedNotification = ToNotificationPushNotification(notification, notificationStatus);
|
||||||
|
|
||||||
|
await sutProvider.Sut.PushNotificationStatusAsync(notification, notificationStatus);
|
||||||
|
|
||||||
|
await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotificationStatus,
|
||||||
|
expectedNotification,
|
||||||
|
$"(template:payload && organizationId:{notification.OrganizationId})");
|
||||||
|
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
||||||
|
.Received(0)
|
||||||
|
.UpsertAsync(Arg.Any<InstallationDeviceEntity>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData(ClientType.Browser)]
|
||||||
|
[BitAutoData(ClientType.Desktop)]
|
||||||
|
[BitAutoData(ClientType.Web)]
|
||||||
|
[BitAutoData(ClientType.Mobile)]
|
||||||
|
[NotificationCustomize(false)]
|
||||||
|
public async Task
|
||||||
|
PushNotificationStatusAsync_UserIdNullOrganizationIdProvidedClientTypeNotAll_SentToOrganization(
|
||||||
|
ClientType clientType, SutProvider<NotificationHubPushNotificationService> sutProvider,
|
||||||
|
Notification notification, NotificationStatus notificationStatus)
|
||||||
|
{
|
||||||
|
notification.UserId = null;
|
||||||
|
notification.ClientType = clientType;
|
||||||
|
var expectedNotification = ToNotificationPushNotification(notification, notificationStatus);
|
||||||
|
|
||||||
|
await sutProvider.Sut.PushNotificationStatusAsync(notification, notificationStatus);
|
||||||
|
|
||||||
|
await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotificationStatus,
|
||||||
|
expectedNotification,
|
||||||
$"(template:payload && organizationId:{notification.OrganizationId} && clientType:{clientType})");
|
$"(template:payload && organizationId:{notification.OrganizationId} && clientType:{clientType})");
|
||||||
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
||||||
.Received(0)
|
.Received(0)
|
||||||
@@ -137,7 +294,7 @@ public class NotificationHubPushNotificationServiceTests
|
|||||||
[Theory]
|
[Theory]
|
||||||
[BitAutoData([null])]
|
[BitAutoData([null])]
|
||||||
[BitAutoData(ClientType.All)]
|
[BitAutoData(ClientType.All)]
|
||||||
public async void SendPayloadToUserAsync_ClientTypeNullOrAll_SentToUser(ClientType? clientType,
|
public async Task SendPayloadToUserAsync_ClientTypeNullOrAll_SentToUser(ClientType? clientType,
|
||||||
SutProvider<NotificationHubPushNotificationService> sutProvider, Guid userId, PushType pushType, string payload,
|
SutProvider<NotificationHubPushNotificationService> sutProvider, Guid userId, PushType pushType, string payload,
|
||||||
string identifier)
|
string identifier)
|
||||||
{
|
{
|
||||||
@@ -156,7 +313,7 @@ public class NotificationHubPushNotificationServiceTests
|
|||||||
[BitAutoData(ClientType.Desktop)]
|
[BitAutoData(ClientType.Desktop)]
|
||||||
[BitAutoData(ClientType.Mobile)]
|
[BitAutoData(ClientType.Mobile)]
|
||||||
[BitAutoData(ClientType.Web)]
|
[BitAutoData(ClientType.Web)]
|
||||||
public async void SendPayloadToUserAsync_ClientTypeExplicit_SentToUserAndClientType(ClientType clientType,
|
public async Task SendPayloadToUserAsync_ClientTypeExplicit_SentToUserAndClientType(ClientType clientType,
|
||||||
SutProvider<NotificationHubPushNotificationService> sutProvider, Guid userId, PushType pushType, string payload,
|
SutProvider<NotificationHubPushNotificationService> sutProvider, Guid userId, PushType pushType, string payload,
|
||||||
string identifier)
|
string identifier)
|
||||||
{
|
{
|
||||||
@@ -173,7 +330,7 @@ public class NotificationHubPushNotificationServiceTests
|
|||||||
[Theory]
|
[Theory]
|
||||||
[BitAutoData([null])]
|
[BitAutoData([null])]
|
||||||
[BitAutoData(ClientType.All)]
|
[BitAutoData(ClientType.All)]
|
||||||
public async void SendPayloadToOrganizationAsync_ClientTypeNullOrAll_SentToOrganization(ClientType? clientType,
|
public async Task SendPayloadToOrganizationAsync_ClientTypeNullOrAll_SentToOrganization(ClientType? clientType,
|
||||||
SutProvider<NotificationHubPushNotificationService> sutProvider, Guid organizationId, PushType pushType,
|
SutProvider<NotificationHubPushNotificationService> sutProvider, Guid organizationId, PushType pushType,
|
||||||
string payload, string identifier)
|
string payload, string identifier)
|
||||||
{
|
{
|
||||||
@@ -192,7 +349,7 @@ public class NotificationHubPushNotificationServiceTests
|
|||||||
[BitAutoData(ClientType.Desktop)]
|
[BitAutoData(ClientType.Desktop)]
|
||||||
[BitAutoData(ClientType.Mobile)]
|
[BitAutoData(ClientType.Mobile)]
|
||||||
[BitAutoData(ClientType.Web)]
|
[BitAutoData(ClientType.Web)]
|
||||||
public async void SendPayloadToOrganizationAsync_ClientTypeExplicit_SentToOrganizationAndClientType(
|
public async Task SendPayloadToOrganizationAsync_ClientTypeExplicit_SentToOrganizationAndClientType(
|
||||||
ClientType clientType, SutProvider<NotificationHubPushNotificationService> sutProvider, Guid organizationId,
|
ClientType clientType, SutProvider<NotificationHubPushNotificationService> sutProvider, Guid organizationId,
|
||||||
PushType pushType, string payload, string identifier)
|
PushType pushType, string payload, string identifier)
|
||||||
{
|
{
|
||||||
@@ -206,7 +363,8 @@ public class NotificationHubPushNotificationServiceTests
|
|||||||
.UpsertAsync(Arg.Any<InstallationDeviceEntity>());
|
.UpsertAsync(Arg.Any<InstallationDeviceEntity>());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static NotificationPushNotification ToSyncNotificationPushNotification(Notification notification) =>
|
private static NotificationPushNotification ToNotificationPushNotification(Notification notification,
|
||||||
|
NotificationStatus? notificationStatus) =>
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
Id = notification.Id,
|
Id = notification.Id,
|
||||||
@@ -218,7 +376,9 @@ public class NotificationHubPushNotificationServiceTests
|
|||||||
Title = notification.Title,
|
Title = notification.Title,
|
||||||
Body = notification.Body,
|
Body = notification.Body,
|
||||||
CreationDate = notification.CreationDate,
|
CreationDate = notification.CreationDate,
|
||||||
RevisionDate = notification.RevisionDate
|
RevisionDate = notification.RevisionDate,
|
||||||
|
ReadDate = notificationStatus?.ReadDate,
|
||||||
|
DeletedDate = notificationStatus?.DeletedDate
|
||||||
};
|
};
|
||||||
|
|
||||||
private static async Task AssertSendTemplateNotificationAsync(
|
private static async Task AssertSendTemplateNotificationAsync(
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public class AzureQueuePushNotificationServiceTests
|
|||||||
[BitAutoData]
|
[BitAutoData]
|
||||||
[NotificationCustomize]
|
[NotificationCustomize]
|
||||||
[CurrentContextCustomize]
|
[CurrentContextCustomize]
|
||||||
public async void PushNotificationAsync_Notification_Sent(
|
public async Task PushNotificationAsync_Notification_Sent(
|
||||||
SutProvider<AzureQueuePushNotificationService> sutProvider, Notification notification, Guid deviceIdentifier,
|
SutProvider<AzureQueuePushNotificationService> sutProvider, Notification notification, Guid deviceIdentifier,
|
||||||
ICurrentContext currentContext)
|
ICurrentContext currentContext)
|
||||||
{
|
{
|
||||||
@@ -36,7 +36,30 @@ public class AzureQueuePushNotificationServiceTests
|
|||||||
|
|
||||||
await sutProvider.GetDependency<QueueClient>().Received(1)
|
await sutProvider.GetDependency<QueueClient>().Received(1)
|
||||||
.SendMessageAsync(Arg.Is<string>(message =>
|
.SendMessageAsync(Arg.Is<string>(message =>
|
||||||
MatchMessage(PushType.SyncNotification, message, new SyncNotificationEquals(notification),
|
MatchMessage(PushType.SyncNotification, message,
|
||||||
|
new NotificationPushNotificationEquals(notification, null),
|
||||||
|
deviceIdentifier.ToString())));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData]
|
||||||
|
[NotificationCustomize]
|
||||||
|
[NotificationStatusCustomize]
|
||||||
|
[CurrentContextCustomize]
|
||||||
|
public async Task PushNotificationStatusAsync_Notification_Sent(
|
||||||
|
SutProvider<AzureQueuePushNotificationService> sutProvider, Notification notification, Guid deviceIdentifier,
|
||||||
|
ICurrentContext currentContext, NotificationStatus notificationStatus)
|
||||||
|
{
|
||||||
|
currentContext.DeviceIdentifier.Returns(deviceIdentifier.ToString());
|
||||||
|
sutProvider.GetDependency<IHttpContextAccessor>().HttpContext!.RequestServices
|
||||||
|
.GetService(Arg.Any<Type>()).Returns(currentContext);
|
||||||
|
|
||||||
|
await sutProvider.Sut.PushNotificationStatusAsync(notification, notificationStatus);
|
||||||
|
|
||||||
|
await sutProvider.GetDependency<QueueClient>().Received(1)
|
||||||
|
.SendMessageAsync(Arg.Is<string>(message =>
|
||||||
|
MatchMessage(PushType.SyncNotificationStatus, message,
|
||||||
|
new NotificationPushNotificationEquals(notification, notificationStatus),
|
||||||
deviceIdentifier.ToString())));
|
deviceIdentifier.ToString())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,7 +73,8 @@ public class AzureQueuePushNotificationServiceTests
|
|||||||
pushNotificationData.ContextId == contextId;
|
pushNotificationData.ContextId == contextId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SyncNotificationEquals(Notification notification) : IEquatable<NotificationPushNotification>
|
private class NotificationPushNotificationEquals(Notification notification, NotificationStatus? notificationStatus)
|
||||||
|
: IEquatable<NotificationPushNotification>
|
||||||
{
|
{
|
||||||
public bool Equals(NotificationPushNotification? other)
|
public bool Equals(NotificationPushNotification? other)
|
||||||
{
|
{
|
||||||
@@ -66,7 +90,9 @@ public class AzureQueuePushNotificationServiceTests
|
|||||||
other.Title == notification.Title &&
|
other.Title == notification.Title &&
|
||||||
other.Body == notification.Body &&
|
other.Body == notification.Body &&
|
||||||
other.CreationDate == notification.CreationDate &&
|
other.CreationDate == notification.CreationDate &&
|
||||||
other.RevisionDate == notification.RevisionDate;
|
other.RevisionDate == notification.RevisionDate &&
|
||||||
|
other.ReadDate == notificationStatus?.ReadDate &&
|
||||||
|
other.DeletedDate == notificationStatus?.DeletedDate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,22 @@ public class MultiServicePushNotificationServiceTests
|
|||||||
.PushNotificationAsync(notification);
|
.PushNotificationAsync(notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData]
|
||||||
|
[NotificationCustomize]
|
||||||
|
[NotificationStatusCustomize]
|
||||||
|
public async Task PushNotificationStatusAsync_Notification_Sent(
|
||||||
|
SutProvider<MultiServicePushNotificationService> sutProvider, Notification notification,
|
||||||
|
NotificationStatus notificationStatus)
|
||||||
|
{
|
||||||
|
await sutProvider.Sut.PushNotificationStatusAsync(notification, notificationStatus);
|
||||||
|
|
||||||
|
await sutProvider.GetDependency<IEnumerable<IPushNotificationService>>()
|
||||||
|
.First()
|
||||||
|
.Received(1)
|
||||||
|
.PushNotificationStatusAsync(notification, notificationStatus);
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[BitAutoData([null, null])]
|
[BitAutoData([null, null])]
|
||||||
[BitAutoData(ClientType.All, null)]
|
[BitAutoData(ClientType.All, null)]
|
||||||
|
|||||||
Reference in New Issue
Block a user