Skip to content

Commit 5ab0aa1

Browse files
authored
Merge branch 'main' into update-send-openapi-to-work-for-sdk
2 parents 7a305f2 + b4de307 commit 5ab0aa1

69 files changed

Lines changed: 4104 additions & 873 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

bitwarden_license/src/Scim/Groups/PatchGroupCommand.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,22 @@ public class PatchGroupCommand : IPatchGroupCommand
2222
private readonly IUpdateGroupCommand _updateGroupCommand;
2323
private readonly ILogger<PatchGroupCommand> _logger;
2424
private readonly IOrganizationRepository _organizationRepository;
25+
private readonly TimeProvider _timeProvider;
2526

2627
public PatchGroupCommand(
2728
IGroupRepository groupRepository,
2829
IGroupService groupService,
2930
IUpdateGroupCommand updateGroupCommand,
3031
ILogger<PatchGroupCommand> logger,
31-
IOrganizationRepository organizationRepository)
32+
IOrganizationRepository organizationRepository,
33+
TimeProvider timeProvider)
3234
{
3335
_groupRepository = groupRepository;
3436
_groupService = groupService;
3537
_updateGroupCommand = updateGroupCommand;
3638
_logger = logger;
3739
_organizationRepository = organizationRepository;
40+
_timeProvider = timeProvider;
3841
}
3942

4043
public async Task PatchGroupAsync(Group group, ScimPatchModel model)
@@ -53,7 +56,7 @@ private async Task HandleOperationAsync(Group group, ScimPatchModel.OperationMod
5356
case PatchOps.Replace when operation.Path?.ToLowerInvariant() == PatchPaths.Members:
5457
{
5558
var ids = GetOperationValueIds(operation.Value);
56-
await _groupRepository.UpdateUsersAsync(group.Id, ids);
59+
await _groupRepository.UpdateUsersAsync(group.Id, ids, _timeProvider.GetUtcNow().UtcDateTime);
5760
break;
5861
}
5962

@@ -122,7 +125,7 @@ private async Task HandleOperationAsync(Group group, ScimPatchModel.OperationMod
122125
{
123126
orgUserIds.Remove(v);
124127
}
125-
await _groupRepository.UpdateUsersAsync(group.Id, orgUserIds);
128+
await _groupRepository.UpdateUsersAsync(group.Id, orgUserIds, _timeProvider.GetUtcNow().UtcDateTime);
126129
break;
127130
}
128131

@@ -146,7 +149,7 @@ private async Task AddMembersAsync(Group group, HashSet<Guid> usersToAdd)
146149
return;
147150
}
148151

149-
await _groupRepository.AddGroupUsersByIdAsync(group.Id, usersToAdd);
152+
await _groupRepository.AddGroupUsersByIdAsync(group.Id, usersToAdd, _timeProvider.GetUtcNow().UtcDateTime);
150153
}
151154

152155
private static HashSet<Guid> GetOperationValueIds(JsonElement objArray)

bitwarden_license/src/Scim/Groups/PostGroupCommand.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,6 @@ private async Task UpdateGroupMembersAsync(Group group, ScimGroupRequestModel mo
6262
return;
6363
}
6464

65-
await _groupRepository.UpdateUsersAsync(group.Id, memberIds);
65+
await _groupRepository.UpdateUsersAsync(group.Id, memberIds, group.RevisionDate);
6666
}
6767
}

bitwarden_license/src/Scim/Groups/PutGroupCommand.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,6 @@ private async Task UpdateGroupMembersAsync(Group group, ScimGroupRequestModel mo
5252
}
5353
}
5454

55-
await _groupRepository.UpdateUsersAsync(group.Id, memberIds);
55+
await _groupRepository.UpdateUsersAsync(group.Id, memberIds, group.RevisionDate);
5656
}
5757
}

bitwarden_license/test/Scim.Test/Groups/PatchGroupCommandTests.cs

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using Bit.Test.Common.AutoFixture;
1414
using Bit.Test.Common.AutoFixture.Attributes;
1515
using Microsoft.Extensions.Logging;
16+
using Microsoft.Extensions.Time.Testing;
1617
using NSubstitute;
1718
using Xunit;
1819

