From 3511ece8990a73984da6dc855b5bf9d379d95aad Mon Sep 17 00:00:00 2001 From: Shane Melton Date: Thu, 18 Dec 2025 10:20:46 -0800 Subject: [PATCH] [PM-28746] Add support for Organization_ItemOrganization_Accepted/Declined event types (#6747) --- src/Events/Controllers/CollectController.cs | 24 +++++++++++++- .../Controllers/CollectControllerTests.cs | 33 ++++++++++++++++++- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src/Events/Controllers/CollectController.cs b/src/Events/Controllers/CollectController.cs index bae1575134..3902522665 100644 --- a/src/Events/Controllers/CollectController.cs +++ b/src/Events/Controllers/CollectController.cs @@ -21,17 +21,21 @@ public class CollectController : Controller private readonly IEventService _eventService; private readonly ICipherRepository _cipherRepository; private readonly IOrganizationRepository _organizationRepository; + private readonly IOrganizationUserRepository _organizationUserRepository; public CollectController( ICurrentContext currentContext, IEventService eventService, ICipherRepository cipherRepository, - IOrganizationRepository organizationRepository) + IOrganizationRepository organizationRepository, + IOrganizationUserRepository organizationUserRepository + ) { _currentContext = currentContext; _eventService = eventService; _cipherRepository = cipherRepository; _organizationRepository = organizationRepository; + _organizationUserRepository = organizationUserRepository; } [HttpPost] @@ -54,6 +58,24 @@ public class CollectController : Controller await _eventService.LogUserEventAsync(_currentContext.UserId.Value, eventModel.Type, eventModel.Date); break; + case EventType.Organization_ItemOrganization_Accepted: + case EventType.Organization_ItemOrganization_Declined: + if (!eventModel.OrganizationId.HasValue || !_currentContext.UserId.HasValue) + { + continue; + } + + var orgUser = await _organizationUserRepository.GetByOrganizationAsync(eventModel.OrganizationId.Value, _currentContext.UserId.Value); + + if (orgUser == null) + { + continue; + } + + await _eventService.LogOrganizationUserEventAsync(orgUser, eventModel.Type, eventModel.Date); + + continue; + // Cipher events case EventType.Cipher_ClientAutofilled: case EventType.Cipher_ClientCopiedHiddenField: diff --git a/test/Events.Test/Controllers/CollectControllerTests.cs b/test/Events.Test/Controllers/CollectControllerTests.cs index 325442d50e..b6fa018623 100644 --- a/test/Events.Test/Controllers/CollectControllerTests.cs +++ b/test/Events.Test/Controllers/CollectControllerTests.cs @@ -1,6 +1,7 @@ using AutoFixture.Xunit2; using Bit.Core.AdminConsole.Entities; using Bit.Core.Context; +using Bit.Core.Entities; using Bit.Core.Enums; using Bit.Core.Repositories; using Bit.Core.Services; @@ -9,6 +10,7 @@ using Bit.Core.Vault.Models.Data; using Bit.Core.Vault.Repositories; using Bit.Events.Controllers; using Bit.Events.Models; +using Bit.Test.Common.AutoFixture.Attributes; using Microsoft.AspNetCore.Mvc; using NSubstitute; @@ -21,6 +23,7 @@ public class CollectControllerTests private readonly IEventService _eventService; private readonly ICipherRepository _cipherRepository; private readonly IOrganizationRepository _organizationRepository; + private readonly IOrganizationUserRepository _organizationUserRepository; public CollectControllerTests() { @@ -28,12 +31,14 @@ public class CollectControllerTests _eventService = Substitute.For(); _cipherRepository = Substitute.For(); _organizationRepository = Substitute.For(); + _organizationUserRepository = Substitute.For(); _sut = new CollectController( _currentContext, _eventService, _cipherRepository, - _organizationRepository + _organizationRepository, + _organizationUserRepository ); } @@ -74,6 +79,32 @@ public class CollectControllerTests await _eventService.Received(1).LogUserEventAsync(userId, EventType.User_ClientExportedVault, eventDate); } + [Theory] + [BitAutoData(EventType.Organization_ItemOrganization_Accepted)] + [BitAutoData(EventType.Organization_ItemOrganization_Declined)] + public async Task Post_Organization_ItemOrganization_LogsOrganizationUserEvent( + EventType type, Guid userId, Guid orgId, OrganizationUser orgUser) + { + _currentContext.UserId.Returns(userId); + orgUser.OrganizationId = orgId; + _organizationUserRepository.GetByOrganizationAsync(orgId, userId).Returns(orgUser); + var eventDate = DateTime.UtcNow; + var events = new List + { + new EventModel + { + Type = type, + OrganizationId = orgId, + Date = eventDate + } + }; + + var result = await _sut.Post(events); + + Assert.IsType(result); + await _eventService.Received(1).LogOrganizationUserEventAsync(orgUser, type, eventDate); + } + [Theory] [AutoData] public async Task Post_CipherAutofilled_WithValidCipher_LogsCipherEvent(Guid userId, Guid cipherId, CipherDetails cipherDetails)