Compare commits

..

No commits in common. "6f4fb29ae82cbc88d86d2f9863b4f028376fc25b" and "b81d0cf0bdacbaa6543e19281c103ee5e4503696" have entirely different histories.

13 changed files with 85 additions and 461 deletions

View File

@ -9,7 +9,6 @@ using AAIntegration.SimmonsBank.API.Config;
using System.Collections.Generic; using System.Collections.Generic;
using AAIntegration.SimmonsBank.API.Entities; using AAIntegration.SimmonsBank.API.Entities;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using System.Security.Claims;
[Authorize] [Authorize]
[ApiController] [ApiController]
@ -17,23 +16,17 @@ using System.Security.Claims;
public class AccountsController : ControllerBase public class AccountsController : ControllerBase
{ {
private IAccountService _accountService; private IAccountService _accountService;
private IUserService _userService;
private IMapper _mapper; private IMapper _mapper;
private readonly AppSettings _appSettings; private readonly AppSettings _appSettings;
private readonly ILogger<AccountsController> _logger;
public AccountsController( public AccountsController(
IAccountService accountService, IAccountService accountService,
IUserService userService,
IMapper mapper, IMapper mapper,
IOptions<AppSettings> appSettings, IOptions<AppSettings> appSettings)
ILogger<AccountsController> logger)
{ {
_accountService = accountService; _accountService = accountService;
_userService = userService;
_mapper = mapper; _mapper = mapper;
_appSettings = appSettings.Value; _appSettings = appSettings.Value;
_logger = logger;
} }
[HttpGet] [HttpGet]
@ -41,7 +34,7 @@ public class AccountsController : ControllerBase
{ {
List<AccountDTO> accountDtos = new List<AccountDTO>(); List<AccountDTO> accountDtos = new List<AccountDTO>();
foreach (Account acc in _accountService.GetAll(GetCurrentUserId())) foreach (Account acc in _accountService.GetAll())
accountDtos.Add(_mapper.Map<Account, AccountDTO>(acc)); accountDtos.Add(_mapper.Map<Account, AccountDTO>(acc));
return Ok(accountDtos); return Ok(accountDtos);
@ -50,42 +43,28 @@ public class AccountsController : ControllerBase
[HttpGet("{id}")] [HttpGet("{id}")]
public IActionResult GetById(int id) public IActionResult GetById(int id)
{ {
Account account = _accountService.GetById(id, GetCurrentUserId()); Account account = _accountService.GetById(id);
return Ok(_mapper.Map<Account, AccountDTO>(account)); return Ok(_mapper.Map<Account, AccountDTO>(account));
} }
[HttpPost] [HttpPost]
public IActionResult Create([FromBody]AccountCreateRequest model) public IActionResult Create([FromBody]AccountCreateRequest model)
{ {
_accountService.Create(model, GetCurrentUserId()); _accountService.Create(model);
return Ok(new { message = "account created" }); return Ok(new { message = "account created" });
} }
[HttpPut("{id}")] [HttpPut("{id}")]
public IActionResult Update(int id, [FromBody]AccountUpdateRequest model) public IActionResult Update(int id, [FromBody]AccountUpdateRequest model)
{ {
_accountService.Update(id, model, GetCurrentUserId()); _accountService.Update(id, model);
return Ok(new { message = "account updated" }); return Ok(new { message = "account updated" });
} }
[HttpDelete("{id}")] [HttpDelete("{id}")]
public IActionResult Delete(int id) public IActionResult Delete(int id)
{ {
_accountService.Delete(id, GetCurrentUserId()); _accountService.Delete(id);
return Ok(new { message = "account deleted" }); return Ok(new { message = "account deleted" });
} }
// Helpers
private int GetCurrentUserId()
{
string apiKey = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (apiKey is null)
_logger.LogInformation($"ApiKey: is null");
_logger.LogInformation($"apiKey: {apiKey}");
return _userService.GetUser(apiKey).Id;
}
} }

View File

@ -10,7 +10,6 @@ using System.Runtime.InteropServices;
using AAIntegration.SimmonsBank.API.Entities; using AAIntegration.SimmonsBank.API.Entities;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using System.Security.Claims;
[Authorize] [Authorize]
[ApiController] [ApiController]
@ -18,23 +17,17 @@ using System.Security.Claims;
public class TransactionsController : ControllerBase public class TransactionsController : ControllerBase
{ {
private ITransactionService _transactionService; private ITransactionService _transactionService;
private IUserService _userService;
private IMapper _mapper; private IMapper _mapper;
private readonly AppSettings _appSettings; private readonly AppSettings _appSettings;
private readonly ILogger<TransactionsController> _logger;
public TransactionsController( public TransactionsController(
ITransactionService transactionService, ITransactionService transactionService,
IUserService userService,
IMapper mapper, IMapper mapper,
IOptions<AppSettings> appSettings, IOptions<AppSettings> appSettings)
ILogger<TransactionsController> logger)
{ {
_transactionService = transactionService; _transactionService = transactionService;
_userService = userService;
_mapper = mapper; _mapper = mapper;
_appSettings = appSettings.Value; _appSettings = appSettings.Value;
_logger = logger;
} }
[HttpGet] [HttpGet]
@ -42,7 +35,7 @@ public class TransactionsController : ControllerBase
{ {
List<TransactionDto> transactionDtos = new List<TransactionDto>(); List<TransactionDto> transactionDtos = new List<TransactionDto>();
foreach (Transaction tran in _transactionService.GetAll(this.GetCurrentUserId())) foreach (Transaction tran in _transactionService.GetAll())
{ {
if (accountId.HasValue if (accountId.HasValue
&& (tran.DebitAccount == null || tran.DebitAccount.Id != accountId) && (tran.DebitAccount == null || tran.DebitAccount.Id != accountId)
@ -61,49 +54,35 @@ public class TransactionsController : ControllerBase
[HttpGet("{id}")] [HttpGet("{id}")]
public IActionResult GetById(int id) public IActionResult GetById(int id)
{ {
Transaction tran = _transactionService.GetById(id, this.GetCurrentUserId()); Transaction tran = _transactionService.GetById(id);
return Ok(_mapper.Map<Transaction, TransactionDto>(tran)); return Ok(_mapper.Map<Transaction, TransactionDto>(tran));
} }
[HttpPost("BulkAdd")] [HttpPost("BulkAdd")]
public IActionResult BulkCreate([FromBody]List<TransactionCreate> model) public IActionResult BulkCreate([FromBody]List<TransactionCreate> model)
{ {
List<Transaction> trans = _transactionService.BulkCreate(model, this.GetCurrentUserId()).ToList(); List<Transaction> trans = _transactionService.BulkCreate(model).ToList();
return Ok(new { message = $"{trans.Count()} transaction(s) created." }); return Ok(new { message = $"{trans.Count()} transaction(s) created." });
} }
[HttpPost] [HttpPost]
public IActionResult Create([FromBody]TransactionCreate model) public IActionResult Create([FromBody]TransactionCreate model)
{ {
Transaction tran = _transactionService.Create(model, this.GetCurrentUserId()); Transaction tran = _transactionService.Create(model);
return Ok(new { message = $"transaction '{tran.Description}' created with id '{tran.Id}'." }); return Ok(new { message = $"transaction '{tran.Description}' created with id '{tran.Id}'." });
} }
[HttpPut("{id}")] [HttpPut("{id}")]
public IActionResult Update(int id, [FromBody]TransactionUpdateRequest model) public IActionResult Update(int id, [FromBody]TransactionUpdateRequest model)
{ {
_transactionService.Update(id, model, this.GetCurrentUserId()); _transactionService.Update(id, model);
return Ok(new { message = $"transaction with id '{id}' updated" }); return Ok(new { message = $"transaction with id '{id}' updated" });
} }
[HttpDelete("{id}")] [HttpDelete("{id}")]
public IActionResult Delete(int id) public IActionResult Delete(int id)
{ {
_transactionService.Delete(id, this.GetCurrentUserId()); _transactionService.Delete(id);
return Ok(new { message = "transaction deleted" }); return Ok(new { message = "transaction deleted" });
} }
// Helpers
private int GetCurrentUserId()
{
string apiKey = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (apiKey is null)
_logger.LogInformation($"ApiKey: is null");
_logger.LogInformation($"apiKey: {apiKey}");
return _userService.GetUser(apiKey).Id;
}
} }

View File

@ -39,7 +39,7 @@ public class UsersController : ControllerBase
} }
[Authorize] [Authorize]
[HttpPut] [HttpPut("{id}")]
public IActionResult Update([FromBody]UserUpdateRequest model) public IActionResult Update([FromBody]UserUpdateRequest model)
{ {
_userService.Update(this.GetCurrentUserApiKey(), model); _userService.Update(this.GetCurrentUserApiKey(), model);
@ -47,8 +47,8 @@ public class UsersController : ControllerBase
} }
[Authorize] [Authorize]
[HttpDelete] [HttpDelete("{id}")]
public IActionResult Delete() public IActionResult Delete(int id)
{ {
_userService.Delete(this.GetCurrentUserApiKey()); _userService.Delete(this.GetCurrentUserApiKey());
return Ok(new { message = "User deleted" }); return Ok(new { message = "User deleted" });
@ -64,6 +64,7 @@ public class UsersController : ControllerBase
_logger.LogInformation($"ApiKey: is null"); _logger.LogInformation($"ApiKey: is null");
_logger.LogInformation($"apiKey: {apiKey}"); _logger.LogInformation($"apiKey: {apiKey}");
Console.WriteLine($"User Id: " + apiKey);
return apiKey; return apiKey;
} }

View File

@ -8,5 +8,4 @@ public class Account
public string Name { get; set; } public string Name { get; set; }
public decimal Balance { get; set; } public decimal Balance { get; set; }
public string ExternalAccountNumber { get; set; } public string ExternalAccountNumber { get; set; }
public User Owner { get; set; }
} }

View File

@ -15,5 +15,4 @@ public class Transaction
public Account? CreditAccount { get; set; } public Account? CreditAccount { get; set; }
public decimal Amount { get; set; } public decimal Amount { get; set; }
public bool IsPending { get; set; } public bool IsPending { get; set; }
public User Owner { get; set; }
} }

View File

@ -1,173 +0,0 @@
// <auto-generated />
using System;
using AAIntegration.SimmonsBank.API.Config;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace AAIntegration.SimmonsBank.API.Migrations
{
[DbContext(typeof(DataContext))]
[Migration("20240320022712_UserOwnedEntities")]
partial class UserOwnedEntities
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.9")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("AAIntegration.SimmonsBank.API.Entities.Account", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<decimal>("Balance")
.HasColumnType("numeric");
b.Property<string>("ExternalAccountNumber")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<int>("OwnerId")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("OwnerId");
b.ToTable("Accounts");
});
modelBuilder.Entity("AAIntegration.SimmonsBank.API.Entities.Transaction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<decimal>("Amount")
.HasColumnType("numeric");
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<int?>("CreditAccountId")
.HasColumnType("integer");
b.Property<DateTime>("Date")
.HasColumnType("timestamp with time zone");
b.Property<int?>("DebitAccountId")
.HasColumnType("integer");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("text");
b.Property<string>("ExternalId")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("IsPending")
.HasColumnType("boolean");
b.Property<int>("OwnerId")
.HasColumnType("integer");
b.Property<DateTime>("UpdatedOn")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.HasIndex("CreditAccountId");
b.HasIndex("DebitAccountId");
b.HasIndex("OwnerId");
b.ToTable("Transactions");
});
modelBuilder.Entity("AAIntegration.SimmonsBank.API.Entities.User", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ApiKey")
.IsRequired()
.HasColumnType("text");
b.Property<string>("MFAKey")
.IsRequired()
.HasColumnType("text");
b.Property<string>("SimmonsBankPassword")
.IsRequired()
.HasColumnType("text");
b.Property<string>("SimmonsBankUsername")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Users");
});
modelBuilder.Entity("AAIntegration.SimmonsBank.API.Entities.Account", b =>
{
b.HasOne("AAIntegration.SimmonsBank.API.Entities.User", "Owner")
.WithMany()
.HasForeignKey("OwnerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Owner");
});
modelBuilder.Entity("AAIntegration.SimmonsBank.API.Entities.Transaction", b =>
{
b.HasOne("AAIntegration.SimmonsBank.API.Entities.Account", "CreditAccount")
.WithMany()
.HasForeignKey("CreditAccountId");
b.HasOne("AAIntegration.SimmonsBank.API.Entities.Account", "DebitAccount")
.WithMany()
.HasForeignKey("DebitAccountId");
b.HasOne("AAIntegration.SimmonsBank.API.Entities.User", "Owner")
.WithMany()
.HasForeignKey("OwnerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("CreditAccount");
b.Navigation("DebitAccount");
b.Navigation("Owner");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -1,82 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace AAIntegration.SimmonsBank.API.Migrations
{
/// <inheritdoc />
public partial class UserOwnedEntities : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "OwnerId",
table: "Transactions",
type: "integer",
nullable: false,
defaultValue: 0);
migrationBuilder.AddColumn<int>(
name: "OwnerId",
table: "Accounts",
type: "integer",
nullable: false,
defaultValue: 0);
migrationBuilder.CreateIndex(
name: "IX_Transactions_OwnerId",
table: "Transactions",
column: "OwnerId");
migrationBuilder.CreateIndex(
name: "IX_Accounts_OwnerId",
table: "Accounts",
column: "OwnerId");
migrationBuilder.AddForeignKey(
name: "FK_Accounts_Users_OwnerId",
table: "Accounts",
column: "OwnerId",
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_Transactions_Users_OwnerId",
table: "Transactions",
column: "OwnerId",
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Accounts_Users_OwnerId",
table: "Accounts");
migrationBuilder.DropForeignKey(
name: "FK_Transactions_Users_OwnerId",
table: "Transactions");
migrationBuilder.DropIndex(
name: "IX_Transactions_OwnerId",
table: "Transactions");
migrationBuilder.DropIndex(
name: "IX_Accounts_OwnerId",
table: "Accounts");
migrationBuilder.DropColumn(
name: "OwnerId",
table: "Transactions");
migrationBuilder.DropColumn(
name: "OwnerId",
table: "Accounts");
}
}
}

