Skip to content

Commit ff7ebcd

Browse files
handle feature flag on/off logic
1 parent c1e2ee9 commit ff7ebcd

5 files changed

Lines changed: 46 additions & 7 deletions

File tree

src/Core/Platform/Push/Engines/RelayPushEngine.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ public RelayPushEngine(
4343
public async Task PushAsync<T>(PushNotification<T> pushNotification)
4444
where T : class
4545
{
46+
if (pushNotification.NonMobileOnly == true)
47+
{
48+
return;
49+
}
50+
4651
var deviceIdentifier = _httpContextAccessor.HttpContext
4752
?.RequestServices.GetService<ICurrentContext>()
4853
?.DeviceIdentifier;

src/Core/Platform/Push/NotificationHub/NotificationHubPushEngine.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ private string BuildTag(string tag, string? identifier, ClientType? clientType)
7070
public async Task PushAsync<T>(PushNotification<T> pushNotification)
7171
where T : class
7272
{
73+
if (pushNotification.NonMobileOnly == true)
74+
{
75+
return;
76+
}
77+
7378
var initialTag = pushNotification.Target switch
7479
{
7580
NotificationTarget.User => $"template:payload_userId:{pushNotification.TargetId}",

src/Core/Platform/Push/PushNotification.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,17 @@ public record PushNotification<T>
1313
/// <summary>
1414
/// The <see cref="PushType"/> to be associated with the notification. This is used to route
1515
/// the notification to the correct handler on the client side. Be sure to use the correct payload
16-
/// type for the associated <see cref="PushType"/>.
16+
/// type for the associated <see cref="PushType"/>.
1717
/// </summary>
1818
public required PushType Type { get; init; }
1919

2020
/// <summary>
2121
/// The target entity type for the notification.
2222
/// </summary>
2323
/// <remarks>
24-
/// When the target type is <see cref="NotificationTarget.User"/> the <see cref="TargetId"/>
24+
/// When the target type is <see cref="NotificationTarget.User"/> the <see cref="TargetId"/>
2525
/// property is expected to be a users ID. When it is <see cref="NotificationTarget.Organization"/>
26-
/// it should be an organizations id. When it is a <see cref="NotificationTarget.Installation"/>
26+
/// it should be an organizations id. When it is a <see cref="NotificationTarget.Installation"/>
2727
/// it should be an installation id.
2828
/// </remarks>
2929
public required NotificationTarget Target { get; init; }
@@ -45,11 +45,17 @@ public record PushNotification<T>
4545
public required bool ExcludeCurrentContext { get; init; }
4646

4747
/// <summary>
48-
/// The type of clients the notification should be sent to, if <see langword="null"/> then
48+
/// The type of clients the notification should be sent to, if <see langword="null"/> then
4949
/// <see cref="ClientType.All"/> is inferred.
5050
/// </summary>
5151
public ClientType? ClientType { get; init; }
5252

53+
54+
/// <summary>
55+
/// When true, only non-mobile engines (SignalR/web/desktop) will deliver this notification. When null or false, all engines process it.
56+
/// </summary>
57+
public bool? NonMobileOnly { get; init; }
58+
5359
internal Guid? GetTargetWhen(NotificationTarget notificationTarget)
5460
{
5561
return Target == notificationTarget ? TargetId : null;

src/Core/Vault/Services/Implementations/CipherSyncPushService.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,23 @@ private async Task PushCipherAsync(Cipher cipher, PushType pushType, IEnumerable
4242
{
4343
if (!_featureService.IsEnabled(FeatureFlagKeys.OrgCipherPushFanout))
4444
{
45+
// Device registrations in Notification Hub and Relay are not collection-aware, so we cannot
46+
// safely fan out to individual users on those mobile engines. Restrict to the non-mobile
47+
// (SignalR) path, which routes by organizationId on the receiving end.
48+
await _pushNotificationService.PushAsync(new PushNotification<SyncCipherPushNotification>
49+
{
50+
Type = pushType,
51+
Target = NotificationTarget.Organization,
52+
TargetId = cipher.OrganizationId.Value,
53+
Payload = new SyncCipherPushNotification
54+
{
55+
Id = cipher.Id,
56+
OrganizationId = cipher.OrganizationId,
57+
RevisionDate = cipher.RevisionDate,
58+
},
59+
ExcludeCurrentContext = true,
60+
NonMobileOnly = true,
61+
});
4562
return;
4663
}
4764

test/Core.Test/Vault/Services/CipherSyncPushServiceTests.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ await sutProvider.GetDependency<IPushNotificationService>()
8383
}
8484

8585
[Theory, BitAutoData]
86-
public async Task PushSyncCipherCreateAsync_OrgCipher_FlagOff_NoPush(
86+
public async Task PushSyncCipherCreateAsync_OrgCipher_FlagOff_SendsNonMobileOrgBroadcast(
8787
SutProvider<CipherSyncPushService> sutProvider, Cipher cipher, Guid collectionId)
8888
{
8989
cipher.OrganizationId = Guid.NewGuid();
@@ -96,8 +96,14 @@ public async Task PushSyncCipherCreateAsync_OrgCipher_FlagOff_NoPush(
9696
await sutProvider.Sut.PushSyncCipherCreateAsync(cipher, [collectionId]);
9797

9898
await sutProvider.GetDependency<IPushNotificationService>()
99-
.DidNotReceiveWithAnyArgs()
100-
.PushAsync(Arg.Any<PushNotification<SyncCipherPushNotification>>());
99+
.Received(1)
100+
.PushAsync(Arg.Is<PushNotification<SyncCipherPushNotification>>(n =>
101+
n.Type == PushType.SyncCipherCreate &&
102+
n.Target == NotificationTarget.Organization &&
103+
n.TargetId == cipher.OrganizationId!.Value &&
104+
n.NonMobileOnly == true &&
105+
n.Payload.Id == cipher.Id &&
106+
n.Payload.OrganizationId == cipher.OrganizationId));
101107
}
102108

103109
[Theory, BitAutoData]

0 commit comments

Comments
 (0)