Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 135 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.

# User-specific files
*.suo
*.user
*.sln.docstates

# Build results

[Dd]ebug/
[Rr]elease/
x64/
[Bb]in/
[Oo]bj/

# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

.vs/

*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.log
*.svclog
*.scc

# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile

# Visual Studio profiler
*.psess
*.vsp
*.vspx

# Guidance Automation Toolkit
*.gpState

# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user

# Click-Once directory
publish/

# Publish Web Output
*.Publish.xml
*.pubxml
*.azurePubxml

# NuGet Packages Directory
## TODO: If you have NuGet Package Restore enabled, uncomment the next line
packages/
## TODO: If the tool you use requires repositories.config, also uncomment the next line
!packages/repositories.config

# Windows Azure Build Output
csx/
*.build.csdef

# Windows Store app package directory
AppPackages/

# Others
sql/
*.Cache
ClientBin/
[Ss]tyle[Cc]op.*
![Ss]tyle[Cc]op.targets
~$*
*~
*.dbmdl
*.[Pp]ublish.xml

*.publishsettings

# RIA/Silverlight projects
Generated_Code/

# Backup & report files from converting an old project file to a newer
# Visual Studio version. Backup files are not needed, because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm

# SQL Server files
App_Data/*.mdf
App_Data/*.ldf

# =========================
# Windows detritus
# =========================

# Windows image file caches
Thumbs.db
ehthumbs.db

# Folder config file
Desktop.ini

# Recycle Bin used on file shares
$RECYCLE.BIN/

# Mac desktop service store files
.DS_Store

_NCrunch*
93 changes: 93 additions & 0 deletions InvestmentPerformanceWebAPI/Controllers/TransactionsController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
using InvestmentPerformanceWebAPI.Database;
using InvestmentPerformanceWebAPI.DataTransferObjects;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace InvestmentPerformanceWebAPI.Controllers
{
/// <summary>
/// Controller responsible for handling transaction-related API endpoints.
/// Provides access to transaction data including basic transaction information and detailed financial calculations.
/// </summary>
[ApiController]
[Route("[controller]")]
public class TransactionsController : ControllerBase
{
private readonly ApplicationDbContext _context;

/// <summary>
/// Initializes a new instance of the TransactionsController.
/// </summary>
/// <param name="context">The Entity Framework database context used to access transaction data.</param>
public TransactionsController(ApplicationDbContext context)
{
_context = context;
}

/// <summary>
/// Retrieves all transactions associated with a specific user.
/// Returns basic transaction information (ID and Name) for all transactions belonging to the specified user.
/// </summary>
/// <param name="id">The unique identifier of the user whose transactions should be retrieved.</param>
[HttpGet]
[Route("user/{id}")]
public IActionResult GetTransactionsForUser(int id)
{
// Query the database for all transactions belonging to the specified user
// Project the results to TransactionDTO to return only basic information
var transactions = _context.Transactions.Where(t => t.UserId == id).Select( t => new TransactionDTO()
{
Id = t.Id,
Name = t.Name
});

return Ok(transactions);
}

/// <summary>
/// Retrieves basic information for a specific transaction by its ID.
/// Returns only the transaction ID and company name.
/// </summary>
/// <param name="id">The unique identifier of the transaction to retrieve.</param>
[HttpGet]
[Route("{id}")]
public IActionResult GetTransaction(int id)
{
// Query for a specific transaction by ID and project to basic DTO
// Note: Returns IQueryable which may contain 0 or 1 results
var transactions = _context.Transactions.Where(t => t.Id == id).Select(t => new TransactionDTO()
{
Id = t.Id,
Name = t.Name,
});

return Ok(transactions);
}

/// <summary>
/// Retrieves comprehensive transaction details including financial calculations for a specific transaction.
/// Returns detailed information including current market value, total gain/loss, and investment performance metrics.
/// </summary>
/// <param name="id">The unique identifier of the transaction to retrieve detailed information for.</param>
[HttpGet]
[Route("transaction-details/{id}")]
public IActionResult GetTransactionDetails(int id)
{
// Query for specific transaction and project to detailed DTO with financial calculations
var transactions = _context.Transactions.Where(t => t.Id == id).Select(t => new TransactionDetailsDTO()
{
Id = t.Id,
Name = t.Name,
Shares = t.Quantity, // Map Quantity to Shares for DTO
TransactionTime = t.TransactionTime,
CostBasisPerShare = t.SharePriceAtPurchase, // Original purchase price per share
CurrentValue = t.CurrentSharePrice * t.Quantity, // Total current market value
CurrentPrice = t.CurrentSharePrice, // Current market price per share
// Calculate total gain/loss: (Current Value) - (Original Investment)
TotalGain = (t.CurrentSharePrice * t.Quantity) - (t.SharePriceAtPurchase * t.Quantity)
});

return Ok(transactions);
}
}
}
88 changes: 88 additions & 0 deletions InvestmentPerformanceWebAPI/Controllers/UsersController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using InvestmentPerformanceWebAPI.Database;
using InvestmentPerformanceWebAPI.DataTransferObjects;
using InvestmentPerformanceWebAPI.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;

namespace InvestmentPerformanceWebAPI.Controllers
{

[ApiController]
[Route("[controller]")]
public class UserController : ControllerBase
{
private readonly ApplicationDbContext _context;

/// <summary>
/// Initializes a new instance of the UserController.
/// </summary>
/// <param name="context">Database context for accessing user and transaction data.</param>
public UserController(ApplicationDbContext context)
{
_context = context;
}

/// <summary>
/// Retrieves all users with basic information (ID and username only).
/// </summary>
[HttpGet]
public IActionResult GetUsers()
{
// Query all users and project to basic UserDTO
var users = _context.Users.Select(u => new UserDTO()
{
Id = u.Id,
Username = u.Username
});

// Note: This null check is unnecessary as LINQ Select never returns null
if (users == null)
{
return BadRequest();
}
else
{
return Ok(users);
}
}

/// <summary>
/// Retrieves detailed user information including complete investment portfolio with financial calculations.
/// </summary>
/// <param name="id">The unique identifier of the user to retrieve.</param>
[HttpGet]
[Route("{id}")]
public IActionResult GetUser(int id)
{
// Query specific user with transactions, calculate financial metrics in projection
var user = _context.Users.Include("Transactions").Where(u => u.Id == id).Select(u => new UserDTO()
{
Id = u.Id,
Username = u.Username,
Transactions = u.Transactions.Select(t => new TransactionDetailsDTO()
{
Id = t.Id,
Name = t.Name,
Shares = t.Quantity,
TransactionTime = t.TransactionTime,
CostBasisPerShare = t.SharePriceAtPurchase,
CurrentValue = t.CurrentSharePrice * t.Quantity,
CurrentPrice = t.CurrentSharePrice,
TotalGain = (t.CurrentSharePrice * t.Quantity) - (t.SharePriceAtPurchase * t.Quantity)
}).ToList()
}).FirstOrDefault();

// return bad request if user not found
if (user == null)
{
return BadRequest();
}
else
{
return Ok(user);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace InvestmentPerformanceWebAPI.DataTransferObjects
{
public class TransactionDTO
{
public int Id { get; set; }
public string Name { get; set; } // e.g., "Microsoft"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace InvestmentPerformanceWebAPI.DataTransferObjects
{
public class TransactionDetailsDTO : TransactionDTO
{
public DateTime TransactionTime { get; set; }
public int Shares { get; set; }
public string Term
{
get
{
return TransactionTime >= DateTime.UtcNow.AddYears(-1) ? "Short-Term" : "Long-Term";
}
}
public double CostBasisPerShare { get; set; }

public double CurrentValue {get; set;}

public double CurrentPrice { get; set; }

public double TotalGain { get; set; }
}
}
10 changes: 10 additions & 0 deletions InvestmentPerformanceWebAPI/DataTransferObjects/UserDTO.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace InvestmentPerformanceWebAPI.DataTransferObjects
{
public class UserDTO
{
public int Id { get; set; }
public string Username { get; set; }

public ICollection<TransactionDetailsDTO> Transactions { get; set; } = new List<TransactionDetailsDTO>();
}
}
24 changes: 24 additions & 0 deletions InvestmentPerformanceWebAPI/Database Models/Transaction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System.ComponentModel.DataAnnotations.Schema;

namespace InvestmentPerformanceWebAPI.Models
{
public class Transaction
{
public int Id { get; set; }
public TransactionType Type { get; set; }
public string Name { get; set; } // e.g., "Microsoft"
public string Symbol { get; set; } // e.g., "IBM"
public int Quantity { get; set; }
public double SharePriceAtPurchase { get; set; }
public double CurrentSharePrice { get; set; }
public DateTime TransactionTime { get; set; }
[ForeignKey("User")]
public int UserId { get; set; } // Foreign key to User
}

public enum TransactionType
{
Buy,
Sell
}
}
Loading