using Bit.Core.Dirt.Models.Data.EventIntegrations; namespace Bit.Core.Dirt.Services.Implementations; public class SlackIntegrationHandler( ISlackService slackService) : IntegrationHandlerBase { public override async Task HandleAsync(IntegrationMessage message) { var slackResponse = await slackService.SendSlackMessageByChannelIdAsync( message.Configuration.Token, message.RenderedTemplate, message.Configuration.ChannelId ); if (slackResponse is null) { return IntegrationHandlerResult.Fail( message, IntegrationFailureCategory.TransientError, "Slack response was null" ); } if (slackResponse.Ok) { return IntegrationHandlerResult.Succeed(message); } var category = ClassifySlackError(slackResponse.Error); return IntegrationHandlerResult.Fail( message, category, slackResponse.Error ); } /// /// Classifies a Slack API error code string as an to drive /// retry behavior and operator-facing failure reporting. /// /// /// /// Slack responses commonly return an error string when ok is false. This method maps /// known Slack error codes to failure categories. /// /// /// Any unrecognized error codes default to to avoid /// incorrectly marking new/unknown Slack failures as non-retryable. /// /// /// The Slack error code string (e.g. invalid_auth, rate_limited). /// The corresponding . private static IntegrationFailureCategory ClassifySlackError(string error) { return error switch { "invalid_auth" => IntegrationFailureCategory.AuthenticationFailed, "access_denied" => IntegrationFailureCategory.AuthenticationFailed, "token_expired" => IntegrationFailureCategory.AuthenticationFailed, "token_revoked" => IntegrationFailureCategory.AuthenticationFailed, "account_inactive" => IntegrationFailureCategory.AuthenticationFailed, "not_authed" => IntegrationFailureCategory.AuthenticationFailed, "channel_not_found" => IntegrationFailureCategory.ConfigurationError, "is_archived" => IntegrationFailureCategory.ConfigurationError, "rate_limited" => IntegrationFailureCategory.RateLimited, "ratelimited" => IntegrationFailureCategory.RateLimited, "message_limit_exceeded" => IntegrationFailureCategory.RateLimited, "internal_error" => IntegrationFailureCategory.TransientError, "service_unavailable" => IntegrationFailureCategory.ServiceUnavailable, "fatal_error" => IntegrationFailureCategory.ServiceUnavailable, _ => IntegrationFailureCategory.TransientError }; } }