Browse Source
* migrate from classic controller to minimal api * fix all PublicApi integration test * update all nuget package add forget project * fix pay now * Adapt readme use in memory database * undo AuthenticateEndpoint to use EndpointBaseAsync * Update README.md Co-authored-by: Steve Smith <steve@kentsmiths.com> Co-authored-by: Steve Smith <steve@kentsmiths.com>main
committed by
GitHub
63 changed files with 842 additions and 630 deletions
@ -0,0 +1,40 @@ |
|||
using Microsoft.EntityFrameworkCore; |
|||
using Microsoft.eShopWeb.Infrastructure.Data; |
|||
using Microsoft.eShopWeb.Infrastructure.Identity; |
|||
using Microsoft.Extensions.Configuration; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
|
|||
namespace Microsoft.eShopWeb.Infrastructure; |
|||
|
|||
public static class Dependencies |
|||
{ |
|||
public static void ConfigureServices(IConfiguration configuration, IServiceCollection services) |
|||
{ |
|||
var useOnlyInMemoryDatabase = false; |
|||
if (configuration["UseOnlyInMemoryDatabase"] != null) |
|||
{ |
|||
useOnlyInMemoryDatabase = bool.Parse(configuration["UseOnlyInMemoryDatabase"]); |
|||
} |
|||
|
|||
if (useOnlyInMemoryDatabase) |
|||
{ |
|||
services.AddDbContext<CatalogContext>(c => |
|||
c.UseInMemoryDatabase("Catalog")); |
|||
|
|||
services.AddDbContext<AppIdentityDbContext>(options => |
|||
options.UseInMemoryDatabase("Identity")); |
|||
} |
|||
else |
|||
{ |
|||
// use real database
|
|||
// Requires LocalDB which can be installed with SQL Server Express 2016
|
|||
// https://www.microsoft.com/en-us/download/details.aspx?id=54284
|
|||
services.AddDbContext<CatalogContext>(c => |
|||
c.UseSqlServer(configuration.GetConnectionString("CatalogConnection"))); |
|||
|
|||
// Add Identity DbContext
|
|||
services.AddDbContext<AppIdentityDbContext>(options => |
|||
options.UseSqlServer(configuration.GetConnectionString("IdentityConnection"))); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,48 @@ |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using AutoMapper; |
|||
using Microsoft.AspNetCore.Builder; |
|||
using Microsoft.AspNetCore.Http; |
|||
using Microsoft.AspNetCore.Routing; |
|||
using Microsoft.eShopWeb.ApplicationCore.Entities; |
|||
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
|||
using MinimalApi.Endpoint; |
|||
|
|||
namespace Microsoft.eShopWeb.PublicApi.CatalogBrandEndpoints; |
|||
|
|||
/// <summary>
|
|||
/// List Catalog Brands
|
|||
/// </summary>
|
|||
public class CatalogBrandListEndpoint : IEndpoint<IResult> |
|||
{ |
|||
private IRepository<CatalogBrand> _catalogBrandRepository; |
|||
private readonly IMapper _mapper; |
|||
|
|||
public CatalogBrandListEndpoint(IMapper mapper) |
|||
{ |
|||
_mapper = mapper; |
|||
} |
|||
|
|||
public void AddRoute(IEndpointRouteBuilder app) |
|||
{ |
|||
app.MapGet("api/catalog-brands", |
|||
async (IRepository<CatalogBrand> catalogBrandRepository) => |
|||
{ |
|||
_catalogBrandRepository = catalogBrandRepository; |
|||
return await HandleAsync(); |
|||
}) |
|||
.Produces<ListCatalogBrandsResponse>() |
|||
.WithTags("CatalogBrandEndpoints"); |
|||
} |
|||
|
|||
public async Task<IResult> HandleAsync() |
|||
{ |
|||
var response = new ListCatalogBrandsResponse(); |
|||
|
|||
var items = await _catalogBrandRepository.ListAsync(); |
|||
|
|||
response.CatalogBrands.AddRange(items.Select(_mapper.Map<CatalogBrandDto>)); |
|||
|
|||
return Results.Ok(response); |
|||
} |
|||
} |
|||
@ -1,44 +0,0 @@ |
|||
using System.Linq; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Ardalis.ApiEndpoints; |
|||
using AutoMapper; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.eShopWeb.ApplicationCore.Entities; |
|||
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
|||
using Swashbuckle.AspNetCore.Annotations; |
|||
|
|||
namespace Microsoft.eShopWeb.PublicApi.CatalogBrandEndpoints; |
|||
|
|||
public class List : EndpointBaseAsync |
|||
.WithoutRequest |
|||
.WithActionResult<ListCatalogBrandsResponse> |
|||
{ |
|||
private readonly IRepository<CatalogBrand> _catalogBrandRepository; |
|||
private readonly IMapper _mapper; |
|||
|
|||
public List(IRepository<CatalogBrand> catalogBrandRepository, |
|||
IMapper mapper) |
|||
{ |
|||
_catalogBrandRepository = catalogBrandRepository; |
|||
_mapper = mapper; |
|||
} |
|||
|
|||
[HttpGet("api/catalog-brands")] |
|||
[SwaggerOperation( |
|||
Summary = "List Catalog Brands", |
|||
Description = "List Catalog Brands", |
|||
OperationId = "catalog-brands.List", |
|||
Tags = new[] { "CatalogBrandEndpoints" }) |
|||
] |
|||
public override async Task<ActionResult<ListCatalogBrandsResponse>> HandleAsync(CancellationToken cancellationToken) |
|||
{ |
|||
var response = new ListCatalogBrandsResponse(); |
|||
|
|||
var items = await _catalogBrandRepository.ListAsync(cancellationToken); |
|||
|
|||
response.CatalogBrands.AddRange(items.Select(_mapper.Map<CatalogBrandDto>)); |
|||
|
|||
return Ok(response); |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
namespace Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints; |
|||
|
|||
public class GetByIdCatalogItemRequest : BaseRequest |
|||
{ |
|||
public int CatalogItemId { get; init; } |
|||
|
|||
public GetByIdCatalogItemRequest(int catalogItemId) |
|||
{ |
|||
CatalogItemId = catalogItemId; |
|||
} |
|||
} |
|||
@ -0,0 +1,56 @@ |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Builder; |
|||
using Microsoft.AspNetCore.Http; |
|||
using Microsoft.AspNetCore.Routing; |
|||
using Microsoft.eShopWeb.ApplicationCore.Entities; |
|||
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
|||
using MinimalApi.Endpoint; |
|||
|
|||
namespace Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints; |
|||
|
|||
/// <summary>
|
|||
/// Get a Catalog Item by Id
|
|||
/// </summary>
|
|||
public class CatalogItemGetByIdEndpoint : IEndpoint<IResult, GetByIdCatalogItemRequest> |
|||
{ |
|||
private IRepository<CatalogItem> _itemRepository; |
|||
private readonly IUriComposer _uriComposer; |
|||
|
|||
public CatalogItemGetByIdEndpoint(IUriComposer uriComposer) |
|||
{ |
|||
_uriComposer = uriComposer; |
|||
} |
|||
|
|||
public void AddRoute(IEndpointRouteBuilder app) |
|||
{ |
|||
app.MapGet("api/catalog-items/{catalogItemId}", |
|||
async (int catalogItemId, IRepository<CatalogItem> itemRepository) => |
|||
{ |
|||
_itemRepository = itemRepository; |
|||
return await HandleAsync(new GetByIdCatalogItemRequest(catalogItemId)); |
|||
}) |
|||
.Produces<GetByIdCatalogItemResponse>() |
|||
.WithTags("CatalogItemEndpoints"); |
|||
} |
|||
|
|||
public async Task<IResult> HandleAsync(GetByIdCatalogItemRequest request) |
|||
{ |
|||
var response = new GetByIdCatalogItemResponse(request.CorrelationId()); |
|||
|
|||
var item = await _itemRepository.GetByIdAsync(request.CatalogItemId); |
|||
if (item is null) |
|||
return Results.NotFound(); |
|||
|
|||
response.CatalogItem = new CatalogItemDto |
|||
{ |
|||
Id = item.Id, |
|||
CatalogBrandId = item.CatalogBrandId, |
|||
CatalogTypeId = item.CatalogTypeId, |
|||
Description = item.Description, |
|||
Name = item.Name, |
|||
PictureUri = _uriComposer.ComposePicUri(item.PictureUri), |
|||
Price = item.Price |
|||
}; |
|||
return Results.Ok(response); |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
namespace Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints; |
|||
|
|||
public class ListPagedCatalogItemRequest : BaseRequest |
|||
{ |
|||
public int? PageSize { get; init; } |
|||
public int? PageIndex { get; init; } |
|||
public int? CatalogBrandId { get; init; } |
|||
public int? CatalogTypeId { get; init; } |
|||
|
|||
public ListPagedCatalogItemRequest(int? pageSize, int? pageIndex, int? catalogBrandId, int? catalogTypeId) |
|||
{ |
|||
PageSize = pageSize ?? 0; |
|||
PageIndex = pageIndex ?? 0; |
|||
CatalogBrandId = catalogBrandId; |
|||
CatalogTypeId = catalogTypeId; |
|||
} |
|||
} |
|||
@ -1,9 +0,0 @@ |
|||
using Microsoft.AspNetCore.Mvc; |
|||
|
|||
namespace Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints; |
|||
|
|||
public class DeleteCatalogItemRequest : BaseRequest |
|||
{ |
|||
//[FromRoute]
|
|||
public int CatalogItemId { get; set; } |
|||
} |
|||
@ -1,43 +0,0 @@ |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Ardalis.ApiEndpoints; |
|||
using Microsoft.AspNetCore.Authentication.JwtBearer; |
|||
using Microsoft.AspNetCore.Authorization; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.eShopWeb.ApplicationCore.Entities; |
|||
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
|||
using Swashbuckle.AspNetCore.Annotations; |
|||
|
|||
namespace Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints; |
|||
|
|||
[Authorize(Roles = BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS, AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] |
|||
public class Delete : EndpointBaseAsync |
|||
.WithRequest<DeleteCatalogItemRequest> |
|||
.WithActionResult<DeleteCatalogItemResponse> |
|||
{ |
|||
private readonly IRepository<CatalogItem> _itemRepository; |
|||
|
|||
public Delete(IRepository<CatalogItem> itemRepository) |
|||
{ |
|||
_itemRepository = itemRepository; |
|||
} |
|||
|
|||
[HttpDelete("api/catalog-items/{CatalogItemId}")] |
|||
[SwaggerOperation( |
|||
Summary = "Deletes a Catalog Item", |
|||
Description = "Deletes a Catalog Item", |
|||
OperationId = "catalog-items.Delete", |
|||
Tags = new[] { "CatalogItemEndpoints" }) |
|||
] |
|||
public override async Task<ActionResult<DeleteCatalogItemResponse>> HandleAsync([FromRoute] DeleteCatalogItemRequest request, CancellationToken cancellationToken) |
|||
{ |
|||
var response = new DeleteCatalogItemResponse(request.CorrelationId()); |
|||
|
|||
var itemToDelete = await _itemRepository.GetByIdAsync(request.CatalogItemId, cancellationToken); |
|||
if (itemToDelete is null) return NotFound(); |
|||
|
|||
await _itemRepository.DeleteAsync(itemToDelete, cancellationToken); |
|||
|
|||
return Ok(response); |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
namespace Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints; |
|||
|
|||
public class DeleteCatalogItemRequest : BaseRequest |
|||
{ |
|||
public int CatalogItemId { get; init; } |
|||
|
|||
public DeleteCatalogItemRequest(int catalogItemId) |
|||
{ |
|||
CatalogItemId = catalogItemId; |
|||
} |
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Authentication.JwtBearer; |
|||
using Microsoft.AspNetCore.Authorization; |
|||
using Microsoft.AspNetCore.Builder; |
|||
using Microsoft.AspNetCore.Http; |
|||
using Microsoft.AspNetCore.Routing; |
|||
using Microsoft.eShopWeb.ApplicationCore.Entities; |
|||
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
|||
using MinimalApi.Endpoint; |
|||
|
|||
namespace Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints; |
|||
|
|||
/// <summary>
|
|||
/// Deletes a Catalog Item
|
|||
/// </summary>
|
|||
public class DeleteCatalogItemEndpoint : IEndpoint<IResult, DeleteCatalogItemRequest> |
|||
{ |
|||
private IRepository<CatalogItem> _itemRepository; |
|||
|
|||
public void AddRoute(IEndpointRouteBuilder app) |
|||
{ |
|||
app.MapDelete("api/catalog-items/{catalogItemId}", |
|||
[Authorize(Roles = BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS, AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] async |
|||
(int catalogItemId, IRepository<CatalogItem> itemRepository) => |
|||
{ |
|||
_itemRepository = itemRepository; |
|||
return await HandleAsync(new DeleteCatalogItemRequest(catalogItemId)); |
|||
}) |
|||
.Produces<DeleteCatalogItemResponse>() |
|||
.WithTags("CatalogItemEndpoints"); |
|||
} |
|||
|
|||
public async Task<IResult> HandleAsync(DeleteCatalogItemRequest request) |
|||
{ |
|||
var response = new DeleteCatalogItemResponse(request.CorrelationId()); |
|||
|
|||
var itemToDelete = await _itemRepository.GetByIdAsync(request.CatalogItemId); |
|||
if (itemToDelete is null) |
|||
return Results.NotFound(); |
|||
|
|||
await _itemRepository.DeleteAsync(itemToDelete); |
|||
|
|||
return Results.Ok(response); |
|||
} |
|||
} |
|||
@ -1,6 +0,0 @@ |
|||
namespace Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints; |
|||
|
|||
public class GetByIdCatalogItemRequest : BaseRequest |
|||
{ |
|||
public int CatalogItemId { get; set; } |
|||
} |
|||
@ -1,50 +0,0 @@ |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Ardalis.ApiEndpoints; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.eShopWeb.ApplicationCore.Entities; |
|||
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
|||
using Swashbuckle.AspNetCore.Annotations; |
|||
|
|||
namespace Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints; |
|||
|
|||
public class GetById : EndpointBaseAsync |
|||
.WithRequest<GetByIdCatalogItemRequest> |
|||
.WithActionResult<GetByIdCatalogItemResponse> |
|||
{ |
|||
private readonly IRepository<CatalogItem> _itemRepository; |
|||
private readonly IUriComposer _uriComposer; |
|||
|
|||
public GetById(IRepository<CatalogItem> itemRepository, IUriComposer uriComposer) |
|||
{ |
|||
_itemRepository = itemRepository; |
|||
_uriComposer = uriComposer; |
|||
} |
|||
|
|||
[HttpGet("api/catalog-items/{CatalogItemId}")] |
|||
[SwaggerOperation( |
|||
Summary = "Get a Catalog Item by Id", |
|||
Description = "Gets a Catalog Item by Id", |
|||
OperationId = "catalog-items.GetById", |
|||
Tags = new[] { "CatalogItemEndpoints" }) |
|||
] |
|||
public override async Task<ActionResult<GetByIdCatalogItemResponse>> HandleAsync([FromRoute] GetByIdCatalogItemRequest request, CancellationToken cancellationToken) |
|||
{ |
|||
var response = new GetByIdCatalogItemResponse(request.CorrelationId()); |
|||
|
|||
var item = await _itemRepository.GetByIdAsync(request.CatalogItemId, cancellationToken); |
|||
if (item is null) return NotFound(); |
|||
|
|||
response.CatalogItem = new CatalogItemDto |
|||
{ |
|||
Id = item.Id, |
|||
CatalogBrandId = item.CatalogBrandId, |
|||
CatalogTypeId = item.CatalogTypeId, |
|||
Description = item.Description, |
|||
Name = item.Name, |
|||
PictureUri = _uriComposer.ComposePicUri(item.PictureUri), |
|||
Price = item.Price |
|||
}; |
|||
return Ok(response); |
|||
} |
|||
} |
|||
@ -1,9 +0,0 @@ |
|||
namespace Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints; |
|||
|
|||
public class ListPagedCatalogItemRequest : BaseRequest |
|||
{ |
|||
public int PageSize { get; set; } |
|||
public int PageIndex { get; set; } |
|||
public int? CatalogBrandId { get; set; } |
|||
public int? CatalogTypeId { get; set; } |
|||
} |
|||
@ -1,60 +0,0 @@ |
|||
using System.IO; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Ardalis.ApiEndpoints; |
|||
using Microsoft.AspNetCore.Authentication.JwtBearer; |
|||
using Microsoft.AspNetCore.Authorization; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.eShopWeb.ApplicationCore.Entities; |
|||
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
|||
using Swashbuckle.AspNetCore.Annotations; |
|||
|
|||
namespace Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints; |
|||
|
|||
[Authorize(Roles = BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS, AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] |
|||
public class Update : EndpointBaseAsync |
|||
.WithRequest<UpdateCatalogItemRequest> |
|||
.WithActionResult<UpdateCatalogItemResponse> |
|||
{ |
|||
private readonly IRepository<CatalogItem> _itemRepository; |
|||
private readonly IUriComposer _uriComposer; |
|||
|
|||
public Update(IRepository<CatalogItem> itemRepository, IUriComposer uriComposer) |
|||
{ |
|||
_itemRepository = itemRepository; |
|||
_uriComposer = uriComposer; |
|||
} |
|||
|
|||
[HttpPut("api/catalog-items")] |
|||
[SwaggerOperation( |
|||
Summary = "Updates a Catalog Item", |
|||
Description = "Updates a Catalog Item", |
|||
OperationId = "catalog-items.update", |
|||
Tags = new[] { "CatalogItemEndpoints" }) |
|||
] |
|||
public override async Task<ActionResult<UpdateCatalogItemResponse>> HandleAsync(UpdateCatalogItemRequest request, CancellationToken cancellationToken) |
|||
{ |
|||
var response = new UpdateCatalogItemResponse(request.CorrelationId()); |
|||
|
|||
var existingItem = await _itemRepository.GetByIdAsync(request.Id, cancellationToken); |
|||
|
|||
existingItem.UpdateDetails(request.Name, request.Description, request.Price); |
|||
existingItem.UpdateBrand(request.CatalogBrandId); |
|||
existingItem.UpdateType(request.CatalogTypeId); |
|||
|
|||
await _itemRepository.UpdateAsync(existingItem, cancellationToken); |
|||
|
|||
var dto = new CatalogItemDto |
|||
{ |
|||
Id = existingItem.Id, |
|||
CatalogBrandId = existingItem.CatalogBrandId, |
|||
CatalogTypeId = existingItem.CatalogTypeId, |
|||
Description = existingItem.Description, |
|||
Name = existingItem.Name, |
|||
PictureUri = _uriComposer.ComposePicUri(existingItem.PictureUri), |
|||
Price = existingItem.Price |
|||
}; |
|||
response.CatalogItem = dto; |
|||
return response; |
|||
} |
|||
} |
|||
@ -0,0 +1,64 @@ |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Authentication.JwtBearer; |
|||
using Microsoft.AspNetCore.Authorization; |
|||
using Microsoft.AspNetCore.Builder; |
|||
using Microsoft.AspNetCore.Http; |
|||
using Microsoft.AspNetCore.Routing; |
|||
using Microsoft.eShopWeb.ApplicationCore.Entities; |
|||
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
|||
using MinimalApi.Endpoint; |
|||
|
|||
namespace Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints; |
|||
|
|||
/// <summary>
|
|||
/// Updates a Catalog Item
|
|||
/// </summary>
|
|||
public class UpdateCatalogItemEndpoint : IEndpoint<IResult, UpdateCatalogItemRequest> |
|||
{ |
|||
private IRepository<CatalogItem> _itemRepository; |
|||
private readonly IUriComposer _uriComposer; |
|||
|
|||
public UpdateCatalogItemEndpoint(IUriComposer uriComposer) |
|||
{ |
|||
_uriComposer = uriComposer; |
|||
} |
|||
|
|||
public void AddRoute(IEndpointRouteBuilder app) |
|||
{ |
|||
app.MapPut("api/catalog-items", |
|||
[Authorize(Roles = BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS, AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] async |
|||
(UpdateCatalogItemRequest request, IRepository<CatalogItem> itemRepository) => |
|||
{ |
|||
_itemRepository = itemRepository; |
|||
return await HandleAsync(request); |
|||
}) |
|||
.Produces<UpdateCatalogItemResponse>() |
|||
.WithTags("CatalogItemEndpoints"); |
|||
} |
|||
|
|||
public async Task<IResult> HandleAsync(UpdateCatalogItemRequest request) |
|||
{ |
|||
var response = new UpdateCatalogItemResponse(request.CorrelationId()); |
|||
|
|||
var existingItem = await _itemRepository.GetByIdAsync(request.Id); |
|||
|
|||
existingItem.UpdateDetails(request.Name, request.Description, request.Price); |
|||
existingItem.UpdateBrand(request.CatalogBrandId); |
|||
existingItem.UpdateType(request.CatalogTypeId); |
|||
|
|||
await _itemRepository.UpdateAsync(existingItem); |
|||
|
|||
var dto = new CatalogItemDto |
|||
{ |
|||
Id = existingItem.Id, |
|||
CatalogBrandId = existingItem.CatalogBrandId, |
|||
CatalogTypeId = existingItem.CatalogTypeId, |
|||
Description = existingItem.Description, |
|||
Name = existingItem.Name, |
|||
PictureUri = _uriComposer.ComposePicUri(existingItem.PictureUri), |
|||
Price = existingItem.Price |
|||
}; |
|||
response.CatalogItem = dto; |
|||
return Results.Ok(response); |
|||
} |
|||
} |
|||
@ -0,0 +1,48 @@ |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using AutoMapper; |
|||
using Microsoft.AspNetCore.Builder; |
|||
using Microsoft.AspNetCore.Http; |
|||
using Microsoft.AspNetCore.Routing; |
|||
using Microsoft.eShopWeb.ApplicationCore.Entities; |
|||
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
|||
using MinimalApi.Endpoint; |
|||
|
|||
namespace Microsoft.eShopWeb.PublicApi.CatalogTypeEndpoints; |
|||
|
|||
/// <summary>
|
|||
/// List Catalog Types
|
|||
/// </summary>
|
|||
public class CatalogTypeListEndpoint : IEndpoint<IResult> |
|||
{ |
|||
private IRepository<CatalogType> _catalogTypeRepository; |
|||
private readonly IMapper _mapper; |
|||
|
|||
public CatalogTypeListEndpoint(IMapper mapper) |
|||
{ |
|||
_mapper = mapper; |
|||
} |
|||
|
|||
public void AddRoute(IEndpointRouteBuilder app) |
|||
{ |
|||
app.MapGet("api/catalog-types", |
|||
async (IRepository<CatalogType> catalogTypeRepository) => |
|||
{ |
|||
_catalogTypeRepository = catalogTypeRepository; |
|||
return await HandleAsync(); |
|||
}) |
|||
.Produces<ListCatalogTypesResponse>() |
|||
.WithTags("CatalogTypeEndpoints"); |
|||
} |
|||
|
|||
public async Task<IResult> HandleAsync() |
|||
{ |
|||
var response = new ListCatalogTypesResponse(); |
|||
|
|||
var items = await _catalogTypeRepository.ListAsync(); |
|||
|
|||
response.CatalogTypes.AddRange(items.Select(_mapper.Map<CatalogTypeDto>)); |
|||
|
|||
return Results.Ok(response); |
|||
} |
|||
} |
|||
@ -1,44 +0,0 @@ |
|||
using System.Linq; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Ardalis.ApiEndpoints; |
|||
using AutoMapper; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.eShopWeb.ApplicationCore.Entities; |
|||
using Microsoft.eShopWeb.ApplicationCore.Interfaces; |
|||
using Swashbuckle.AspNetCore.Annotations; |
|||
|
|||
namespace Microsoft.eShopWeb.PublicApi.CatalogTypeEndpoints; |
|||
|
|||
public class List : EndpointBaseAsync |
|||
.WithoutRequest |
|||
.WithActionResult<ListCatalogTypesResponse> |
|||
{ |
|||
private readonly IRepository<CatalogType> _catalogTypeRepository; |
|||
private readonly IMapper _mapper; |
|||
|
|||
public List(IRepository<CatalogType> catalogTypeRepository, |
|||
IMapper mapper) |
|||
{ |
|||
_catalogTypeRepository = catalogTypeRepository; |
|||
_mapper = mapper; |
|||
} |
|||
|
|||
[HttpGet("api/catalog-types")] |
|||
[SwaggerOperation( |
|||
Summary = "List Catalog Types", |
|||
Description = "List Catalog Types", |
|||
OperationId = "catalog-types.List", |
|||
Tags = new[] { "CatalogTypeEndpoints" }) |
|||
] |
|||
public override async Task<ActionResult<ListCatalogTypesResponse>> HandleAsync(CancellationToken cancellationToken) |
|||
{ |
|||
var response = new ListCatalogTypesResponse(); |
|||
|
|||
var items = await _catalogTypeRepository.ListAsync(cancellationToken); |
|||
|
|||
response.CatalogTypes.AddRange(items.Select(_mapper.Map<CatalogTypeDto>)); |
|||
|
|||
return Ok(response); |
|||
} |
|||
} |
|||
@ -1,43 +1,43 @@ |
|||
using System.Net.Http; |
|||
using System.Text; |
|||
using System.Text.Json; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.eShopWeb.ApplicationCore.Constants; |
|||
using Microsoft.eShopWeb.FunctionalTests.PublicApi; |
|||
using Microsoft.eShopWeb.PublicApi.AuthEndpoints; |
|||
using Xunit; |
|||
//using System.Net.Http;
|
|||
//using System.Text;
|
|||
//using System.Text.Json;
|
|||
//using System.Threading.Tasks;
|
|||
//using Microsoft.eShopWeb.ApplicationCore.Constants;
|
|||
//using Microsoft.eShopWeb.FunctionalTests.PublicApi;
|
|||
//using Microsoft.eShopWeb.PublicApi.AuthEndpoints;
|
|||
//using Xunit;
|
|||
|
|||
namespace Microsoft.eShopWeb.FunctionalTests.Web.Controllers; |
|||
//namespace Microsoft.eShopWeb.FunctionalTests.Web.Controllers;
|
|||
|
|||
[Collection("Sequential")] |
|||
public class AuthenticateEndpoint : IClassFixture<TestApiApplication> |
|||
{ |
|||
JsonSerializerOptions _jsonOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; |
|||
//[Collection("Sequential")]
|
|||
//public class AuthenticateEndpoint : IClassFixture<TestApiApplication>
|
|||
//{
|
|||
// JsonSerializerOptions _jsonOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
|
|||
|
|||
public AuthenticateEndpoint(TestApiApplication factory) |
|||
{ |
|||
Client = factory.CreateClient(); |
|||
} |
|||
// public AuthenticateEndpoint(TestApiApplication factory)
|
|||
// {
|
|||
// Client = factory.CreateClient();
|
|||
// }
|
|||
|
|||
public HttpClient Client { get; } |
|||
// public HttpClient Client { get; }
|
|||
|
|||
[Theory] |
|||
[InlineData("demouser@microsoft.com", AuthorizationConstants.DEFAULT_PASSWORD, true)] |
|||
[InlineData("demouser@microsoft.com", "badpassword", false)] |
|||
[InlineData("baduser@microsoft.com", "badpassword", false)] |
|||
public async Task ReturnsExpectedResultGivenCredentials(string testUsername, string testPassword, bool expectedResult) |
|||
{ |
|||
var request = new AuthenticateRequest() |
|||
{ |
|||
Username = testUsername, |
|||
Password = testPassword |
|||
}; |
|||
var jsonContent = new StringContent(JsonSerializer.Serialize(request), Encoding.UTF8, "application/json"); |
|||
var response = await Client.PostAsync("api/authenticate", jsonContent); |
|||
response.EnsureSuccessStatusCode(); |
|||
var stringResponse = await response.Content.ReadAsStringAsync(); |
|||
var model = stringResponse.FromJson<AuthenticateResponse>(); |
|||
// [Theory]
|
|||
// [InlineData("demouser@microsoft.com", AuthorizationConstants.DEFAULT_PASSWORD, true)]
|
|||
// [InlineData("demouser@microsoft.com", "badpassword", false)]
|
|||
// [InlineData("baduser@microsoft.com", "badpassword", false)]
|
|||
// public async Task ReturnsExpectedResultGivenCredentials(string testUsername, string testPassword, bool expectedResult)
|
|||
// {
|
|||
// var request = new AuthenticateRequest()
|
|||
// {
|
|||
// Username = testUsername,
|
|||
// Password = testPassword
|
|||
// };
|
|||
// var jsonContent = new StringContent(JsonSerializer.Serialize(request), Encoding.UTF8, "application/json");
|
|||
// var response = await Client.PostAsync("api/authenticate", jsonContent);
|
|||
// response.EnsureSuccessStatusCode();
|
|||
// var stringResponse = await response.Content.ReadAsStringAsync();
|
|||
// var model = stringResponse.FromJson<AuthenticateResponse>();
|
|||
|
|||
Assert.Equal(expectedResult, model.Result); |
|||
} |
|||
} |
|||
// Assert.Equal(expectedResult, model.Result);
|
|||
// }
|
|||
//}
|
|||
|
|||
@ -1,41 +0,0 @@ |
|||
using System.Linq; |
|||
using System.Net.Http; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.eShopWeb.FunctionalTests.PublicApi; |
|||
using Microsoft.eShopWeb.Web.ViewModels; |
|||
using Xunit; |
|||
|
|||
namespace Microsoft.eShopWeb.FunctionalTests.Web.Controllers; |
|||
|
|||
[Collection("Sequential")] |
|||
public class ApiCatalogControllerList : IClassFixture<TestApiApplication> |
|||
{ |
|||
public ApiCatalogControllerList(TestApiApplication factory) |
|||
{ |
|||
Client = factory.CreateClient(); |
|||
} |
|||
|
|||
public HttpClient Client { get; } |
|||
|
|||
[Fact] |
|||
public async Task ReturnsFirst10CatalogItems() |
|||
{ |
|||
var response = await Client.GetAsync("/api/catalog-items?pageSize=10"); |
|||
response.EnsureSuccessStatusCode(); |
|||
var stringResponse = await response.Content.ReadAsStringAsync(); |
|||
var model = stringResponse.FromJson<CatalogIndexViewModel>(); |
|||
|
|||
Assert.Equal(10, model.CatalogItems.Count()); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task ReturnsLast2CatalogItemsGivenPageIndex1() |
|||
{ |
|||
var response = await Client.GetAsync("/api/catalog-items?pageSize=10&pageIndex=1"); |
|||
response.EnsureSuccessStatusCode(); |
|||
var stringResponse = await response.Content.ReadAsStringAsync(); |
|||
var model = stringResponse.FromJson<CatalogIndexViewModel>(); |
|||
|
|||
Assert.Equal(2, model.CatalogItems.Count()); |
|||
} |
|||
} |
|||
@ -1,74 +0,0 @@ |
|||
using System.Net; |
|||
using System.Net.Http; |
|||
using System.Net.Http.Headers; |
|||
using System.Text; |
|||
using System.Text.Json; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.eShopWeb.FunctionalTests.PublicApi; |
|||
using Microsoft.eShopWeb.FunctionalTests.Web.Api; |
|||
using Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints; |
|||
using Xunit; |
|||
|
|||
namespace Microsoft.eShopWeb.FunctionalTests.Web.Controllers; |
|||
|
|||
[Collection("Sequential")] |
|||
public class CreateEndpoint : IClassFixture<TestApiApplication> |
|||
{ |
|||
JsonSerializerOptions _jsonOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; |
|||
private int _testBrandId = 1; |
|||
private int _testTypeId = 2; |
|||
private string _testDescription = "test description"; |
|||
private string _testName = "test name"; |
|||
private decimal _testPrice = 1.23m; |
|||
|
|||
public CreateEndpoint(TestApiApplication factory) |
|||
{ |
|||
Client = factory.CreateClient(); |
|||
} |
|||
|
|||
public HttpClient Client { get; } |
|||
|
|||
[Fact] |
|||
public async Task ReturnsNotAuthorizedGivenNormalUserToken() |
|||
{ |
|||
var jsonContent = GetValidNewItemJson(); |
|||
var token = ApiTokenHelper.GetNormalUserToken(); |
|||
Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); |
|||
var response = await Client.PostAsync("api/catalog-items", jsonContent); |
|||
|
|||
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task ReturnsSuccessGivenValidNewItemAndAdminUserToken() |
|||
{ |
|||
var jsonContent = GetValidNewItemJson(); |
|||
var adminToken = ApiTokenHelper.GetAdminUserToken(); |
|||
Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", adminToken); |
|||
var response = await Client.PostAsync("api/catalog-items", jsonContent); |
|||
response.EnsureSuccessStatusCode(); |
|||
var stringResponse = await response.Content.ReadAsStringAsync(); |
|||
var model = stringResponse.FromJson<CreateCatalogItemResponse>(); |
|||
|
|||
Assert.Equal(_testBrandId, model.CatalogItem.CatalogBrandId); |
|||
Assert.Equal(_testTypeId, model.CatalogItem.CatalogTypeId); |
|||
Assert.Equal(_testDescription, model.CatalogItem.Description); |
|||
Assert.Equal(_testName, model.CatalogItem.Name); |
|||
Assert.Equal(_testPrice, model.CatalogItem.Price); |
|||
} |
|||
|
|||
private StringContent GetValidNewItemJson() |
|||
{ |
|||
var request = new CreateCatalogItemRequest() |
|||
{ |
|||
CatalogBrandId = _testBrandId, |
|||
CatalogTypeId = _testTypeId, |
|||
Description = _testDescription, |
|||
Name = _testName, |
|||
Price = _testPrice |
|||
}; |
|||
var jsonContent = new StringContent(JsonSerializer.Serialize(request), Encoding.UTF8, "application/json"); |
|||
|
|||
return jsonContent; |
|||
} |
|||
} |
|||
@ -1,47 +0,0 @@ |
|||
using System.Net; |
|||
using System.Net.Http; |
|||
using System.Net.Http.Headers; |
|||
using System.Text.Json; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.eShopWeb.FunctionalTests.PublicApi; |
|||
using Microsoft.eShopWeb.FunctionalTests.Web.Api; |
|||
using Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints; |
|||
using Xunit; |
|||
|
|||
namespace Microsoft.eShopWeb.FunctionalTests.Web.Controllers; |
|||
|
|||
[Collection("Sequential")] |
|||
public class DeleteEndpoint : IClassFixture<TestApiApplication> |
|||
{ |
|||
JsonSerializerOptions _jsonOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; |
|||
|
|||
public DeleteEndpoint(TestApiApplication factory) |
|||
{ |
|||
Client = factory.CreateClient(); |
|||
} |
|||
|
|||
public HttpClient Client { get; } |
|||
|
|||
[Fact] |
|||
public async Task ReturnsSuccessGivenValidIdAndAdminUserToken() |
|||
{ |
|||
var adminToken = ApiTokenHelper.GetAdminUserToken(); |
|||
Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", adminToken); |
|||
var response = await Client.DeleteAsync("api/catalog-items/12"); |
|||
response.EnsureSuccessStatusCode(); |
|||
var stringResponse = await response.Content.ReadAsStringAsync(); |
|||
var model = stringResponse.FromJson<DeleteCatalogItemResponse>(); |
|||
|
|||
Assert.Equal("Deleted", model.Status); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task ReturnsNotFoundGivenInvalidIdAndAdminUserToken() |
|||
{ |
|||
var adminToken = ApiTokenHelper.GetAdminUserToken(); |
|||
Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", adminToken); |
|||
var response = await Client.DeleteAsync("api/catalog-items/0"); |
|||
|
|||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); |
|||
} |
|||
} |
|||
@ -1,42 +0,0 @@ |
|||
using System.Net; |
|||
using System.Net.Http; |
|||
using System.Text.Json; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.eShopWeb.FunctionalTests.PublicApi; |
|||
using Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints; |
|||
using Xunit; |
|||
|
|||
namespace Microsoft.eShopWeb.FunctionalTests.Web.Controllers; |
|||
|
|||
[Collection("Sequential")] |
|||
public class GetByIdEndpoint : IClassFixture<TestApiApplication> |
|||
{ |
|||
JsonSerializerOptions _jsonOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; |
|||
|
|||
public GetByIdEndpoint(TestApiApplication factory) |
|||
{ |
|||
Client = factory.CreateClient(); |
|||
} |
|||
|
|||
public HttpClient Client { get; } |
|||
|
|||
[Fact] |
|||
public async Task ReturnsItemGivenValidId() |
|||
{ |
|||
var response = await Client.GetAsync("api/catalog-items/5"); |
|||
response.EnsureSuccessStatusCode(); |
|||
var stringResponse = await response.Content.ReadAsStringAsync(); |
|||
var model = stringResponse.FromJson<GetByIdCatalogItemResponse>(); |
|||
|
|||
Assert.Equal(5, model.CatalogItem.Id); |
|||
Assert.Equal("Roslyn Red Sheet", model.CatalogItem.Name); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task ReturnsNotFoundGivenInvalidId() |
|||
{ |
|||
var response = await Client.GetAsync("api/catalog-items/0"); |
|||
|
|||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); |
|||
} |
|||
} |
|||
@ -0,0 +1,50 @@ |
|||
using Microsoft.eShopWeb.ApplicationCore.Constants; |
|||
using Microsoft.IdentityModel.Tokens; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IdentityModel.Tokens.Jwt; |
|||
using System.Security.Claims; |
|||
using System.Text; |
|||
|
|||
namespace PublicApiIntegrationTests |
|||
{ |
|||
public class ApiTokenHelper |
|||
{ |
|||
public static string GetAdminUserToken() |
|||
{ |
|||
string userName = "admin@microsoft.com"; |
|||
string[] roles = { "Administrators" }; |
|||
|
|||
return CreateToken(userName, roles); |
|||
} |
|||
|
|||
public static string GetNormalUserToken() |
|||
{ |
|||
string userName = "demouser@microsoft.com"; |
|||
string[] roles = { }; |
|||
|
|||
return CreateToken(userName, roles); |
|||
} |
|||
|
|||
private static string CreateToken(string userName, string[] roles) |
|||
{ |
|||
var claims = new List<Claim> { new Claim(ClaimTypes.Name, userName) }; |
|||
|
|||
foreach (var role in roles) |
|||
{ |
|||
claims.Add(new Claim(ClaimTypes.Role, role)); |
|||
} |
|||
|
|||
var key = Encoding.ASCII.GetBytes(AuthorizationConstants.JWT_SECRET_KEY); |
|||
var tokenDescriptor = new SecurityTokenDescriptor |
|||
{ |
|||
Subject = new ClaimsIdentity(claims.ToArray()), |
|||
Expires = DateTime.UtcNow.AddHours(1), |
|||
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) |
|||
}; |
|||
var tokenHandler = new JwtSecurityTokenHandler(); |
|||
var token = tokenHandler.CreateToken(tokenDescriptor); |
|||
return tokenHandler.WriteToken(token); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
using Microsoft.AspNetCore.Mvc.Testing; |
|||
using Microsoft.eShopWeb; |
|||
using Microsoft.eShopWeb.ApplicationCore.Constants; |
|||
using Microsoft.eShopWeb.PublicApi.AuthEndpoints; |
|||
using Microsoft.VisualStudio.TestTools.UnitTesting; |
|||
using System.Net.Http; |
|||
using System.Text; |
|||
using System.Text.Json; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace PublicApiIntegrationTests.AuthEndpoints |
|||
{ |
|||
[TestClass] |
|||
public class AuthenticateEndpoint |
|||
{ |
|||
[TestMethod] |
|||
[DataRow("demouser@microsoft.com", AuthorizationConstants.DEFAULT_PASSWORD, true)] |
|||
[DataRow("demouser@microsoft.com", "badpassword", false)] |
|||
[DataRow("baduser@microsoft.com", "badpassword", false)] |
|||
public async Task ReturnsExpectedResultGivenCredentials(string testUsername, string testPassword, bool expectedResult) |
|||
{ |
|||
var request = new AuthenticateRequest() |
|||
{ |
|||
Username = testUsername, |
|||
Password = testPassword |
|||
}; |
|||
var jsonContent = new StringContent(JsonSerializer.Serialize(request), Encoding.UTF8, "application/json"); |
|||
var response = await ProgramTest.NewClient.PostAsync("api/authenticate", jsonContent); |
|||
response.EnsureSuccessStatusCode(); |
|||
var stringResponse = await response.Content.ReadAsStringAsync(); |
|||
var model = stringResponse.FromJson<AuthenticateResponse>(); |
|||
|
|||
Assert.AreEqual(expectedResult, model.Result); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
using Microsoft.eShopWeb; |
|||
using Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints; |
|||
using Microsoft.VisualStudio.TestTools.UnitTesting; |
|||
using System.Net; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace PublicApiIntegrationTests.CatalogItemEndpoints |
|||
{ |
|||
[TestClass] |
|||
public class CatalogItemGetByIdEndpointTest |
|||
{ |
|||
[TestMethod] |
|||
public async Task ReturnsItemGivenValidId() |
|||
{ |
|||
var response = await ProgramTest.NewClient.GetAsync("api/catalog-items/5"); |
|||
response.EnsureSuccessStatusCode(); |
|||
var stringResponse = await response.Content.ReadAsStringAsync(); |
|||
var model = stringResponse.FromJson<GetByIdCatalogItemResponse>(); |
|||
|
|||
Assert.AreEqual(5, model.CatalogItem.Id); |
|||
Assert.AreEqual("Roslyn Red Sheet", model.CatalogItem.Name); |
|||
} |
|||
|
|||
[TestMethod] |
|||
public async Task ReturnsNotFoundGivenInvalidId() |
|||
{ |
|||
var response = await ProgramTest.NewClient.GetAsync("api/catalog-items/0"); |
|||
|
|||
Assert.AreEqual(HttpStatusCode.NotFound, response.StatusCode); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
using Microsoft.eShopWeb; |
|||
using Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints; |
|||
using Microsoft.eShopWeb.Web.ViewModels; |
|||
using Microsoft.VisualStudio.TestTools.UnitTesting; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace PublicApiIntegrationTests.CatalogItemEndpoints |
|||
{ |
|||
[TestClass] |
|||
public class CatalogItemListPagedEndpoint |
|||
{ |
|||
[TestMethod] |
|||
public async Task ReturnsFirst10CatalogItems() |
|||
{ |
|||
var client = ProgramTest.NewClient; |
|||
var response = await client.GetAsync("/api/catalog-items?pageSize=10"); |
|||
response.EnsureSuccessStatusCode(); |
|||
var stringResponse = await response.Content.ReadAsStringAsync(); |
|||
var model = stringResponse.FromJson<CatalogIndexViewModel>(); |
|||
|
|||
Assert.AreEqual(10, model.CatalogItems.Count()); |
|||
} |
|||
|
|||
[TestMethod] |
|||
public async Task ReturnsCorrectCatalogItemsGivenPageIndex1() |
|||
{ |
|||
|
|||
var pageSize = 10; |
|||
var pageIndex = 1; |
|||
|
|||
var client = ProgramTest.NewClient; |
|||
var response = await client.GetAsync($"/api/catalog-items"); |
|||
response.EnsureSuccessStatusCode(); |
|||
var stringResponse = await response.Content.ReadAsStringAsync(); |
|||
var model = stringResponse.FromJson<ListPagedCatalogItemResponse>(); |
|||
var totalItem = model.CatalogItems.Count(); |
|||
|
|||
var response2 = await client.GetAsync($"/api/catalog-items?pageSize={pageSize}&pageIndex={pageIndex}"); |
|||
response.EnsureSuccessStatusCode(); |
|||
var stringResponse2 = await response2.Content.ReadAsStringAsync(); |
|||
var model2 = stringResponse2.FromJson<ListPagedCatalogItemResponse>(); |
|||
|
|||
var totalExpected = totalItem - (pageSize * pageIndex); |
|||
|
|||
Assert.AreEqual(totalExpected, model2.CatalogItems.Count()); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,69 @@ |
|||
using BlazorShared.Models; |
|||
using Microsoft.eShopWeb; |
|||
using Microsoft.VisualStudio.TestTools.UnitTesting; |
|||
using System.Net; |
|||
using System.Net.Http; |
|||
using System.Net.Http.Headers; |
|||
using System.Text; |
|||
using System.Text.Json; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace PublicApiIntegrationTests.AuthEndpoints |
|||
{ |
|||
[TestClass] |
|||
public class CreateCatalogItemEndpointTest |
|||
{ |
|||
private int _testBrandId = 1; |
|||
private int _testTypeId = 2; |
|||
private string _testDescription = "test description"; |
|||
private string _testName = "test name"; |
|||
private decimal _testPrice = 1.23m; |
|||
|
|||
|
|||
[TestMethod] |
|||
public async Task ReturnsNotAuthorizedGivenNormalUserToken() |
|||
{ |
|||
var jsonContent = GetValidNewItemJson(); |
|||
var token = ApiTokenHelper.GetNormalUserToken(); |
|||
var client = ProgramTest.NewClient; |
|||
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); |
|||
var response = await client.PostAsync("api/catalog-items", jsonContent); |
|||
|
|||
Assert.AreEqual(HttpStatusCode.Forbidden, response.StatusCode); |
|||
} |
|||
|
|||
[TestMethod] |
|||
public async Task ReturnsSuccessGivenValidNewItemAndAdminUserToken() |
|||
{ |
|||
var jsonContent = GetValidNewItemJson(); |
|||
var adminToken = ApiTokenHelper.GetAdminUserToken(); |
|||
var client = ProgramTest.NewClient; |
|||
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", adminToken); |
|||
var response = await client.PostAsync("api/catalog-items", jsonContent); |
|||
response.EnsureSuccessStatusCode(); |
|||
var stringResponse = await response.Content.ReadAsStringAsync(); |
|||
var model = stringResponse.FromJson<CreateCatalogItemResponse>(); |
|||
|
|||
Assert.AreEqual(_testBrandId, model.CatalogItem.CatalogBrandId); |
|||
Assert.AreEqual(_testTypeId, model.CatalogItem.CatalogTypeId); |
|||
Assert.AreEqual(_testDescription, model.CatalogItem.Description); |
|||
Assert.AreEqual(_testName, model.CatalogItem.Name); |
|||
Assert.AreEqual(_testPrice, model.CatalogItem.Price); |
|||
} |
|||
|
|||
private StringContent GetValidNewItemJson() |
|||
{ |
|||
var request = new CreateCatalogItemRequest() |
|||
{ |
|||
CatalogBrandId = _testBrandId, |
|||
CatalogTypeId = _testTypeId, |
|||
Description = _testDescription, |
|||
Name = _testName, |
|||
Price = _testPrice |
|||
}; |
|||
var jsonContent = new StringContent(JsonSerializer.Serialize(request), Encoding.UTF8, "application/json"); |
|||
|
|||
return jsonContent; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
using BlazorShared.Models; |
|||
using Microsoft.eShopWeb; |
|||
using Microsoft.VisualStudio.TestTools.UnitTesting; |
|||
using System.Net; |
|||
using System.Net.Http.Headers; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace PublicApiIntegrationTests.CatalogItemEndpoints |
|||
{ |
|||
[TestClass] |
|||
public class DeleteCatalogItemEndpointTest |
|||
{ |
|||
[TestMethod] |
|||
public async Task ReturnsSuccessGivenValidIdAndAdminUserToken() |
|||
{ |
|||
var adminToken = ApiTokenHelper.GetAdminUserToken(); |
|||
var client = ProgramTest.NewClient; |
|||
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", adminToken); |
|||
var response = await client.DeleteAsync("api/catalog-items/12"); |
|||
response.EnsureSuccessStatusCode(); |
|||
var stringResponse = await response.Content.ReadAsStringAsync(); |
|||
var model = stringResponse.FromJson<DeleteCatalogItemResponse>(); |
|||
|
|||
Assert.AreEqual("Deleted", model.Status); |
|||
} |
|||
|
|||
[TestMethod] |
|||
public async Task ReturnsNotFoundGivenInvalidIdAndAdminUserToken() |
|||
{ |
|||
var adminToken = ApiTokenHelper.GetAdminUserToken(); |
|||
var client = ProgramTest.NewClient; |
|||
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", adminToken); |
|||
var response = await client.DeleteAsync("api/catalog-items/0"); |
|||
|
|||
Assert.AreEqual(HttpStatusCode.NotFound, response.StatusCode); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
using Microsoft.AspNetCore.Mvc.Testing; |
|||
using Microsoft.VisualStudio.TestTools.UnitTesting; |
|||
using System.Net.Http; |
|||
|
|||
namespace PublicApiIntegrationTests |
|||
{ |
|||
[TestClass] |
|||
public class ProgramTest |
|||
{ |
|||
private static WebApplicationFactory<Program> _application; |
|||
|
|||
public static HttpClient NewClient |
|||
{ |
|||
get |
|||
{ |
|||
return _application.CreateClient(); |
|||
} |
|||
} |
|||
|
|||
[AssemblyInitialize] |
|||
public static void AssemblyInitialize(TestContext _) |
|||
{ |
|||
_application = new WebApplicationFactory<Program>(); |
|||
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net6.0</TargetFramework> |
|||
<Nullable>enable</Nullable> |
|||
|
|||
<IsPackable>false</IsPackable> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<None Remove="appsettings.json" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<Content Include="appsettings.json"> |
|||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> |
|||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile> |
|||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> |
|||
</Content> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.1" /> |
|||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" /> |
|||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.8" /> |
|||
<PackageReference Include="MSTest.TestFramework" Version="2.2.8" /> |
|||
<PackageReference Include="coverlet.collector" Version="3.1.0" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\src\PublicApi\PublicApi.csproj" /> |
|||
<ProjectReference Include="..\..\src\Web\Web.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,3 @@ |
|||
{ |
|||
"UseOnlyInMemoryDatabase": true |
|||
} |
|||
Loading…
Reference in new issue