feat: add Plaid transaction handling and async queue processing
- 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.
This commit is contained in:
@@ -13,7 +13,7 @@ internal static class Endpoint
|
||||
HttpContext httpContext,
|
||||
[FromBody] Request request,
|
||||
[FromServices] AppDbContext appDbContext,
|
||||
[FromServices] PlaidService plaidService,
|
||||
[FromServices] IPlaidAccountService plaidAccountService,
|
||||
[FromServices] IEncryptor encryptor,
|
||||
CancellationToken ct
|
||||
)
|
||||
@@ -23,8 +23,8 @@ internal static class Endpoint
|
||||
var user = await appDbContext.Users
|
||||
.Include(u => u.Institutions
|
||||
.Where(
|
||||
i => i.Metadata is PlaidMetadata &&
|
||||
((PlaidMetadata)i.Metadata).PlaidId == request.PlaidInstitutionId
|
||||
i => i.Metadata is PlaidInstitutionMetadata &&
|
||||
((PlaidInstitutionMetadata)i.Metadata).PlaidId == request.PlaidInstitutionId
|
||||
)
|
||||
)
|
||||
.ThenInclude(i => i.Metadata)
|
||||
@@ -40,12 +40,11 @@ internal static class Endpoint
|
||||
return Results.Conflict();
|
||||
}
|
||||
|
||||
var (itemId, accessToken) = await plaidService.ExchangeTokenAsync(request.PublicToken);
|
||||
var item = await plaidService.GetItemAsync(accessToken);
|
||||
|
||||
var (itemId, accessToken) = await plaidAccountService.ExchangeTokenAsync(request.PublicToken);
|
||||
var item = await plaidAccountService.GetItemAsync(accessToken);
|
||||
var encryptedAccessToken = await encryptor.EncryptAsyncFor(user, accessToken, ct);
|
||||
|
||||
var plaidMetadata = PlaidMetadata.From(item.InstitutionId, item.InstitutionName, encryptedAccessToken);
|
||||
var plaidMetadata = PlaidInstitutionMetadata.From(item.InstitutionId, item.InstitutionName, encryptedAccessToken, itemId);
|
||||
var institution = Institution.From(item.InstitutionName, plaidMetadata);
|
||||
|
||||
user.AddInstitution(institution);
|
||||
|
||||
@@ -13,7 +13,7 @@ internal static class Endpoint
|
||||
HttpContext httpContext,
|
||||
[FromRoute] Guid id,
|
||||
[FromServices] AppDbContext appDbContext,
|
||||
[FromServices] PlaidService plaidService,
|
||||
[FromServices] IPlaidAccountService plaidAccountService,
|
||||
[FromServices] IEncryptor encryptor,
|
||||
CancellationToken ct
|
||||
)
|
||||
@@ -37,13 +37,13 @@ internal static class Endpoint
|
||||
|
||||
var institution = user.Institutions.First();
|
||||
|
||||
if (institution.Metadata is not PlaidMetadata plaidMetadata)
|
||||
if (institution.Metadata is not PlaidInstitutionMetadata plaidMetadata)
|
||||
{
|
||||
return Results.BadRequest();
|
||||
}
|
||||
|
||||
var accessToken = await encryptor.DecryptAsyncFor(user, plaidMetadata.EncryptedAccessToken, ct);
|
||||
var accounts = await plaidService.GetAccountsAsync(accessToken);
|
||||
var accounts = await plaidAccountService.GetAccountsAsync(accessToken);
|
||||
var accountsDtos = accounts.Select(a => AvailableAccountDto.From(plaidMetadata, a));
|
||||
|
||||
return Results.Ok(Response.From(accountsDtos));
|
||||
|
||||
@@ -33,7 +33,7 @@ internal sealed record AvailableAccountDto
|
||||
}
|
||||
|
||||
public static AvailableAccountDto From(
|
||||
PlaidMetadata plaidMetadata,
|
||||
PlaidInstitutionMetadata plaidMetadata,
|
||||
Going.Plaid.Entity.Account plaidAccount
|
||||
)
|
||||
{
|
||||
|
||||
@@ -12,7 +12,7 @@ internal static class Endpoint
|
||||
private static async Task<IResult> HandleAsync(
|
||||
HttpContext httpContext,
|
||||
[FromServices] AppDbContext appDbContext,
|
||||
[FromServices] PlaidService plaidService
|
||||
[FromServices] IPlaidAccountService plaidAccountService
|
||||
)
|
||||
{
|
||||
var userId = httpContext.GetUserId();
|
||||
@@ -24,7 +24,7 @@ internal static class Endpoint
|
||||
return Results.Unauthorized();
|
||||
}
|
||||
|
||||
var linkToken = await plaidService.CreateLinkTokenAsync(user.Id.ToString());
|
||||
var linkToken = await plaidAccountService.CreateLinkTokenAsync(user.Id.ToString());
|
||||
|
||||
return Results.Ok(Response.From(linkToken));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user