@@ -21,11 +22,14 @@ namespace Bit.Scim.Test.Groups;
2122
[SutProviderCustomize]
2223
public class PatchGroupCommandTests
2324
{
25+
private static readonly DateTime _expectedRevisionDate = DateTime.UtcNow.AddYears(1);
26+
2427
[Theory]
2528
[BitAutoData]
26-
public async Task PatchGroup_ReplaceListMembers_Success(SutProvider<PatchGroupCommand> sutProvider,
29+
public async Task PatchGroup_ReplaceListMembers_Success(
2730
Organization organization, Group group, IEnumerable<Guid> userIds)
2831
{
32+
var sutProvider = SetupSutProvider();
2933
group.OrganizationId = organization.Id;
3034

3135
var scimPatchModel = new ScimPatchModel
@@ -48,7 +52,8 @@ await sutProvider.GetDependency<IGroupRepository>().Received(1).UpdateUsersAsync
4852
group.Id,
4953
Arg.Is<IEnumerable<Guid>>(arg =>
5054
arg.Count() == userIds.Count() &&
51-
arg.ToHashSet().SetEquals(userIds)));
55+
arg.ToHashSet().SetEquals(userIds)),
56+
Arg.Is<DateTime>(d => d == _expectedRevisionDate));
5257
}
5358

5459
[Theory]
@@ -168,8 +173,9 @@ public async Task PatchGroup_ReplaceDisplayNameFromValueObject_MissingOrganizati
168173

169174
[Theory]
170175
[BitAutoData]
171-
public async Task PatchGroup_AddSingleMember_Success(SutProvider<PatchGroupCommand> sutProvider, Organization organization, Group group, ICollection<Guid> existingMembers, Guid userId)
176+
public async Task PatchGroup_AddSingleMember_Success(Organization organization, Group group, ICollection<Guid> existingMembers, Guid userId)
172177
{
178+
var sutProvider = SetupSutProvider();
173179
group.OrganizationId = organization.Id;
174180

175181
sutProvider.GetDependency<IGroupRepository>()
@@ -193,7 +199,8 @@ public async Task PatchGroup_AddSingleMember_Success(SutProvider<PatchGroupComma
193199

194200
await sutProvider.GetDependency<IGroupRepository>().Received(1).AddGroupUsersByIdAsync(
195201
group.Id,
196-
Arg.Is<IEnumerable<Guid>>(arg => arg.Single() == userId));
202+
Arg.Is<IEnumerable<Guid>>(arg => arg.Single() == userId),
203+
Arg.Is<DateTime>(d => d == _expectedRevisionDate));
197204
}
198205

199206
[Theory]
@@ -229,13 +236,14 @@ public async Task PatchGroup_AddSingleMember_ReturnsEarlyIfAlreadyInGroup(
229236

230237
await sutProvider.GetDependency<IGroupRepository>()
231238
.DidNotReceiveWithAnyArgs()
232-
.AddGroupUsersByIdAsync(default, default);
239+
.AddGroupUsersByIdAsync(default, default, default);
233240
}
234241

235242
[Theory]
236243
[BitAutoData]
237-
public async Task PatchGroup_AddListMembers_Success(SutProvider<PatchGroupCommand> sutProvider, Organization organization, Group group, ICollection<Guid> existingMembers, ICollection<Guid> userIds)
244+
public async Task PatchGroup_AddListMembers_Success(Organization organization, Group group, ICollection<Guid> existingMembers, ICollection<Guid> userIds)
238245
{
246+
var sutProvider = SetupSutProvider();
239247
group.OrganizationId = organization.Id;
240248

241249
sutProvider.GetDependency<IGroupRepository>()
@@ -262,15 +270,18 @@ await sutProvider.GetDependency<IGroupRepository>().Received(1).AddGroupUsersByI
262270
group.Id,
263271
Arg.Is<IEnumerable<Guid>>(arg =>
264272
arg.Count() == userIds.Count &&
265-
arg.ToHashSet().SetEquals(userIds)));
273+
arg.ToHashSet().SetEquals(userIds)),
274+
Arg.Is<DateTime>(d => d == _expectedRevisionDate));
266275
}
267276

