mirror of
https://github.com/bitwarden/server
synced 2025-12-30 23:23:37 +00:00
Add template properties for Datadog (#6528)
* Add template properites for Datadog * Add test and implementation for including User and ActingUser when only the Type is referenced * Refactored database calls to fetch the user details in a single DB call * Refactor to use a dedicated stored procedure for Dapper * Remove TOP 1 from stored procedure * Accept Claude's optimization of SingleOrDefaultAsync to unify Dapper/EF Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> * Revert earlier change and add TOP 1 back into stored procedure * Change go to GO * Revert back to version that assumes uniqueness, remove TOP 1 --------- Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
using System.Text.Json;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||
|
||||
namespace Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
|
||||
@@ -36,13 +36,18 @@ public class IntegrationTemplateContext(EventMessage eventMessage)
|
||||
public string DateIso8601 => Date.ToString("o");
|
||||
public string EventMessage => JsonSerializer.Serialize(Event);
|
||||
|
||||
public User? User { get; set; }
|
||||
public OrganizationUserUserDetails? User { get; set; }
|
||||
public string? UserName => User?.Name;
|
||||
public string? UserEmail => User?.Email;
|
||||
public OrganizationUserType? UserType => User?.Type;
|
||||
|
||||
public User? ActingUser { get; set; }
|
||||
public OrganizationUserUserDetails? ActingUser { get; set; }
|
||||
public string? ActingUserName => ActingUser?.Name;
|
||||
public string? ActingUserEmail => ActingUser?.Email;
|
||||
public OrganizationUserType? ActingUserType => ActingUser?.Type;
|
||||
|
||||
public Group? Group { get; set; }
|
||||
public string? GroupName => Group?.Name;
|
||||
|
||||
public Organization? Organization { get; set; }
|
||||
public string? OrganizationName => Organization?.DisplayName();
|
||||
|
||||
@@ -97,4 +97,15 @@ public interface IOrganizationUserRepository : IRepository<OrganizationUser, Gui
|
||||
/// <param name="organizationUserToConfirm">Accepted OrganizationUser to confirm</param>
|
||||
/// <returns>True, if the user was updated. False, if not performed.</returns>
|
||||
Task<bool> ConfirmOrganizationUserAsync(AcceptedOrganizationUserToConfirm organizationUserToConfirm);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the OrganizationUserUserDetails if found.
|
||||
/// </summary>
|
||||
/// <param name="organizationId">The id of the organization</param>
|
||||
/// <param name="userId">The id of the User to fetch</param>
|
||||
/// <returns>OrganizationUserUserDetails of the specified user or null if not found</returns>
|
||||
/// <remarks>
|
||||
/// Similar to GetByOrganizationAsync, but returns the user details.
|
||||
/// </remarks>
|
||||
Task<OrganizationUserUserDetails?> GetDetailsByOrganizationIdUserIdAsync(Guid organizationId, Guid userId);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Text.Json;
|
||||
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.AdminConsole.Utilities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Data;
|
||||
@@ -13,8 +14,9 @@ public class EventIntegrationHandler<T>(
|
||||
IEventIntegrationPublisher eventIntegrationPublisher,
|
||||
IIntegrationFilterService integrationFilterService,
|
||||
IIntegrationConfigurationDetailsCache configurationCache,
|
||||
IUserRepository userRepository,
|
||||
IGroupRepository groupRepository,
|
||||
IOrganizationRepository organizationRepository,
|
||||
IOrganizationUserRepository organizationUserRepository,
|
||||
ILogger<EventIntegrationHandler<T>> logger)
|
||||
: IEventMessageHandler
|
||||
{
|
||||
@@ -89,19 +91,35 @@ public class EventIntegrationHandler<T>(
|
||||
{
|
||||
var context = new IntegrationTemplateContext(eventMessage);
|
||||
|
||||
if (IntegrationTemplateProcessor.TemplateRequiresGroup(template) && eventMessage.GroupId.HasValue)
|
||||
{
|
||||
context.Group = await groupRepository.GetByIdAsync(eventMessage.GroupId.Value);
|
||||
}
|
||||
|
||||
if (eventMessage.OrganizationId is not Guid organizationId)
|
||||
{
|
||||
return context;
|
||||
}
|
||||
|
||||
if (IntegrationTemplateProcessor.TemplateRequiresUser(template) && eventMessage.UserId.HasValue)
|
||||
{
|
||||
context.User = await userRepository.GetByIdAsync(eventMessage.UserId.Value);
|
||||
context.User = await organizationUserRepository.GetDetailsByOrganizationIdUserIdAsync(
|
||||
organizationId: organizationId,
|
||||
userId: eventMessage.UserId.Value
|
||||
);
|
||||
}
|
||||
|
||||
if (IntegrationTemplateProcessor.TemplateRequiresActingUser(template) && eventMessage.ActingUserId.HasValue)
|
||||
{
|
||||
context.ActingUser = await userRepository.GetByIdAsync(eventMessage.ActingUserId.Value);
|
||||
context.ActingUser = await organizationUserRepository.GetDetailsByOrganizationIdUserIdAsync(
|
||||
organizationId: organizationId,
|
||||
userId: eventMessage.ActingUserId.Value
|
||||
);
|
||||
}
|
||||
|
||||
if (IntegrationTemplateProcessor.TemplateRequiresOrganization(template) && eventMessage.OrganizationId.HasValue)
|
||||
if (IntegrationTemplateProcessor.TemplateRequiresOrganization(template))
|
||||
{
|
||||
context.Organization = await organizationRepository.GetByIdAsync(eventMessage.OrganizationId.Value);
|
||||
context.Organization = await organizationRepository.GetByIdAsync(organizationId);
|
||||
}
|
||||
|
||||
return context;
|
||||
|
||||
@@ -26,7 +26,7 @@ public static partial class IntegrationTemplateProcessor
|
||||
return match.Value; // Return unknown keys as keys - i.e. #Key#
|
||||
}
|
||||
|
||||
return property?.GetValue(values)?.ToString() ?? "";
|
||||
return property.GetValue(values)?.ToString() ?? string.Empty;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -38,7 +38,8 @@ public static partial class IntegrationTemplateProcessor
|
||||
}
|
||||
|
||||
return template.Contains("#UserName#", StringComparison.Ordinal)
|
||||
|| template.Contains("#UserEmail#", StringComparison.Ordinal);
|
||||
|| template.Contains("#UserEmail#", StringComparison.Ordinal)
|
||||
|| template.Contains("#UserType#", StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public static bool TemplateRequiresActingUser(string template)
|
||||
@@ -49,7 +50,18 @@ public static partial class IntegrationTemplateProcessor
|
||||
}
|
||||
|
||||
return template.Contains("#ActingUserName#", StringComparison.Ordinal)
|
||||
|| template.Contains("#ActingUserEmail#", StringComparison.Ordinal);
|
||||
|| template.Contains("#ActingUserEmail#", StringComparison.Ordinal)
|
||||
|| template.Contains("#ActingUserType#", StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public static bool TemplateRequiresGroup(string template)
|
||||
{
|
||||
if (string.IsNullOrEmpty(template))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return template.Contains("#GroupName#", StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public static bool TemplateRequiresOrganization(string template)
|
||||
|
||||
Reference in New Issue
Block a user