Skip to content

Commit 72a6d30

Browse files
authored
603 add bookstore webappexample (#610)
* Created API fore Singup and Login * added bookstore simulator * Added oreders repository, controller and test steps logic * Cosmetic chenges * uncomit main example * Chenged books controller * cosmetic changes * cosmetic changes * cosmetic changes * cosmetic changes * last cosmetic changes
1 parent 1843255 commit 72a6d30

File tree

109 files changed

+75782
-7
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

109 files changed

+75782
-7
lines changed

NBomber.sln

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSharpProd", "examples\CSha
1515
EndProject
1616
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "xUnitExample", "examples\xUnitExample\xUnitExample.csproj", "{062DD1FF-B466-4F40-BE1F-8D85EA3BDB6A}"
1717
EndProject
18-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebAppSimulator", "examples\WebAppSimulator\WebAppSimulator.csproj", "{37D936ED-619C-47F8-95BD-63B966590A15}"
18+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebAppSimulator", "examples\WebAppSimulator\WebAppSimulator.csproj", "{37D936ED-619C-47F8-95BD-63B966590A15}"
19+
EndProject
20+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BookstoreSimulator", "examples\BookstoreSimulator\BookstoreSimulator.csproj", "{9BC9E01E-C12A-45D6-9910-B0642F36338B}"
1921
EndProject
2022
Global
2123
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -99,6 +101,18 @@ Global
99101
{37D936ED-619C-47F8-95BD-63B966590A15}.Release|x64.Build.0 = Release|Any CPU
100102
{37D936ED-619C-47F8-95BD-63B966590A15}.Release|x86.ActiveCfg = Release|Any CPU
101103
{37D936ED-619C-47F8-95BD-63B966590A15}.Release|x86.Build.0 = Release|Any CPU
104+
{9BC9E01E-C12A-45D6-9910-B0642F36338B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
105+
{9BC9E01E-C12A-45D6-9910-B0642F36338B}.Debug|Any CPU.Build.0 = Debug|Any CPU
106+
{9BC9E01E-C12A-45D6-9910-B0642F36338B}.Debug|x64.ActiveCfg = Debug|Any CPU
107+
{9BC9E01E-C12A-45D6-9910-B0642F36338B}.Debug|x64.Build.0 = Debug|Any CPU
108+
{9BC9E01E-C12A-45D6-9910-B0642F36338B}.Debug|x86.ActiveCfg = Debug|Any CPU
109+
{9BC9E01E-C12A-45D6-9910-B0642F36338B}.Debug|x86.Build.0 = Debug|Any CPU
110+
{9BC9E01E-C12A-45D6-9910-B0642F36338B}.Release|Any CPU.ActiveCfg = Release|Any CPU
111+
{9BC9E01E-C12A-45D6-9910-B0642F36338B}.Release|Any CPU.Build.0 = Release|Any CPU
112+
{9BC9E01E-C12A-45D6-9910-B0642F36338B}.Release|x64.ActiveCfg = Release|Any CPU
113+
{9BC9E01E-C12A-45D6-9910-B0642F36338B}.Release|x64.Build.0 = Release|Any CPU
114+
{9BC9E01E-C12A-45D6-9910-B0642F36338B}.Release|x86.ActiveCfg = Release|Any CPU
115+
{9BC9E01E-C12A-45D6-9910-B0642F36338B}.Release|x86.Build.0 = Release|Any CPU
102116
EndGlobalSection
103117
GlobalSection(SolutionProperties) = preSolution
104118
HideSolutionNode = FALSE
@@ -108,6 +122,7 @@ Global
108122
{657861BD-19DA-4B93-937D-88B5C25E6D87} = {10398A75-959D-4271-913A-BE99E4ED5744}
109123
{062DD1FF-B466-4F40-BE1F-8D85EA3BDB6A} = {10398A75-959D-4271-913A-BE99E4ED5744}
110124
{37D936ED-619C-47F8-95BD-63B966590A15} = {10398A75-959D-4271-913A-BE99E4ED5744}
125+
{9BC9E01E-C12A-45D6-9910-B0642F36338B} = {10398A75-959D-4271-913A-BE99E4ED5744}
111126
EndGlobalSection
112127
GlobalSection(ExtensibilityGlobals) = postSolution
113128
SolutionGuid = {C7E9329B-84FE-436E-8A44-26D8176C5C6F}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net7.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<Content Remove="wwwroot\Response.cs" />
11+
</ItemGroup>
12+
13+
<ItemGroup>
14+
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.9" />
15+
<PackageReference Include="Serilog.AspNetCore" Version="7.0.0" />
16+
<PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="6.5.0" />
17+
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.5.0" />
18+
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.5.0" />
19+
<PackageReference Include="Npgsql" Version="7.0.4" />
20+
<PackageReference Include="FluentValidation" Version="11.6.0" />
21+
<PackageReference Include="Dapper.Contrib" Version="2.0.78" />
22+
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
23+
</ItemGroup>
24+
25+
</Project>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using FluentValidation;
2+
3+
namespace BookstoreSimulator.Contracts
4+
{
5+
public class BookRequest
6+
{
7+
public string Title { get; set; }
8+
public string Author { get; set; }
9+
public DateTime PublicationDate { get; set; }
10+
public int Quantaty { get; set; } = 0;
11+
}
12+
13+
public class BookRequestValidator: AbstractValidator<BookRequest>
14+
{
15+
public BookRequestValidator()
16+
{
17+
RuleFor(book => book.Title).NotEmpty().WithMessage("Book title cannot be empty");
18+
RuleFor(book => book.Author).NotEmpty().WithMessage("Book author cannot be empty");
19+
20+
RuleFor(book => book.PublicationDate)
21+
.NotEmpty().WithMessage("Book publication date cannot be empty")
22+
.LessThan(DateTime.UtcNow).WithMessage("Book publication date cannot be more than today");
23+
}
24+
}
25+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using FluentValidation;
2+
3+
namespace BookstoreSimulator.Contracts
4+
{
5+
public class LoginUserRequest
6+
{
7+
public string Email { get; set; }
8+
public string Password { get; set; }
9+
}
10+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace BookstoreSimulator.Contracts
2+
{
3+
public class OrderRequest
4+
{
5+
public Guid BookId { get; set; }
6+
public int Quantaty { get; set; }
7+
}
8+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace BookstoreSimulator.Contracts
2+
{
3+
public class Response<T>
4+
{
5+
public T Data { get; private set; }
6+
public Response(T data)
7+
{
8+
Data = data;
9+
}
10+
}
11+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using FluentValidation;
2+
3+
namespace BookstoreSimulator.Contracts
4+
{
5+
public class SingUpUserRequest
6+
{
7+
public string FirstName { get; set; }
8+
public string LastName { get; set; }
9+
public string Email { get; set; }
10+
public string Password { get; set; }
11+
}
12+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using BookstoreSimulator.Contracts;
2+
using BookstoreSimulator.Infra.DAL;
3+
using Microsoft.AspNetCore.Authorization;
4+
using Microsoft.AspNetCore.Mvc;
5+
6+
namespace BookstoreSimulator.Controllers
7+
{
8+
[Route("api/[controller]")]
9+
[ApiController]
10+
public class BooksController : ControllerBase
11+
{
12+
private readonly BookRequestValidator _bookRequestValidator;
13+
private readonly BookRepository _bookRepository;
14+
15+
public BooksController(BookRepository bookRepository, BookRequestValidator bookRequestValidator)
16+
{
17+
_bookRepository = bookRepository;
18+
_bookRequestValidator = bookRequestValidator;
19+
}
20+
21+
[AllowAnonymous]
22+
[HttpPost]
23+
public async Task<IResult> CreateBook([FromBody] BookRequest request)
24+
{
25+
var validationResult = _bookRequestValidator.Validate(request);
26+
if (validationResult.IsValid)
27+
{
28+
var bookId = Guid.NewGuid();
29+
var book = BookDBRecord.Create(request, bookId);
30+
var insertedResult = await _bookRepository.InsertBook(book);
31+
if (insertedResult)
32+
return Results.Ok();
33+
else
34+
return Results.StatusCode(StatusCodes.Status500InternalServerError);
35+
}
36+
else
37+
return Results.ValidationProblem(validationResult.ToDictionary());
38+
}
39+
40+
[Authorize]
41+
[HttpGet]
42+
public async Task<IResult> Get(bool availableOnly = true)
43+
{
44+
var books = await _bookRepository.Get(availableOnly);
45+
if (books.Count > 0)
46+
{
47+
var data = new Response<List<BookDBRecord>>(books);
48+
return Results.Ok(data);
49+
}
50+
else
51+
return Results.StatusCode(StatusCodes.Status204NoContent);
52+
}
53+
}
54+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using BookstoreSimulator.Infra.DAL;
3+
using Microsoft.AspNetCore.Authorization;
4+
5+
namespace BookstoreSimulator.Controllers
6+
{
7+
[Route("api/[controller]")]
8+
[ApiController]
9+
public class DatabasesController : ControllerBase
10+
{
11+
private readonly DB _db;
12+
13+
public DatabasesController(DB db)
14+
{
15+
_db = db;
16+
}
17+
18+
[AllowAnonymous]
19+
[HttpPut]
20+
public async Task PreparedDB()
21+
{
22+
_db.CleanTables();
23+
_db.CreateTables();
24+
}
25+
}
26+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
using BookstoreSimulator.Contracts;
2+
using BookstoreSimulator.Infra;
3+
using BookstoreSimulator.Infra.DAL;
4+
using Microsoft.AspNetCore.Authorization;
5+
using Microsoft.AspNetCore.Mvc;
6+
using System.Reflection.PortableExecutable;
7+
8+
namespace BookstoreSimulator.Controllers
9+
{
10+
[Route("api/[controller]")]
11+
[ApiController]
12+
public class OrdersController : ControllerBase
13+
{
14+
private readonly OrderRepository _repository;
15+
16+
public OrdersController(OrderRepository repository)
17+
{
18+
_repository = repository;
19+
}
20+
21+
[Authorize]
22+
[HttpPost]
23+
public async Task<IResult> CreateOrder([FromBody] OrderRequest request)
24+
{
25+
var userId = ExtractUserId(this.HttpContext.Request.Headers);
26+
27+
if (userId != null)
28+
{
29+
var order = new OrderDBRecord(request, userId.Value);
30+
31+
var createdOrder = await _repository.CreateOrder(order);
32+
33+
if (createdOrder)
34+
return Results.StatusCode(StatusCodes.Status200OK);
35+
else
36+
return Results.StatusCode(StatusCodes.Status409Conflict);
37+
}
38+
else
39+
return Results.StatusCode(StatusCodes.Status400BadRequest);
40+
}
41+
42+
private Guid? ExtractUserId(IHeaderDictionary headers)
43+
{
44+
Microsoft.Extensions.Primitives.StringValues jwtToken;
45+
46+
if (headers.TryGetValue("Authorization", out jwtToken))
47+
{
48+
var token = jwtToken.ToString().Remove(0, "Bearer ".Length);
49+
var userIdString = JwtToken.DecodeJwtToken(token);
50+
Guid userGuid;
51+
if (Guid.TryParse(userIdString, out userGuid))
52+
{
53+
return userGuid;
54+
}
55+
else
56+
return null;
57+
}
58+
else
59+
return null;
60+
}
61+
}
62+
}

0 commit comments

Comments
 (0)