mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-02-16 10:42:08 +00:00
Restructure data access layer/data layer
This commit is contained in:
@@ -9,7 +9,7 @@ namespace DALTests
|
|||||||
{
|
{
|
||||||
public class UserAccountRepositoryTests
|
public class UserAccountRepositoryTests
|
||||||
{
|
{
|
||||||
private readonly UserAccountRepository _repository;
|
private readonly IUserAccountRepository _repository;
|
||||||
|
|
||||||
public UserAccountRepositoryTests()
|
public UserAccountRepositoryTests()
|
||||||
{
|
{
|
||||||
|
|||||||
13
DataAccessLayer/Repositories/IUserAccountRepository.cs
Normal file
13
DataAccessLayer/Repositories/IUserAccountRepository.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using DataAccessLayer.Entities;
|
||||||
|
|
||||||
|
namespace DataAccessLayer
|
||||||
|
{
|
||||||
|
public interface IUserAccountRepository : IRepository<UserAccount>
|
||||||
|
{
|
||||||
|
IEnumerable<UserAccount> GetAll();
|
||||||
|
UserAccount? GetByUsername(string username);
|
||||||
|
UserAccount? GetByEmail(string email);
|
||||||
|
}
|
||||||
|
}
|
||||||
163
DataAccessLayer/Repositories/UserAccountRepository.cs
Normal file
163
DataAccessLayer/Repositories/UserAccountRepository.cs
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using DataAccessLayer.Entities;
|
||||||
|
using Microsoft.Data.SqlClient;
|
||||||
|
|
||||||
|
namespace DataAccessLayer
|
||||||
|
{
|
||||||
|
public class UserAccountRepository : IUserAccountRepository
|
||||||
|
{
|
||||||
|
private readonly string _connectionString;
|
||||||
|
public UserAccountRepository()
|
||||||
|
{
|
||||||
|
// Retrieve the connection string from environment variables
|
||||||
|
_connectionString =
|
||||||
|
Environment.GetEnvironmentVariable("DB_CONNECTION_STRING")
|
||||||
|
?? throw new InvalidOperationException(
|
||||||
|
"The connection string is not set in the environment variables."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(UserAccount userAccount)
|
||||||
|
{
|
||||||
|
using SqlConnection connection = new(_connectionString);
|
||||||
|
using SqlCommand command = new("usp_CreateUserAccount", connection);
|
||||||
|
command.CommandType = System.Data.CommandType.StoredProcedure;
|
||||||
|
AddUserAccountCreateParameters(command, userAccount);
|
||||||
|
connection.Open();
|
||||||
|
command.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserAccount? GetById(Guid id)
|
||||||
|
{
|
||||||
|
using SqlConnection connection = new(_connectionString);
|
||||||
|
using SqlCommand command = new(
|
||||||
|
"usp_GetUserAccountById",
|
||||||
|
connection
|
||||||
|
);
|
||||||
|
command.CommandType = System.Data.CommandType.StoredProcedure;
|
||||||
|
command.Parameters.AddWithValue("@UserAccountId", id);
|
||||||
|
connection.Open();
|
||||||
|
|
||||||
|
using SqlDataReader reader = command.ExecuteReader();
|
||||||
|
return reader.Read() ? MapUserAccount(reader) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(UserAccount userAccount)
|
||||||
|
{
|
||||||
|
using SqlConnection connection = new(_connectionString);
|
||||||
|
using SqlCommand command = new("usp_UpdateUserAccount", connection);
|
||||||
|
command.CommandType = System.Data.CommandType.StoredProcedure;
|
||||||
|
AddUserAccountUpdateParameters(command, userAccount);
|
||||||
|
connection.Open();
|
||||||
|
command.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Delete(Guid id)
|
||||||
|
{
|
||||||
|
using SqlConnection connection = new(_connectionString);
|
||||||
|
using SqlCommand command = new(
|
||||||
|
"usp_DeleteUserAccount",
|
||||||
|
connection
|
||||||
|
);
|
||||||
|
command.CommandType = System.Data.CommandType.StoredProcedure;
|
||||||
|
command.Parameters.AddWithValue("@UserAccountId", id);
|
||||||
|
connection.Open();
|
||||||
|
command.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<UserAccount> GetAll()
|
||||||
|
{
|
||||||
|
using SqlConnection connection = new(_connectionString);
|
||||||
|
using SqlCommand command = new(
|
||||||
|
"usp_GetAllUserAccounts",
|
||||||
|
connection
|
||||||
|
);
|
||||||
|
command.CommandType = System.Data.CommandType.StoredProcedure;
|
||||||
|
connection.Open();
|
||||||
|
|
||||||
|
using SqlDataReader reader = command.ExecuteReader();
|
||||||
|
List<UserAccount> users = new();
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
users.Add(MapUserAccount(reader));
|
||||||
|
}
|
||||||
|
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserAccount? GetByUsername(string username)
|
||||||
|
{
|
||||||
|
using SqlConnection connection = new(_connectionString);
|
||||||
|
using SqlCommand command = new(
|
||||||
|
"usp_GetUserAccountByUsername",
|
||||||
|
connection
|
||||||
|
);
|
||||||
|
command.CommandType = System.Data.CommandType.StoredProcedure;
|
||||||
|
command.Parameters.AddWithValue("@Username", username);
|
||||||
|
connection.Open();
|
||||||
|
|
||||||
|
using SqlDataReader reader = command.ExecuteReader();
|
||||||
|
return reader.Read() ? MapUserAccount(reader) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserAccount? GetByEmail(string email)
|
||||||
|
{
|
||||||
|
using SqlConnection connection = new(_connectionString);
|
||||||
|
using SqlCommand command = new(
|
||||||
|
"usp_GetUserAccountByEmail",
|
||||||
|
connection
|
||||||
|
);
|
||||||
|
command.CommandType = System.Data.CommandType.StoredProcedure;
|
||||||
|
command.Parameters.AddWithValue("@Email", email);
|
||||||
|
connection.Open();
|
||||||
|
|
||||||
|
using SqlDataReader reader = command.ExecuteReader();
|
||||||
|
return reader.Read() ? MapUserAccount(reader) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddUserAccountCreateParameters(
|
||||||
|
SqlCommand command,
|
||||||
|
UserAccount userAccount
|
||||||
|
)
|
||||||
|
{
|
||||||
|
command.Parameters.AddWithValue(
|
||||||
|
"@UserAccountId",
|
||||||
|
userAccount.UserAccountID
|
||||||
|
);
|
||||||
|
command.Parameters.AddWithValue("@Username", userAccount.Username);
|
||||||
|
command.Parameters.AddWithValue("@FirstName", userAccount.FirstName);
|
||||||
|
command.Parameters.AddWithValue("@LastName", userAccount.LastName);
|
||||||
|
command.Parameters.AddWithValue("@Email", userAccount.Email);
|
||||||
|
command.Parameters.AddWithValue("@DateOfBirth", userAccount.DateOfBirth);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddUserAccountUpdateParameters(
|
||||||
|
SqlCommand command,
|
||||||
|
UserAccount userAccount
|
||||||
|
)
|
||||||
|
{
|
||||||
|
AddUserAccountCreateParameters(command, userAccount);
|
||||||
|
command.Parameters.AddWithValue(
|
||||||
|
"@UserAccountId",
|
||||||
|
userAccount.UserAccountID
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static UserAccount MapUserAccount(SqlDataReader reader)
|
||||||
|
{
|
||||||
|
return new UserAccount
|
||||||
|
{
|
||||||
|
UserAccountID = reader.GetGuid(0),
|
||||||
|
Username = reader.GetString(1),
|
||||||
|
FirstName = reader.GetString(2),
|
||||||
|
LastName = reader.GetString(3),
|
||||||
|
Email = reader.GetString(4),
|
||||||
|
CreatedAt = reader.GetDateTime(5),
|
||||||
|
UpdatedAt = reader.IsDBNull(6) ? null : reader.GetDateTime(6),
|
||||||
|
DateOfBirth = reader.GetDateTime(7),
|
||||||
|
Timer = reader.IsDBNull(8) ? null : (byte[])reader[8],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
using System.Data;
|
using System.Data;
|
||||||
using Microsoft.Data.SqlClient;
|
using Microsoft.Data.SqlClient;
|
||||||
|
|
||||||
namespace DataAccessLayer
|
namespace DataAccessLayer.Sql
|
||||||
{
|
{
|
||||||
public class DatabaseHelper
|
public class DatabaseHelper
|
||||||
{
|
{
|
||||||
@@ -3,6 +3,7 @@ GO
|
|||||||
|
|
||||||
CREATE OR ALTER PROCEDURE usp_CreateUserAccount
|
CREATE OR ALTER PROCEDURE usp_CreateUserAccount
|
||||||
(
|
(
|
||||||
|
@UserAccountId UNIQUEIDENTIFIER = NULL,
|
||||||
@Username VARCHAR(64),
|
@Username VARCHAR(64),
|
||||||
@FirstName NVARCHAR(128),
|
@FirstName NVARCHAR(128),
|
||||||
@LastName NVARCHAR(128),
|
@LastName NVARCHAR(128),
|
||||||
@@ -17,6 +18,7 @@ BEGIN
|
|||||||
|
|
||||||
INSERT INTO UserAccount
|
INSERT INTO UserAccount
|
||||||
(
|
(
|
||||||
|
UserAccountID,
|
||||||
Username,
|
Username,
|
||||||
FirstName,
|
FirstName,
|
||||||
LastName,
|
LastName,
|
||||||
@@ -25,6 +27,7 @@ BEGIN
|
|||||||
)
|
)
|
||||||
VALUES
|
VALUES
|
||||||
(
|
(
|
||||||
|
COALESCE(@UserAccountId, NEWID()),
|
||||||
@Username,
|
@Username,
|
||||||
@FirstName,
|
@FirstName,
|
||||||
@LastName,
|
@LastName,
|
||||||
@@ -40,7 +43,7 @@ GO
|
|||||||
|
|
||||||
CREATE OR ALTER PROCEDURE usp_DeleteUserAccount
|
CREATE OR ALTER PROCEDURE usp_DeleteUserAccount
|
||||||
(
|
(
|
||||||
@UserAccountId INT
|
@UserAccountId UNIQUEIDENTIFIER
|
||||||
)
|
)
|
||||||
AS
|
AS
|
||||||
BEGIN
|
BEGIN
|
||||||
@@ -70,7 +73,7 @@ CREATE OR ALTER PROCEDURE usp_UpdateUserAccount
|
|||||||
@LastName NVARCHAR(128),
|
@LastName NVARCHAR(128),
|
||||||
@DateOfBirth DATETIME,
|
@DateOfBirth DATETIME,
|
||||||
@Email VARCHAR(128),
|
@Email VARCHAR(128),
|
||||||
@UserAccountId GUID
|
@UserAccountId UNIQUEIDENTIFIER
|
||||||
)
|
)
|
||||||
AS
|
AS
|
||||||
BEGIN
|
BEGIN
|
||||||
@@ -98,3 +101,87 @@ BEGIN
|
|||||||
COMMIT TRANSACTION
|
COMMIT TRANSACTION
|
||||||
END;
|
END;
|
||||||
GO
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE usp_GetUserAccountById
|
||||||
|
(
|
||||||
|
@UserAccountId UNIQUEIDENTIFIER
|
||||||
|
)
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
SELECT UserAccountID,
|
||||||
|
Username,
|
||||||
|
FirstName,
|
||||||
|
LastName,
|
||||||
|
Email,
|
||||||
|
CreatedAt,
|
||||||
|
UpdatedAt,
|
||||||
|
DateOfBirth,
|
||||||
|
Timer
|
||||||
|
FROM dbo.UserAccount
|
||||||
|
WHERE UserAccountID = @UserAccountId;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE usp_GetAllUserAccounts
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
SELECT UserAccountID,
|
||||||
|
Username,
|
||||||
|
FirstName,
|
||||||
|
LastName,
|
||||||
|
Email,
|
||||||
|
CreatedAt,
|
||||||
|
UpdatedAt,
|
||||||
|
DateOfBirth,
|
||||||
|
Timer
|
||||||
|
FROM dbo.UserAccount;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE usp_GetUserAccountByUsername
|
||||||
|
(
|
||||||
|
@Username VARCHAR(64)
|
||||||
|
)
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
SELECT UserAccountID,
|
||||||
|
Username,
|
||||||
|
FirstName,
|
||||||
|
LastName,
|
||||||
|
Email,
|
||||||
|
CreatedAt,
|
||||||
|
UpdatedAt,
|
||||||
|
DateOfBirth,
|
||||||
|
Timer
|
||||||
|
FROM dbo.UserAccount
|
||||||
|
WHERE Username = @Username;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE usp_GetUserAccountByEmail
|
||||||
|
(
|
||||||
|
@Email VARCHAR(128)
|
||||||
|
)
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
SELECT UserAccountID,
|
||||||
|
Username,
|
||||||
|
FirstName,
|
||||||
|
LastName,
|
||||||
|
Email,
|
||||||
|
CreatedAt,
|
||||||
|
UpdatedAt,
|
||||||
|
DateOfBirth,
|
||||||
|
Timer
|
||||||
|
FROM dbo.UserAccount
|
||||||
|
WHERE Email = @Email;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Data;
|
|
||||||
using DataAccessLayer.Entities;
|
|
||||||
using Microsoft.Data.SqlClient;
|
|
||||||
|
|
||||||
namespace DataAccessLayer
|
|
||||||
{
|
|
||||||
public class UserAccountRepository : IRepository<UserAccount>
|
|
||||||
{
|
|
||||||
private readonly string _connectionString;
|
|
||||||
|
|
||||||
public UserAccountRepository()
|
|
||||||
{
|
|
||||||
// Retrieve the connection string from environment variables
|
|
||||||
_connectionString =
|
|
||||||
Environment.GetEnvironmentVariable("DB_CONNECTION_STRING")
|
|
||||||
?? throw new InvalidOperationException(
|
|
||||||
"The connection string is not set in the environment variables."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(UserAccount userAccount)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserAccount? GetById(Guid id)
|
|
||||||
{
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Update(UserAccount userAccount)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Delete(Guid id)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<UserAccount> GetAll()
|
|
||||||
{
|
|
||||||
return new List<UserAccount>
|
|
||||||
{
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
51
README.md
Normal file
51
README.md
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
# Biergarten SQL Server - Architecture Overview
|
||||||
|
|
||||||
|
This solution is a monolith-oriented Web API with a layered structure. The current focus is a SQL Server-backed data layer with stored procedures and a repository-based DAL.
|
||||||
|
|
||||||
|
## High-level projects
|
||||||
|
|
||||||
|
- `WebAPI/` - ASP.NET Core API endpoints (controllers) and application entrypoint.
|
||||||
|
- `BusinessLayer/` - Intended home for domain/business logic (currently minimal).
|
||||||
|
- `DataAccessLayer/` - Repository implementations, entities (POCOs), and SQL helpers.
|
||||||
|
- `DataLayer/` - Database schema, seed scripts, and data sources.
|
||||||
|
- `WebCrawler/` - Separate crawler executable.
|
||||||
|
- `DALTests/` - Data access tests.
|
||||||
|
|
||||||
|
## Data access architecture
|
||||||
|
|
||||||
|
- **Entities (POCOs)** live in `DataAccessLayer/Entities/`.
|
||||||
|
- **Repositories** live in `DataAccessLayer/Repositories/` and implement interfaces like `IUserAccountRepository`.
|
||||||
|
- **SQL execution** lives in `DataAccessLayer/Sql/`.
|
||||||
|
- **Stored procedures** for CRUD live under `DataAccessLayer/Sql/crud/` and are invoked by repositories.
|
||||||
|
|
||||||
|
Example flow:
|
||||||
|
|
||||||
|
```
|
||||||
|
WebAPI Controller -> IUserAccountRepository -> UserAccountRepository -> stored procedure
|
||||||
|
```
|
||||||
|
|
||||||
|
The repositories are currently responsible for:
|
||||||
|
- Opening connections using `DB_CONNECTION_STRING`
|
||||||
|
- Executing stored procedures
|
||||||
|
- Mapping result sets to POCOs
|
||||||
|
|
||||||
|
## Database schema and seed
|
||||||
|
|
||||||
|
- `DataLayer/schema.sql` contains the database schema definitions.
|
||||||
|
- `DataLayer/seed/SeedDB.cs` provides seeding and stored procedure/function loading.
|
||||||
|
- Stored procedure scripts are organized under `DataAccessLayer/Sql/crud/` (UserAccount and related).
|
||||||
|
|
||||||
|
## Key conventions
|
||||||
|
|
||||||
|
- **Environment variables**: `DB_CONNECTION_STRING` is required for DAL and seed tooling.
|
||||||
|
- **Stored procedures**: CRUD operations use `usp_*` procedures.
|
||||||
|
- **Rowversion** columns are represented as `byte[]` in entities (e.g., `Timer`).
|
||||||
|
|
||||||
|
## Suggested dependency direction
|
||||||
|
|
||||||
|
```
|
||||||
|
WebAPI -> BusinessLayer -> DataAccessLayer -> SQL Server
|
||||||
|
-> DataLayer (schema/seed/scripts)
|
||||||
|
```
|
||||||
|
|
||||||
|
Keep business logic in `BusinessLayer` and avoid direct SQL or ADO code outside `DataAccessLayer`.
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
|
|
||||||
namespace WebAPI.Controllers
|
|
||||||
{
|
|
||||||
[ApiController]
|
|
||||||
[Route("api/beers")]
|
|
||||||
public class BeersController : ControllerBase
|
|
||||||
{
|
|
||||||
[HttpGet]
|
|
||||||
public IActionResult GetBeers([FromQuery] int page_num, [FromQuery] int page_size)
|
|
||||||
{
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("search")]
|
|
||||||
public IActionResult SearchBeers([FromQuery] string search)
|
|
||||||
{
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("styles")]
|
|
||||||
public IActionResult GetBeerStyles([FromQuery] int page_num, [FromQuery] int page_size)
|
|
||||||
{
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost("styles/create")]
|
|
||||||
public IActionResult CreateBeerStyle([FromBody] BeerStyleCreateRequest request)
|
|
||||||
{
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPut("{postId}")]
|
|
||||||
public IActionResult EditBeer(string postId, [FromBody] BeerEditRequest request)
|
|
||||||
{
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpDelete("{postId}")]
|
|
||||||
public IActionResult DeleteBeer(string postId)
|
|
||||||
{
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{postId}/recommendations")]
|
|
||||||
public IActionResult GetBeerRecommendations([FromQuery] int page_num, [FromQuery] int page_size, string postId)
|
|
||||||
{
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost("{postId}/comments")]
|
|
||||||
public IActionResult AddBeerComment(string postId, [FromBody] BeerCommentRequest request)
|
|
||||||
{
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{postId}/comments")]
|
|
||||||
public IActionResult GetBeerComments([FromQuery] int page_num, [FromQuery] int page_size, string postId)
|
|
||||||
{
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPut("{postId}/comments/{commentId}")]
|
|
||||||
public IActionResult EditBeerComment(string postId, string commentId, [FromBody] BeerCommentRequest request)
|
|
||||||
{
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpDelete("{postId}/comments/{commentId}")]
|
|
||||||
public IActionResult DeleteBeerComment(string postId, string commentId)
|
|
||||||
{
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
|
|
||||||
namespace WebAPI.Controllers
|
|
||||||
{
|
|
||||||
[ApiController]
|
|
||||||
[Route("api/breweries")]
|
|
||||||
public class BreweriesController : ControllerBase
|
|
||||||
{
|
|
||||||
[HttpGet]
|
|
||||||
public IActionResult GetBreweries([FromQuery] int page_num, [FromQuery] int page_size)
|
|
||||||
{
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("map")]
|
|
||||||
public IActionResult GetBreweriesMap([FromQuery] int page_num, [FromQuery] int page_size)
|
|
||||||
{
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPut("{postId}")]
|
|
||||||
public IActionResult EditBrewery(string postId, [FromBody] BreweryEditRequest request)
|
|
||||||
{
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpDelete("{postId}")]
|
|
||||||
public IActionResult DeleteBrewery(string postId)
|
|
||||||
{
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost("{postId}/comments")]
|
|
||||||
public IActionResult AddBreweryComment(string postId, [FromBody] BreweryCommentRequest request)
|
|
||||||
{
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{postId}/comments")]
|
|
||||||
public IActionResult GetBreweryComments([FromQuery] int page_num, [FromQuery] int page_size, string postId)
|
|
||||||
{
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPut("{postId}/comments/{commentId}")]
|
|
||||||
public IActionResult EditBreweryComment(string postId, string commentId, [FromBody] BreweryCommentRequest request)
|
|
||||||
{
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpDelete("{postId}/comments/{commentId}")]
|
|
||||||
public IActionResult DeleteBreweryComment(string postId, string commentId)
|
|
||||||
{
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using DataAccessLayer;
|
using DataAccessLayer;
|
||||||
|
using DataAccessLayer.Entities;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace WebAPI.Controllers
|
namespace WebAPI.Controllers
|
||||||
{
|
{
|
||||||
@@ -7,7 +8,7 @@ namespace WebAPI.Controllers
|
|||||||
[Route("api/users")]
|
[Route("api/users")]
|
||||||
public class UsersController : ControllerBase
|
public class UsersController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly UserAccountRepository _userAccountRepository;
|
private readonly IUserAccountRepository _userAccountRepository;
|
||||||
|
|
||||||
public UsersController()
|
public UsersController()
|
||||||
{
|
{
|
||||||
@@ -15,6 +16,7 @@ namespace WebAPI.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
// all users
|
// all users
|
||||||
|
[HttpGet]
|
||||||
[HttpGet("users")]
|
[HttpGet("users")]
|
||||||
public IActionResult GetAllUsers()
|
public IActionResult GetAllUsers()
|
||||||
{
|
{
|
||||||
@@ -22,5 +24,61 @@ namespace WebAPI.Controllers
|
|||||||
return Ok(users);
|
return Ok(users);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("{id:guid}")]
|
||||||
|
public IActionResult GetUserById(Guid id)
|
||||||
|
{
|
||||||
|
var user = _userAccountRepository.GetById(id);
|
||||||
|
return user is null ? NotFound() : Ok(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("by-username/{username}")]
|
||||||
|
public IActionResult GetUserByUsername(string username)
|
||||||
|
{
|
||||||
|
var user = _userAccountRepository.GetByUsername(username);
|
||||||
|
return user is null ? NotFound() : Ok(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("by-email/{email}")]
|
||||||
|
public IActionResult GetUserByEmail(string email)
|
||||||
|
{
|
||||||
|
var user = _userAccountRepository.GetByEmail(email);
|
||||||
|
return user is null ? NotFound() : Ok(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult CreateUser([FromBody] UserAccount userAccount)
|
||||||
|
{
|
||||||
|
if (userAccount.UserAccountID == Guid.Empty)
|
||||||
|
{
|
||||||
|
userAccount.UserAccountID = Guid.NewGuid();
|
||||||
|
}
|
||||||
|
|
||||||
|
_userAccountRepository.Add(userAccount);
|
||||||
|
return CreatedAtAction(
|
||||||
|
nameof(GetUserById),
|
||||||
|
new { id = userAccount.UserAccountID },
|
||||||
|
userAccount
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPut("{id:guid}")]
|
||||||
|
public IActionResult UpdateUser(Guid id, [FromBody] UserAccount userAccount)
|
||||||
|
{
|
||||||
|
if (userAccount.UserAccountID != Guid.Empty && userAccount.UserAccountID != id)
|
||||||
|
{
|
||||||
|
return BadRequest("UserAccountID does not match route id.");
|
||||||
|
}
|
||||||
|
|
||||||
|
userAccount.UserAccountID = id;
|
||||||
|
_userAccountRepository.Update(userAccount);
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("{id:guid}")]
|
||||||
|
public IActionResult DeleteUser(Guid id)
|
||||||
|
{
|
||||||
|
_userAccountRepository.Delete(id);
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,17 +30,22 @@ catch
|
|||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
// Add services to the container.
|
// Add services to the container.
|
||||||
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
|
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
|
||||||
builder.Services.AddOpenApi();
|
builder.Services.AddControllers();
|
||||||
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
|
builder.Services.AddSwaggerGen();
|
||||||
|
builder.Services.AddOpenApi();
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
// Configure the HTTP request pipeline.
|
||||||
if (app.Environment.IsDevelopment())
|
if (app.Environment.IsDevelopment())
|
||||||
{
|
{
|
||||||
app.MapOpenApi();
|
app.UseSwagger();
|
||||||
}
|
app.UseSwaggerUI();
|
||||||
|
app.MapOpenApi();
|
||||||
|
}
|
||||||
|
|
||||||
app.UseHttpsRedirection();
|
app.UseHttpsRedirection();
|
||||||
|
|
||||||
@@ -58,24 +63,6 @@ var summaries = new[]
|
|||||||
"Scorching",
|
"Scorching",
|
||||||
};
|
};
|
||||||
|
|
||||||
app.MapGet(
|
|
||||||
"/weatherforecast",
|
|
||||||
() =>
|
|
||||||
{
|
|
||||||
var forecast = Enumerable
|
|
||||||
.Range(1, 5)
|
|
||||||
.Select(index => new WeatherForecast(
|
|
||||||
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
|
|
||||||
Random.Shared.Next(-20, 55),
|
|
||||||
summaries[Random.Shared.Next(summaries.Length)]
|
|
||||||
))
|
|
||||||
.ToArray();
|
|
||||||
return forecast;
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.WithName("GetWeatherForecast");
|
|
||||||
|
|
||||||
// Register controllers
|
|
||||||
app.MapControllers();
|
app.MapControllers();
|
||||||
app.Run();
|
app.Run();
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,10 @@
|
|||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.11" />
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.11" />
|
||||||
</ItemGroup>
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="../DataAccessLayer/DataAccessLayer.csproj" />
|
<ProjectReference Include="../DataAccessLayer/DataAccessLayer.csproj" />
|
||||||
|
|||||||
@@ -1,6 +1,64 @@
|
|||||||
@WebAPI_HostAddress = http://localhost:5069
|
@WebAPI_HostAddress = http://localhost:5069
|
||||||
|
|
||||||
GET {{WebAPI_HostAddress}}/weatherforecast/
|
GET {{WebAPI_HostAddress}}/weatherforecast/
|
||||||
Accept: application/json
|
Accept: application/json
|
||||||
|
|
||||||
###
|
###
|
||||||
|
|
||||||
|
GET {{WebAPI_HostAddress}}/api/users
|
||||||
|
Accept: application/json
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
GET {{WebAPI_HostAddress}}/api/users/{{userId}}
|
||||||
|
Accept: application/json
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
GET {{WebAPI_HostAddress}}/api/users/by-username/{{username}}
|
||||||
|
Accept: application/json
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
GET {{WebAPI_HostAddress}}/api/users/by-email/{{email}}
|
||||||
|
Accept: application/json
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
POST {{WebAPI_HostAddress}}/api/users
|
||||||
|
Content-Type: application/json
|
||||||
|
Accept: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"userAccountID": "00000000-0000-0000-0000-000000000000",
|
||||||
|
"username": "testuser",
|
||||||
|
"firstName": "Test",
|
||||||
|
"lastName": "User",
|
||||||
|
"email": "testuser@example.com",
|
||||||
|
"createdAt": "2025-01-01T00:00:00Z",
|
||||||
|
"updatedAt": null,
|
||||||
|
"dateOfBirth": "1990-01-01T00:00:00Z",
|
||||||
|
"timer": null
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
PUT {{WebAPI_HostAddress}}/api/users/{{userId}}
|
||||||
|
Content-Type: application/json
|
||||||
|
Accept: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"userAccountID": "{{userId}}",
|
||||||
|
"username": "testuser",
|
||||||
|
"firstName": "Updated",
|
||||||
|
"lastName": "User",
|
||||||
|
"email": "testuser@example.com",
|
||||||
|
"createdAt": "2025-01-01T00:00:00Z",
|
||||||
|
"updatedAt": "2025-02-01T00:00:00Z",
|
||||||
|
"dateOfBirth": "1990-01-01T00:00:00Z",
|
||||||
|
"timer": null
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
DELETE {{WebAPI_HostAddress}}/api/users/{{userId}}
|
||||||
|
|||||||
@@ -17,40 +17,6 @@ services:
|
|||||||
retries: 12
|
retries: 12
|
||||||
networks:
|
networks:
|
||||||
- devnet
|
- devnet
|
||||||
|
|
||||||
redis:
|
|
||||||
image: redis:7
|
|
||||||
container_name: redis
|
|
||||||
env_file:
|
|
||||||
- .env
|
|
||||||
networks:
|
|
||||||
- devnet
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "redis-cli", "ping"]
|
|
||||||
interval: 10s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
|
|
||||||
dotnet:
|
|
||||||
image: mcr.microsoft.com/dotnet/sdk:10.0
|
|
||||||
container_name: dotnet-sdk
|
|
||||||
tty: true
|
|
||||||
stdin_open: true
|
|
||||||
volumes:
|
|
||||||
- ./:/home/dev/projects
|
|
||||||
- nuget-cache:/home/dev/.nuget/packages
|
|
||||||
- ~/.gitconfig:/home/dev/.gitconfig:ro
|
|
||||||
working_dir: /home/dev/projects
|
|
||||||
environment:
|
|
||||||
DOTNET_CLI_TELEMETRY_OPTOUT: "1"
|
|
||||||
HOME: /home/dev
|
|
||||||
USER: dev
|
|
||||||
DB_CONNECTION_STRING: "Server=sqlserver,1433;User Id=sa;Password=${SA_PASSWORD};Encrypt=True;TrustServerCertificate=True;Connection Timeout=30;Database=${DB_NAME};"
|
|
||||||
REDIS_URL: "${REDIS_URL}"
|
|
||||||
user: root
|
|
||||||
networks:
|
|
||||||
- devnet
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
sqlserverdata:
|
sqlserverdata:
|
||||||
nuget-cache:
|
nuget-cache:
|
||||||
|
|||||||
Reference in New Issue
Block a user