268277
[Theory]
269278
[BitAutoData]
270279
public async Task PatchGroup_AddListMembers_IgnoresDuplicatesInRequest(
271-
SutProvider<PatchGroupCommand> sutProvider, Organization organization, Group group,
280+
Organization organization, Group group,
272281
ICollection<Guid> existingMembers)
273282
{
283+
var sutProvider = SetupSutProvider();
284+
274285
// Create 3 userIds
275286
var fixture = new Fixture { RepeatCount = 3 };
276287
var userIds = fixture.CreateMany<Guid>().ToList();
@@ -308,17 +319,19 @@ await sutProvider.GetDependency<IGroupRepository>().Received(1).AddGroupUsersByI
308319
group.Id,
309320
Arg.Is<IEnumerable<Guid>>(arg =>
310321
arg.Count() == 3 &&
311-
arg.ToHashSet().SetEquals(userIds)));
322+
arg.ToHashSet().SetEquals(userIds)),
323+
Arg.Is<DateTime>(d => d == _expectedRevisionDate));
312324
}
313325

314326
[Theory]
315327
[BitAutoData]
316328
public async Task PatchGroup_AddListMembers_SuccessIfOnlySomeUsersAreInGroup(
317-
SutProvider<PatchGroupCommand> sutProvider,
318329
Organization organization, Group group,
319330
ICollection<Guid> existingMembers,
320331
ICollection<Guid> userIds)
321332
{
333+
var sutProvider = SetupSutProvider();
334+
322335
// A user is already in the group, but some still need to be added
323336
userIds.Add(existingMembers.First());
324337

@@ -350,7 +363,8 @@ await sutProvider.GetDependency<IGroupRepository>()
350363
group.Id,
351364
Arg.Is<IEnumerable<Guid>>(arg =>
352365
arg.Count() == userIds.Count &&
353-
arg.ToHashSet().SetEquals(userIds)));
366+
arg.ToHashSet().SetEquals(userIds)),
367+
Arg.Is<DateTime>(d => d == _expectedRevisionDate));
354368
}
355369

356370
[Theory]
@@ -379,9 +393,10 @@ public async Task PatchGroup_RemoveSingleMember_Success(SutProvider<PatchGroupCo
379393

380394
[Theory]
381395
[BitAutoData]
382-
public async Task PatchGroup_RemoveListMembers_Success(SutProvider<PatchGroupCommand> sutProvider,
396+
public async Task PatchGroup_RemoveListMembers_Success(
383397
Organization organization, Group group, ICollection<Guid> existingMembers)
384398
{
399+
var sutProvider = SetupSutProvider();
385400
List<Guid> usersToRemove = [existingMembers.First(), existingMembers.Skip(1).First()];
386401
group.OrganizationId = organization.Id;
387402

@@ -412,7 +427,8 @@ await sutProvider.GetDependency<IGroupRepository>()
412427
group.Id,
413428
Arg.Is<IEnumerable<Guid>>(arg =>
414429
arg.Count() == expectedRemainingUsers.Count &&
415-
arg.ToHashSet().SetEquals(expectedRemainingUsers)));
430+
arg.ToHashSet().SetEquals(expectedRemainingUsers)),
431+
Arg.Is<DateTime>(d => d == _expectedRevisionDate));
416432
}
417433

418434
[Theory]
@@ -430,7 +446,7 @@ public async Task PatchGroup_InvalidOperation_Success(SutProvider<PatchGroupComm
430446
await sutProvider.Sut.PatchGroupAsync(group, scimPatchModel);
431447

432448
// Assert: no operation performed
433-
await sutProvider.GetDependency<IGroupRepository>().DidNotReceiveWithAnyArgs().UpdateUsersAsync(default, default);
449+
await sutProvider.GetDependency<IGroupRepository>().DidNotReceiveWithAnyArgs().UpdateUsersAsync(default, default, default);
434450
await sutProvider.GetDependency<IGroupRepository>().DidNotReceiveWithAnyArgs().GetManyUserIdsByIdAsync(default);
435451
await sutProvider.GetDependency<IUpdateGroupCommand>().DidNotReceiveWithAnyArgs().UpdateGroupAsync(default, default);
436452
await sutProvider.GetDependency<IGroupService>().DidNotReceiveWithAnyArgs().DeleteUserAsync(default, default);
@@ -454,9 +470,18 @@ public async Task PatchGroup_NoOperation_Success(
454470

455471
await sutProvider.Sut.PatchGroupAsync(group, scimPatchModel);
456472

457-
await sutProvider.GetDependency<IGroupRepository>().DidNotReceiveWithAnyArgs().UpdateUsersAsync(default, default);
473+
await sutProvider.GetDependency<IGroupRepository>().DidNotReceiveWithAnyArgs().UpdateUsersAsync(default, default, default);
458474
await sutProvider.GetDependency<IGroupRepository>().DidNotReceiveWithAnyArgs().GetManyUserIdsByIdAsync(default);
459475
await sutProvider.GetDependency<IUpdateGroupCommand>().DidNotReceiveWithAnyArgs().UpdateGroupAsync(default, default);
460476
await sutProvider.GetDependency<IGroupService>().DidNotReceiveWithAnyArgs().DeleteUserAsync(default, default);
461477
}
478+
479+
private static SutProvider<PatchGroupCommand> SetupSutProvider()
480+
{
481+
var sutProvider = new SutProvider<PatchGroupCommand>()
482+
.WithFakeTimeProvider()
483+
.Create();
484+
sutProvider.GetDependency<FakeTimeProvider>().SetUtcNow(_expectedRevisionDate);
485+
return sutProvider;
486+
}
462487
}