View File

@ -41,13 +41,8 @@ namespace AAIntegration.SimmonsBank.API.Migrations
.IsRequired() .IsRequired()
.HasColumnType("text"); .HasColumnType("text");
b.Property<int>("OwnerId")
.HasColumnType("integer");
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("OwnerId");
b.ToTable("Accounts"); b.ToTable("Accounts");
}); });
@ -85,9 +80,6 @@ namespace AAIntegration.SimmonsBank.API.Migrations
b.Property<bool>("IsPending") b.Property<bool>("IsPending")
.HasColumnType("boolean"); .HasColumnType("boolean");
b.Property<int>("OwnerId")
.HasColumnType("integer");
b.Property<DateTime>("UpdatedOn") b.Property<DateTime>("UpdatedOn")
.HasColumnType("timestamp with time zone"); .HasColumnType("timestamp with time zone");
@ -97,8 +89,6 @@ namespace AAIntegration.SimmonsBank.API.Migrations
b.HasIndex("DebitAccountId"); b.HasIndex("DebitAccountId");
b.HasIndex("OwnerId");
b.ToTable("Transactions"); b.ToTable("Transactions");
}); });
@ -131,17 +121,6 @@ namespace AAIntegration.SimmonsBank.API.Migrations
b.ToTable("Users"); b.ToTable("Users");
}); });
modelBuilder.Entity("AAIntegration.SimmonsBank.API.Entities.Account", b =>
{
b.HasOne("AAIntegration.SimmonsBank.API.Entities.User", "Owner")
.WithMany()
.HasForeignKey("OwnerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Owner");
});
modelBuilder.Entity("AAIntegration.SimmonsBank.API.Entities.Transaction", b => modelBuilder.Entity("AAIntegration.SimmonsBank.API.Entities.Transaction", b =>
{ {
b.HasOne("AAIntegration.SimmonsBank.API.Entities.Account", "CreditAccount") b.HasOne("AAIntegration.SimmonsBank.API.Entities.Account", "CreditAccount")
@ -152,17 +131,9 @@ namespace AAIntegration.SimmonsBank.API.Migrations
.WithMany() .WithMany()
.HasForeignKey("DebitAccountId"); .HasForeignKey("DebitAccountId");
b.HasOne("AAIntegration.SimmonsBank.API.Entities.User", "Owner")
.WithMany()
.HasForeignKey("OwnerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("CreditAccount"); b.Navigation("CreditAccount");
b.Navigation("DebitAccount"); b.Navigation("DebitAccount");
b.Navigation("Owner");
}); });
#pragma warning restore 612, 618 #pragma warning restore 612, 618
} }

