diff --git a/src/Billing/Controllers/FreshdeskController.cs b/src/Billing/Controllers/FreshdeskController.cs
index 4bf6b7bad4..1fb0fb7ac7 100644
--- a/src/Billing/Controllers/FreshdeskController.cs
+++ b/src/Billing/Controllers/FreshdeskController.cs
@@ -63,6 +63,12 @@ public class FreshdeskController : Controller
note += $"
Region: {_billingSettings.FreshDesk.Region}";
var customFields = new Dictionary();
var user = await _userRepository.GetByEmailAsync(ticketContactEmail);
+ if (user == null)
+ {
+ note += $"No user found: {ticketContactEmail}";
+ await CreateNote(ticketId, note);
+ }
+
if (user != null)
{
var userLink = $"{_globalSettings.BaseServiceUri.Admin}/users/edit/{user.Id}";
@@ -121,18 +127,7 @@ public class FreshdeskController : Controller
Content = JsonContent.Create(updateBody),
};
await CallFreshdeskApiAsync(updateRequest);
-
- var noteBody = new Dictionary
- {
- { "body", $"" },
- { "private", true }
- };
- var noteRequest = new HttpRequestMessage(HttpMethod.Post,
- string.Format("https://bitwarden.freshdesk.com/api/v2/tickets/{0}/notes", ticketId))
- {
- Content = JsonContent.Create(noteBody),
- };
- await CallFreshdeskApiAsync(noteRequest);
+ await CreateNote(ticketId, note);
}
return new OkResult();
@@ -208,6 +203,21 @@ public class FreshdeskController : Controller
return true;
}
+ private async Task CreateNote(string ticketId, string note)
+ {
+ var noteBody = new Dictionary
+ {
+ { "body", $"" },
+ { "private", true }
+ };
+ var noteRequest = new HttpRequestMessage(HttpMethod.Post,
+ string.Format("https://bitwarden.freshdesk.com/api/v2/tickets/{0}/notes", ticketId))
+ {
+ Content = JsonContent.Create(noteBody),
+ };
+ await CallFreshdeskApiAsync(noteRequest);
+ }
+
private async Task AddAnswerNoteToTicketAsync(string note, string ticketId)
{
// if there is no content, then we don't need to add a note
diff --git a/test/Billing.Test/Controllers/FreshdeskControllerTests.cs b/test/Billing.Test/Controllers/FreshdeskControllerTests.cs
index 26ce310b9c..90f8a09ea0 100644
--- a/test/Billing.Test/Controllers/FreshdeskControllerTests.cs
+++ b/test/Billing.Test/Controllers/FreshdeskControllerTests.cs
@@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using NSubstitute;
+using NSubstitute.ReceivedExtensions;
using Xunit;
namespace Bit.Billing.Test.Controllers;
@@ -71,6 +72,41 @@ public class FreshdeskControllerTests
_ = mockHttpMessageHandler.Received(1).Send(Arg.Is(m => m.Method == HttpMethod.Post && m.RequestUri.ToString().EndsWith($"{model.TicketId}/notes")), Arg.Any());
}
+ [Theory]
+ [BitAutoData(WebhookKey)]
+ public async Task PostWebhook_add_note_when_user_is_invalid(
+ string freshdeskWebhookKey, FreshdeskWebhookModel model,
+ SutProvider sutProvider)
+ {
+ // Arrange - for an invalid user
+ model.TicketContactEmail = "invalid@user";
+ sutProvider.GetDependency().GetByEmailAsync(model.TicketContactEmail).Returns((User)null);
+ sutProvider.GetDependency>().Value.FreshDesk.WebhookKey.Returns(WebhookKey);
+
+ var mockHttpMessageHandler = Substitute.ForPartsOf();
+ var mockResponse = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
+ mockHttpMessageHandler.Send(Arg.Any(), Arg.Any())
+ .Returns(mockResponse);
+ var httpClient = new HttpClient(mockHttpMessageHandler);
+ sutProvider.GetDependency().CreateClient("FreshdeskApi").Returns(httpClient);
+
+ // Act
+ var response = await sutProvider.Sut.PostWebhook(freshdeskWebhookKey, model);
+
+ // Assert
+ var statusCodeResult = Assert.IsAssignableFrom(response);
+ Assert.Equal(StatusCodes.Status200OK, statusCodeResult.StatusCode);
+
+ await mockHttpMessageHandler
+ .Received(1).Send(
+ Arg.Is(
+ m => m.Method == HttpMethod.Post
+ && m.RequestUri.ToString().EndsWith($"{model.TicketId}/notes")
+ && m.Content.ReadAsStringAsync().Result.Contains("No user found")),
+ Arg.Any());
+ }
+
+
[Theory]
[BitAutoData((string)null, null)]
[BitAutoData((string)null)]