bitwarden_license/test/Scim.Test/Groups/PostGroupCommandTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public async Task PostGroup_Success(SutProvider<PostGroupCommand> sutProvider, s
4343
var group = await sutProvider.Sut.PostGroupAsync(organization, scimGroupRequestModel);
4444

4545
await sutProvider.GetDependency<ICreateGroupCommand>().Received(1).CreateGroupAsync(group, organization, EventSystemUser.SCIM, null);
46-
await sutProvider.GetDependency<IGroupRepository>().DidNotReceiveWithAnyArgs().UpdateUsersAsync(default, default);
46+
await sutProvider.GetDependency<IGroupRepository>().DidNotReceiveWithAnyArgs().UpdateUsersAsync(default, default, default);
4747

4848
AssertHelper.AssertPropertyEqual(expectedResult, group, "Id", "CreationDate", "RevisionDate");
4949
}
@@ -74,7 +74,7 @@ public async Task PostGroup_WithMembers_Success(SutProvider<PostGroupCommand> su
7474
var group = await sutProvider.Sut.PostGroupAsync(organization, scimGroupRequestModel);
7575

7676
await sutProvider.GetDependency<ICreateGroupCommand>().Received(1).CreateGroupAsync(group, organization, EventSystemUser.SCIM, null);
77-
await sutProvider.GetDependency<IGroupRepository>().Received(1).UpdateUsersAsync(Arg.Any<Guid>(), Arg.Is<IEnumerable<Guid>>(arg => arg.All(id => membersUserIds.Contains(id))));
77+
await sutProvider.GetDependency<IGroupRepository>().Received(1).UpdateUsersAsync(group.Id, Arg.Is<IEnumerable<Guid>>(arg => arg.All(id => membersUserIds.Contains(id))), group.RevisionDate);
7878

7979
AssertHelper.AssertPropertyEqual(expectedResult, group, "Id", "CreationDate", "RevisionDate");
8080
}

bitwarden_license/test/Scim.Test/Groups/PutGroupCommandTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public async Task PutGroup_Success(SutProvider<PutGroupCommand> sutProvider, Org
4747
Assert.Equal(displayName, group.Name);
4848

4949
await sutProvider.GetDependency<IUpdateGroupCommand>().Received(1).UpdateGroupAsync(group, organization, EventSystemUser.SCIM);
50-
await sutProvider.GetDependency<IGroupRepository>().DidNotReceiveWithAnyArgs().UpdateUsersAsync(default, default);
50+
await sutProvider.GetDependency<IGroupRepository>().DidNotReceiveWithAnyArgs().UpdateUsersAsync(default, default, default);
5151
}
5252

5353
[Theory]
@@ -81,7 +81,7 @@ public async Task PutGroup_ChangeMembers_Success(SutProvider<PutGroupCommand> su
8181
Assert.Equal(displayName, group.Name);
8282

8383
await sutProvider.GetDependency<IUpdateGroupCommand>().Received(1).UpdateGroupAsync(group, organization, EventSystemUser.SCIM);
84-
await sutProvider.GetDependency<IGroupRepository>().Received(1).UpdateUsersAsync(group.Id, Arg.Is<IEnumerable<Guid>>(arg => arg.All(id => membersUserIds.Contains(id))));
84+
await sutProvider.GetDependency<IGroupRepository>().Received(1).UpdateUsersAsync(group.Id, Arg.Is<IEnumerable<Guid>>(arg => arg.All(id => membersUserIds.Contains(id))), group.RevisionDate);
8585
}
8686

