- introduced new migration to add Cursor column to AccountMetadata. - updated AppDbContext model snapshot to reflect changes in the database schema. - implemented async queue processing with ChannelAsyncQueue and AsyncQueueHostedService. - created Plaid transaction handlers for added, modified, and removed transactions. - developed PlaidTransactionService and PlaidTransactionSyncer for syncing transactions. - added SyncUpdatesProcessor to handle sync updates from Plaid. - updated tests to accommodate changes in institution and account metadata handling.
65 lines
1.9 KiB
C#
65 lines
1.9 KiB
C#
using Going.Plaid;
|
|
using Going.Plaid.Entity;
|
|
|
|
namespace FiscalOS.API.Transactions.FireWebhook;
|
|
|
|
internal static class Endpoint
|
|
{
|
|
private const string Route = "/fire-webhook";
|
|
|
|
public static RouteHandlerBuilder MapFireWebhookEndpoint(this RouteGroupBuilder groupBuilder)
|
|
{
|
|
return groupBuilder.MapPost(Route, HandleAsync);
|
|
}
|
|
|
|
private static async Task<IResult> HandleAsync(
|
|
HttpContext httpContext,
|
|
[FromBody] Request request,
|
|
[FromServices] AppDbContext appDbContext,
|
|
[FromServices] IEncryptor encryptor,
|
|
[FromServices] PlaidClient plaidClient,
|
|
CancellationToken ct
|
|
)
|
|
{
|
|
var userId = httpContext.GetUserId();
|
|
|
|
var user = await appDbContext.Users
|
|
.Include(u => u.Accounts.Where(a => a.Id.ToString() == request.AccountId))
|
|
.ThenInclude(static a => a.Institution!)
|
|
.ThenInclude(static i => i.Metadata)
|
|
.FirstOrDefaultAsync(u => u.Id == userId, ct);
|
|
|
|
if (user is null)
|
|
{
|
|
return Results.Unauthorized();
|
|
}
|
|
|
|
if (user.Accounts.Any() is false)
|
|
{
|
|
return Results.NotFound();
|
|
}
|
|
|
|
var plaidMetadata = (PlaidInstitutionMetadata?)user.Accounts.First().Institution?.Metadata;
|
|
|
|
if (plaidMetadata is null)
|
|
{
|
|
return Results.InternalServerError("No metadata associated with account");
|
|
}
|
|
|
|
var accessToken = await encryptor.DecryptAsyncFor(user, plaidMetadata.EncryptedAccessToken, ct);
|
|
|
|
var fireEventResponse = await plaidClient.SandboxItemFireWebhookAsync(new()
|
|
{
|
|
AccessToken = accessToken,
|
|
WebhookType = SandboxItemFireWebhookRequestWebhookTypeEnum.Transactions,
|
|
WebhookCode = SandboxItemFireWebhookRequestWebhookCodeEnum.SyncUpdatesAvailable,
|
|
});
|
|
|
|
if (fireEventResponse.IsSuccessStatusCode is false)
|
|
{
|
|
return Results.InternalServerError(fireEventResponse.Error?.ErrorMessage);
|
|
}
|
|
|
|
return Results.Ok(new { fireEventResponse.RequestId, fireEventResponse.WebhookFired });
|
|
}
|
|
} |