View File

@ -10,5 +10,4 @@ public class AccountCreateRequest
public string InitialBalance { get; set; } public string InitialBalance { get; set; }
public int Currency { get; set; } public int Currency { get; set; }
public string ExternalAccountNumber { get; set; } public string ExternalAccountNumber { get; set; }
public int Owner { get; set; }
} }

View File

@ -14,11 +14,11 @@ using Microsoft.EntityFrameworkCore;
public interface IAccountService public interface IAccountService
{ {
IEnumerable<Account> GetAll(int ownerId); IEnumerable<Account> GetAll();
Account GetById(int accountId, int ownerId); Account GetById(int accountId);
void Create(AccountCreateRequest model, int ownerId); void Create(AccountCreateRequest model);
void Update(int accountId, AccountUpdateRequest model, int ownerId); void Update(int accountId, AccountUpdateRequest model);
void Delete(int accountId, int ownerId); void Delete(int accountId);
} }
public class AccountService : IAccountService public class AccountService : IAccountService
@ -37,57 +37,51 @@ public class AccountService : IAccountService
_userService = userService; _userService = userService;
} }
public IEnumerable<Account> GetAll(int ownerId) public IEnumerable<Account> GetAll()
{ {
return _context.Accounts return _context.Accounts;
.Include(x => x.Owner)
.Where(x => x.Owner.Id == ownerId);
} }
public Account GetById(int accountId, int ownerId) public Account GetById(int accountId)
{ {
return getAccount(accountId, ownerId); return getAccount(accountId);
} }
public void Create(AccountCreateRequest model, int ownerId) public void Create(AccountCreateRequest model)
{ {
// Check that account with same name or same external number doesn't exist // Check that account with same name or same external number doesn't exist
IEnumerable<Account> accountsWithSameName = _context.Accounts IEnumerable<Account> accountsWithSameName = _context.Accounts.Where(a => a.Name.ToUpper() == model.Name.ToUpper());
.Include(x => x.Owner)
.Where(x => x.Name.ToUpper() == model.Name.ToUpper() && x.Owner.Id == ownerId);
if (accountsWithSameName.Count() > 0) if (accountsWithSameName.Count() > 0)
throw new AppException("Account with name '" + model.Name + "' already exists"); throw new AppException("Account with name '" + model.Name + "' already exists");
if (!string.IsNullOrWhiteSpace(model.ExternalAccountNumber)) if (!string.IsNullOrWhiteSpace(model.ExternalAccountNumber))
{ {
IEnumerable<Account> matches = _context.Accounts IEnumerable<Account> matches = _context.Accounts.Where(a => a.ExternalAccountNumber == model.ExternalAccountNumber);
.Include(x => x.Owner)
.Where(x => x.ExternalAccountNumber == model.ExternalAccountNumber && x.Owner.Id == ownerId);
if (matches.Count() > 0) if (matches.Count() > 0)
throw new AppException("Account with external account number '" + model.ExternalAccountNumber + "' already exists under account named '" + matches.First().Name + "'"); throw new AppException("Account with external account number '" + model.ExternalAccountNumber + "' already exists under account named '" + matches.First().Name + "'");
} }
// map model to new account object
//var account = _mapper.Map<Account>(model);
Account account = new Account { Account account = new Account {
Name = model.Name, Name = model.Name,
Balance = Convert.ToDecimal(model.InitialBalance), Balance = Convert.ToDecimal(model.InitialBalance),
ExternalAccountNumber = model.ExternalAccountNumber, ExternalAccountNumber = model.ExternalAccountNumber
Owner = getOwner(ownerId)
}; };
_context.Accounts.Add(account); _context.Accounts.Add(account);
_context.SaveChanges(); _context.SaveChanges();
} }
public void Update(int accountId, AccountUpdateRequest model, int ownerId) public void Update(int accountId, AccountUpdateRequest model)
{ {
Account account = getAccount(accountId, ownerId); Account account = getAccount(accountId);
// validate // validate
if (model.Name != account.Name && _context.Accounts if (model.Name != account.Name && _context.Accounts.Any(x => x.Name == model.Name))
.Include(x => x.Owner)
.Any(x => x.Name == model.Name && x.Owner.Id == ownerId))
throw new AppException("Account with the name '" + model.Name + "' already exists"); throw new AppException("Account with the name '" + model.Name + "' already exists");
// Name // Name
@ -102,31 +96,19 @@ public class AccountService : IAccountService
_context.SaveChanges(); _context.SaveChanges();
} }
public void Delete(int accountId, int ownerId) public void Delete(int accountId)
{ {
var account = getAccount(accountId, ownerId); var account = getAccount(accountId);
_context.Accounts.Remove(account); _context.Accounts.Remove(account);
_context.SaveChanges(); _context.SaveChanges();
} }
// helper methods // helper methods
private Account getAccount(int id, int ownerId) private Account getAccount(int id)
{ {
var account = _context.Accounts var account = _context.Accounts.Find(id);
.Include(x => x.Owner)
.FirstOrDefault(x => x.Id == id && x.Owner.Id == ownerId);
if (account == null) throw new KeyNotFoundException("Account not found"); if (account == null) throw new KeyNotFoundException("Account not found");
return account; return account;
} }
private User getOwner(int ownerId)
{
User? owner = _context.Users.Find(ownerId);
if (owner == null)
throw new AppException($"Owner with ID of '{ownerId}' could not be found");
return owner;
}
} }