8787
[Theory]

src/Api/AdminConsole/Public/Controllers/GroupsController.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,22 @@ public class GroupsController : Controller
2323
private readonly ICurrentContext _currentContext;
2424
private readonly ICreateGroupCommand _createGroupCommand;
2525
private readonly IUpdateGroupCommand _updateGroupCommand;
26+
private readonly TimeProvider _timeProvider;
2627

2728
public GroupsController(
2829
IGroupRepository groupRepository,
2930
IOrganizationRepository organizationRepository,
3031
ICurrentContext currentContext,
3132
ICreateGroupCommand createGroupCommand,
32-
IUpdateGroupCommand updateGroupCommand)
33+
IUpdateGroupCommand updateGroupCommand,
34+
TimeProvider timeProvider)
3335
{
3436
_groupRepository = groupRepository;
3537
_organizationRepository = organizationRepository;
3638
_currentContext = currentContext;
3739
_createGroupCommand = createGroupCommand;
3840
_updateGroupCommand = updateGroupCommand;
41+
_timeProvider = timeProvider;
3942
}
4043

4144
/// <summary>
@@ -168,7 +171,7 @@ public async Task<IActionResult> PutMemberIds(Guid id, [FromBody] UpdateMemberId
168171
{
169172
return new NotFoundResult();
170173
}
171-
await _groupRepository.UpdateUsersAsync(existingGroup.Id, model.MemberIds);
174+
await _groupRepository.UpdateUsersAsync(existingGroup.Id, model.MemberIds, _timeProvider.GetUtcNow().UtcDateTime);
172175
return new OkResult();
173176
}
174177

src/Billing/Services/IStripeWebhookHandler.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,4 @@ public interface ICouponDeletedHandler : IStripeWebhookHandler;
7777
/// Defines the contract for handling Stripe checkout session completed events.
7878
/// </summary>
7979
public interface ICheckoutSessionCompletedHandler : IStripeWebhookHandler;
80+

src/Core/AdminConsole/OrganizationFeatures/Groups/CreateGroupCommand.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,19 @@ public class CreateGroupCommand : ICreateGroupCommand
1717
private readonly IEventService _eventService;
1818
private readonly IGroupRepository _groupRepository;
1919
private readonly IOrganizationUserRepository _organizationUserRepository;
20+
private readonly TimeProvider _timeProvider;
2021

2122
public CreateGroupCommand(
2223
IEventService eventService,
2324
IGroupRepository groupRepository,
24-
IOrganizationUserRepository organizationUserRepository
25+
IOrganizationUserRepository organizationUserRepository,
26+
TimeProvider timeProvider
2527
)
2628
{
2729
_eventService = eventService;
2830
_groupRepository = groupRepository;
2931
_organizationUserRepository = organizationUserRepository;
32+
_timeProvider = timeProvider;
3033
}
3134

3235
public async Task CreateGroupAsync(Group group, Organization organization,
@@ -61,7 +64,8 @@ public async Task CreateGroupAsync(Group group, Organization organization, Event
6164

6265
private async Task GroupRepositoryCreateGroupAsync(Group group, Organization organization, IEnumerable<CollectionAccessSelection> collections = null)
6366
{
64-
group.CreationDate = group.RevisionDate = DateTime.UtcNow;
67+
var now = _timeProvider.GetUtcNow().UtcDateTime;
68+
group.CreationDate = group.RevisionDate = now;
6569

6670
if (collections == null)
6771
{
@@ -78,10 +82,10 @@ private async Task GroupRepositoryUpdateUsersAsync(Group group, IEnumerable<Guid
7882
{
7983
var usersToAddToGroup = userIds as Guid[] ?? userIds.ToArray();
8084

81-
await _groupRepository.UpdateUsersAsync(group.Id, usersToAddToGroup);
85+
await _groupRepository.UpdateUsersAsync(group.Id, usersToAddToGroup, group.RevisionDate);
8286

8387
var users = await _organizationUserRepository.GetManyAsync(usersToAddToGroup);
84-
var eventDate = DateTime.UtcNow;
88+
var eventDate = group.RevisionDate;
8589

8690
if (systemUser.HasValue)
8791
{

0 commit comments

Comments
 (0)