View File

@ -11,48 +11,29 @@ public class CacheService : ICacheService
{ {
private readonly IMemoryCache _memoryCache; private readonly IMemoryCache _memoryCache;
private readonly IUserService _userService; private readonly IUserService _userService;
private readonly ILogger<ICacheService> _logger;
public CacheService(IMemoryCache memoryCache, IUserService userService, ILogger<ICacheService> logger) public CacheService(IMemoryCache memoryCache, IUserService userService)
{ {
_memoryCache = memoryCache; _memoryCache = memoryCache;
_userService = userService; _userService = userService;
_logger = logger;
} }
public int GetClientIdFromApiKey(string apiKey) public int GetClientIdFromApiKey(string apiKey)
{ {
if (!_memoryCache.TryGetValue<Dictionary<string, int>>($"Authentication_ApiKeys", out var internalKeys)) if (!_memoryCache.TryGetValue<Dictionary<string, int>>($"Authentication_ApiKeys", out var internalKeys))
{ {
_logger.LogInformation($"Could not find API key '{apiKey}' in cache.");
internalKeys = _userService.GetAllApiKeys(); internalKeys = _userService.GetAllApiKeys();
_logger.LogInformation("Updated cache with new key list.");
PrintInternalKeys(internalKeys);
_memoryCache.Set($"Authentication_ApiKeys", internalKeys); _memoryCache.Set($"Authentication_ApiKeys", internalKeys);
} }
if (!internalKeys.TryGetValue(apiKey, out var clientId)) if (!internalKeys.TryGetValue(apiKey, out var clientId))
{ {
_logger.LogInformation("Could not find API key. Returning -1.");
return -1; return -1;
} }
return clientId; return clientId;
} }
// helpers
private void PrintInternalKeys(Dictionary<string, int> keys)
{
string msg = "API Keys (dev only - needs to be moved to dev only)";
foreach (var item in keys)
msg += $"\n\t{item.Value} : {item.Key}";
_logger.LogInformation(msg);
}
/*public void InvalidateApiKey(string apiKey) /*public void InvalidateApiKey(string apiKey)
{ {

View File

@ -15,12 +15,12 @@ using System.Collections.Immutable;
public interface ITransactionService public interface ITransactionService
{ {
IEnumerable<Transaction> GetAll(int ownerId); IEnumerable<Transaction> GetAll();
Transaction GetById(int id, int ownerId); Transaction GetById(int id);
IEnumerable<Transaction> BulkCreate(List<TransactionCreate> model, int ownerId); IEnumerable<Transaction> BulkCreate(List<TransactionCreate> model);
Transaction Create(TransactionCreate model, int ownerId, bool errorOnFail = true); Transaction Create(TransactionCreate model, bool errorOnFail = true);
void Update(int id, TransactionUpdateRequest model, int ownerId); void Update(int id, TransactionUpdateRequest model);
void Delete(int id, int ownerId); void Delete(int id);
} }
public class TransactionService : ITransactionService public class TransactionService : ITransactionService
@ -39,18 +39,17 @@ public class TransactionService : ITransactionService
_logger = logger; _logger = logger;
} }
public IEnumerable<Transaction> GetAll(int ownerId) public IEnumerable<Transaction> GetAll()
{ {
return _context.Transactions return _context.Transactions
.Include(t => t.DebitAccount) .Include(t => t.DebitAccount)
.Include(t => t.CreditAccount) .Include(t => t.CreditAccount)
.Include(t => t.Owner) .ToList();
.Where(x => x.Owner.Id == ownerId);
} }
public Transaction GetById(int id, int ownerId) public Transaction GetById(int id)
{ {
return getTransaction(id, ownerId); return getTransaction(id);
} }
private Account prepareAccount(int? accountId) private Account prepareAccount(int? accountId)
@ -67,13 +66,13 @@ public class TransactionService : ITransactionService
return account; return account;
} }
public IEnumerable<Transaction> BulkCreate(List<TransactionCreate> model, int ownerId) public IEnumerable<Transaction> BulkCreate(List<TransactionCreate> model)
{ {
List<Transaction> transactions = new List<Transaction>(); List<Transaction> transactions = new List<Transaction>();
foreach (TransactionCreate tr in model) foreach (TransactionCreate tr in model)
{ {
var tran = this.Create(tr, ownerId, false); var tran = this.Create(tr, false);
if (tran != null) if (tran != null)
transactions.Add(tran); transactions.Add(tran);
} }
@ -81,7 +80,7 @@ public class TransactionService : ITransactionService
return transactions; return transactions;
} }
public Transaction Create(TransactionCreate model, int ownerId, bool errorOnFail = true) public Transaction Create(TransactionCreate model, bool errorOnFail = true)
{ {
Transaction transaction = new Transaction { Transaction transaction = new Transaction {
Description = model.Description, Description = model.Description,
@ -92,11 +91,10 @@ public class TransactionService : ITransactionService
DebitAccount = prepareAccount(model.DebitAccount), DebitAccount = prepareAccount(model.DebitAccount),
CreditAccount = prepareAccount(model.CreditAccount), CreditAccount = prepareAccount(model.CreditAccount),
Amount = Convert.ToDecimal(model.Amount), Amount = Convert.ToDecimal(model.Amount),
Owner = this.getOwner(ownerId),
IsPending = model.IsPending IsPending = model.IsPending
}; };
if (this.ValidateTransaction(transaction, ownerId, errorOnFail) == false) if (this.ValidateTransaction(transaction, errorOnFail) == false)
{ {
_logger.LogInformation($"Aborted adding transaction '{transaction.Description}'."); _logger.LogInformation($"Aborted adding transaction '{transaction.Description}'.");
return null; return null;
@ -112,9 +110,9 @@ public class TransactionService : ITransactionService
return transaction; return transaction;
} }
public void Update(int id, TransactionUpdateRequest model, int ownerId) public void Update(int id, TransactionUpdateRequest model)
{ {
Transaction transaction = getTransaction(id, ownerId); Transaction transaction = getTransaction(id);
// Transaction.Date // Transaction.Date
if (model.Date.HasValue) if (model.Date.HasValue)
@ -144,7 +142,7 @@ public class TransactionService : ITransactionService
if (model.IsPending.HasValue) if (model.IsPending.HasValue)
transaction.IsPending = model.IsPending.Value; transaction.IsPending = model.IsPending.Value;
this.ValidateTransaction(transaction, ownerId); this.ValidateTransaction(transaction);
transaction.UpdatedOn = DateTime.UtcNow; transaction.UpdatedOn = DateTime.UtcNow;
@ -154,15 +152,11 @@ public class TransactionService : ITransactionService
_logger.LogInformation($"Transaction '{id}' successfully updated."); _logger.LogInformation($"Transaction '{id}' successfully updated.");
} }
public void Delete(int id, int ownerId) private bool ValidateTransaction(int transactionId)
{ {
var transaction = getTransaction(id, ownerId); return this.ValidateTransaction(getTransaction(transactionId));
_context.Transactions.Remove(transaction);
_context.SaveChanges();
} }
// helpers
private bool ErrorOrFalse(bool error, string errorMessage) private bool ErrorOrFalse(bool error, string errorMessage)
{ {
if (error) if (error)
@ -172,7 +166,7 @@ public class TransactionService : ITransactionService
return false; return false;
} }
private bool ValidateTransaction(Transaction transaction, int ownerId, bool errorOnFail = true) private bool ValidateTransaction(Transaction transaction, bool errorOnFail = true)
{ {
// There has to be at least 1 specified account // There has to be at least 1 specified account
if (transaction.DebitAccount == null && transaction.CreditAccount == null) if (transaction.DebitAccount == null && transaction.CreditAccount == null)
@ -184,10 +178,7 @@ public class TransactionService : ITransactionService
return ErrorOrFalse(errorOnFail, "The debit and credit accounts of a transaction cannot be the same."); return ErrorOrFalse(errorOnFail, "The debit and credit accounts of a transaction cannot be the same.");
// Transaction Duplication Check - External ID // Transaction Duplication Check - External ID
if (!string.IsNullOrWhiteSpace(transaction.ExternalId) if (!string.IsNullOrWhiteSpace(transaction.ExternalId) && _context.Transactions.Any(x => x.ExternalId == transaction.ExternalId))
&& _context.Transactions
.Include(x => x.Owner)
.Any(x => x.ExternalId == transaction.ExternalId && x.Owner.Id == ownerId))
return ErrorOrFalse(errorOnFail, "Transaction with the external ID '" + transaction.ExternalId + "' already exists"); return ErrorOrFalse(errorOnFail, "Transaction with the external ID '" + transaction.ExternalId + "' already exists");
// Transaction Duplication Check - All other fields // Transaction Duplication Check - All other fields
@ -204,27 +195,23 @@ public class TransactionService : ITransactionService
return true; return true;
} }
private Transaction getTransaction(int id, int ownerId) public void Delete(int id)
{
var transaction = getTransaction(id);
_context.Transactions.Remove(transaction);
_context.SaveChanges();
}
private Transaction getTransaction(int id)
{ {
var transaction = _context.Transactions var transaction = _context.Transactions
.Include(t => t.DebitAccount) .Include(t => t.DebitAccount)
.Include(t => t.CreditAccount) .Include(t => t.CreditAccount)
.Include(t => t.Owner) .FirstOrDefault(t => t.Id == id);
.FirstOrDefault(t => t.Id == id && t.Owner.Id == ownerId);
if (transaction == null) if (transaction == null)
throw new KeyNotFoundException("Transaction not found"); throw new KeyNotFoundException("Transaction not found");
return transaction; return transaction;
} }
private User getOwner(int ownerId)
{
User? owner = _context.Users.Find(ownerId);
if (owner == null)
throw new AppException($"Owner with ID of '{ownerId}' could not be found");
return owner;
}
} }

View File

@ -23,7 +23,6 @@ public interface IUserService
void Update(string apiKey, UserUpdateRequest model); void Update(string apiKey, UserUpdateRequest model);
void Delete(string apiKey); void Delete(string apiKey);
Dictionary<string, int> GetAllApiKeys(); Dictionary<string, int> GetAllApiKeys();
User GetUser(string ApiKey);
/* Other cringe way /* Other cringe way
AuthenticateResponse Authenticate(AuthenticateRequest model); AuthenticateResponse Authenticate(AuthenticateRequest model);
@ -75,7 +74,7 @@ public class UserService : IUserService
public void Update(string apiKey, UserUpdateRequest model) public void Update(string apiKey, UserUpdateRequest model)
{ {
var user = this.GetUser(apiKey); var user = getUser(apiKey);
// User.Username // User.Username
if (model.Username != null) if (model.Username != null)
@ -95,7 +94,7 @@ public class UserService : IUserService
public void Delete(string apiKey) public void Delete(string apiKey)
{ {
var user = this.GetUser(apiKey); var user = getUser(apiKey);
_context.Users.Remove(user); _context.Users.Remove(user);
_context.SaveChanges(); _context.SaveChanges();
} }
@ -107,20 +106,23 @@ public class UserService : IUserService
.ToDictionary(u => u.ApiKey, u => u.Id); .ToDictionary(u => u.ApiKey, u => u.Id);
} }
public User GetUser(string ApiKey)
{
var user = _context.Users
.Where(u => u.ApiKey == ApiKey)
.FirstOrDefault() ?? throw new KeyNotFoundException("User not found");
return user;
}
// helper methods // helper methods
private User getUser(int id) private User getUser(int id)
{ {
var user = _context.Users.Find(id) ?? throw new KeyNotFoundException("User not found"); var user = _context.Users.Find(id);
if (user == null) throw new KeyNotFoundException("User not found");
return user;
}
private User getUser(string ApiKey)
{
var user = _context.Users
.Where(u => u.ApiKey == ApiKey)
.FirstOrDefault();
if (user == null) throw new KeyNotFoundException("User not found");
return user; return user;
} }