Refactor to introduce nullable types and reduce compiler warnings (#801)
* Introduce nullable types to Core, Infrastructure and PublicApi projects * Refactor unit tests * Fixed failing tests * Introduce Parameter object for CatalogItem update method * Refactor CataloItemDetails param object * Refactor following PR comments
This commit is contained in:
committed by
GitHub
parent
aa6305eab1
commit
a72dd775ee
@@ -1,4 +1,5 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Ardalis.GuardClauses;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
@@ -73,17 +74,17 @@ public class LoginModel : PageModel
|
||||
// This doesn't count login failures towards account lockout
|
||||
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
|
||||
//var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: true);
|
||||
var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, false, true);
|
||||
var result = await _signInManager.PasswordSignInAsync(Input?.Email, Input?.Password, false, true);
|
||||
|
||||
if (result.Succeeded)
|
||||
{
|
||||
_logger.LogInformation("User logged in.");
|
||||
await TransferAnonymousBasketToUserAsync(Input.Email);
|
||||
await TransferAnonymousBasketToUserAsync(Input?.Email);
|
||||
return LocalRedirect(returnUrl);
|
||||
}
|
||||
if (result.RequiresTwoFactor)
|
||||
{
|
||||
return RedirectToPage("./LoginWith2fa", new { ReturnUrl = returnUrl, RememberMe = Input.RememberMe });
|
||||
return RedirectToPage("./LoginWith2fa", new { ReturnUrl = returnUrl, RememberMe = Input?.RememberMe });
|
||||
}
|
||||
if (result.IsLockedOut)
|
||||
{
|
||||
@@ -108,6 +109,7 @@ public class LoginModel : PageModel
|
||||
var anonymousId = Request.Cookies[Constants.BASKET_COOKIENAME];
|
||||
if (Guid.TryParse(anonymousId, out var _))
|
||||
{
|
||||
Guard.Against.NullOrEmpty(userName, nameof(userName));
|
||||
await _basketService.TransferBasketAsync(anonymousId, userName);
|
||||
}
|
||||
Response.Cookies.Delete(Constants.BASKET_COOKIENAME);
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Ardalis.GuardClauses;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
@@ -67,8 +68,8 @@ public class RegisterModel : PageModel
|
||||
returnUrl = returnUrl ?? Url.Content("~/");
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var user = new ApplicationUser { UserName = Input.Email, Email = Input.Email };
|
||||
var result = await _userManager.CreateAsync(user, Input.Password);
|
||||
var user = new ApplicationUser { UserName = Input?.Email, Email = Input?.Email };
|
||||
var result = await _userManager.CreateAsync(user, Input?.Password);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
_logger.LogInformation("User created a new account with password.");
|
||||
@@ -80,7 +81,8 @@ public class RegisterModel : PageModel
|
||||
values: new { userId = user.Id, code = code },
|
||||
protocol: Request.Scheme);
|
||||
|
||||
await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
|
||||
Guard.Against.Null(callbackUrl, nameof(callbackUrl));
|
||||
await _emailSender.SendEmailAsync(Input?.Email, "Confirm your email",
|
||||
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
|
||||
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
|
||||
@@ -22,12 +22,12 @@ public class RevokeAuthenticationEvents : CookieAuthenticationEvents
|
||||
|
||||
public override async Task ValidatePrincipal(CookieValidatePrincipalContext context)
|
||||
{
|
||||
var userId = context.Principal.Claims.First(c => c.Type == ClaimTypes.Name);
|
||||
var userId = context.Principal?.Claims.First(c => c.Type == ClaimTypes.Name);
|
||||
var identityKey = context.Request.Cookies[ConfigureCookieSettings.IdentifierCookieName];
|
||||
|
||||
if (_cache.TryGetValue($"{userId.Value}:{identityKey}", out var revokeKeys))
|
||||
if (_cache.TryGetValue($"{userId?.Value}:{identityKey}", out var revokeKeys))
|
||||
{
|
||||
_logger.LogDebug($"Access has been revoked for: {userId.Value}.");
|
||||
_logger.LogDebug($"Access has been revoked for: {userId?.Value}.");
|
||||
context.RejectPrincipal();
|
||||
await context.HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using Ardalis.GuardClauses;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
@@ -119,6 +120,7 @@ public class ManageController : Controller
|
||||
|
||||
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
||||
var callbackUrl = Url.EmailConfirmationLink(user.Id, code, Request.Scheme);
|
||||
Guard.Against.Null(callbackUrl, nameof(callbackUrl));
|
||||
var email = user.Email;
|
||||
await _emailSender.SendEmailConfirmationAsync(email, callbackUrl);
|
||||
|
||||
@@ -405,7 +407,7 @@ public class ManageController : Controller
|
||||
}
|
||||
|
||||
// Strip spaces and hypens
|
||||
var verificationCode = model.Code.Replace(" ", string.Empty).Replace("-", string.Empty);
|
||||
var verificationCode = model.Code?.Replace(" ", string.Empty).Replace("-", string.Empty);
|
||||
|
||||
var is2faTokenValid = await _userManager.VerifyTwoFactorTokenAsync(
|
||||
user, _userManager.Options.Tokens.AuthenticatorTokenProvider, verificationCode);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using MediatR;
|
||||
using Ardalis.GuardClauses;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.eShopWeb.Web.Features.MyOrders;
|
||||
@@ -20,7 +21,8 @@ public class OrderController : Controller
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> MyOrders()
|
||||
{
|
||||
{
|
||||
Guard.Against.Null(User?.Identity?.Name, nameof(User.Identity.Name));
|
||||
var viewModel = await _mediator.Send(new GetMyOrders(User.Identity.Name));
|
||||
|
||||
return View(viewModel);
|
||||
@@ -29,6 +31,7 @@ public class OrderController : Controller
|
||||
[HttpGet("{orderId}")]
|
||||
public async Task<IActionResult> Detail(int orderId)
|
||||
{
|
||||
Guard.Against.Null(User?.Identity?.Name, nameof(User.Identity.Name));
|
||||
var viewModel = await _mediator.Send(new GetOrderDetails(User.Identity.Name, orderId));
|
||||
|
||||
if (viewModel == null)
|
||||
|
||||
@@ -28,7 +28,7 @@ public class UserController : ControllerBase
|
||||
|
||||
private async Task<UserInfo> CreateUserInfo(ClaimsPrincipal claimsPrincipal)
|
||||
{
|
||||
if (!claimsPrincipal.Identity.IsAuthenticated)
|
||||
if (claimsPrincipal.Identity == null || claimsPrincipal.Identity.Name == null || !claimsPrincipal.Identity.IsAuthenticated)
|
||||
{
|
||||
return UserInfo.Anonymous;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
public static class UrlHelperExtensions
|
||||
{
|
||||
public static string EmailConfirmationLink(this IUrlHelper urlHelper, string userId, string code, string scheme)
|
||||
public static string? EmailConfirmationLink(this IUrlHelper urlHelper, string userId, string code, string scheme)
|
||||
{
|
||||
return urlHelper.Action(
|
||||
action: "GET",
|
||||
|
||||
@@ -28,7 +28,7 @@ public class GetMyOrdersHandler : IRequestHandler<GetMyOrders, IEnumerable<Order
|
||||
return orders.Select(o => new OrderViewModel
|
||||
{
|
||||
OrderDate = o.OrderDate,
|
||||
OrderItems = o.OrderItems?.Select(oi => new OrderItemViewModel()
|
||||
OrderItems = o.OrderItems.Select(oi => new OrderItemViewModel()
|
||||
{
|
||||
PictureUrl = oi.ItemOrdered.PictureUri,
|
||||
ProductId = oi.ItemOrdered.CatalogItemId,
|
||||
|
||||
@@ -9,7 +9,7 @@ using Microsoft.eShopWeb.Web.ViewModels;
|
||||
|
||||
namespace Microsoft.eShopWeb.Web.Features.OrderDetails;
|
||||
|
||||
public class GetOrderDetailsHandler : IRequestHandler<GetOrderDetails, OrderViewModel>
|
||||
public class GetOrderDetailsHandler : IRequestHandler<GetOrderDetails, OrderViewModel?>
|
||||
{
|
||||
private readonly IReadRepository<Order> _orderRepository;
|
||||
|
||||
@@ -18,11 +18,11 @@ public class GetOrderDetailsHandler : IRequestHandler<GetOrderDetails, OrderView
|
||||
_orderRepository = orderRepository;
|
||||
}
|
||||
|
||||
public async Task<OrderViewModel> Handle(GetOrderDetails request,
|
||||
public async Task<OrderViewModel?> Handle(GetOrderDetails request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var spec = new OrderWithItemsByIdSpec(request.OrderId);
|
||||
var order = await _orderRepository.GetBySpecAsync(spec, cancellationToken);
|
||||
var order = await _orderRepository.FirstOrDefaultAsync(spec, cancellationToken);
|
||||
|
||||
if (order == null)
|
||||
{
|
||||
|
||||
@@ -19,8 +19,8 @@ public class HomePageHealthCheck : IHealthCheck
|
||||
HealthCheckContext context,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
var request = _httpContextAccessor.HttpContext.Request;
|
||||
string myUrl = request.Scheme + "://" + request.Host.ToString();
|
||||
var request = _httpContextAccessor.HttpContext?.Request;
|
||||
string myUrl = request?.Scheme + "://" + request?.Host.ToString();
|
||||
|
||||
var client = new HttpClient();
|
||||
var response = await client.GetAsync(myUrl);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Ardalis.GuardClauses;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
@@ -68,6 +69,7 @@ public class CheckoutModel : PageModel
|
||||
|
||||
private async Task SetBasketModelAsync()
|
||||
{
|
||||
Guard.Against.Null(User?.Identity?.Name, nameof(User.Identity.Name));
|
||||
if (_signInManager.IsSignedIn(HttpContext.User))
|
||||
{
|
||||
BasketModel = await _basketViewModelService.GetOrCreateBasketForUser(User.Identity.Name);
|
||||
@@ -75,7 +77,7 @@ public class CheckoutModel : PageModel
|
||||
else
|
||||
{
|
||||
GetOrSetBasketCookieAndUserName();
|
||||
BasketModel = await _basketViewModelService.GetOrCreateBasketForUser(_username);
|
||||
BasketModel = await _basketViewModelService.GetOrCreateBasketForUser(_username!);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Ardalis.GuardClauses;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||
@@ -66,11 +67,13 @@ public class IndexModel : PageModel
|
||||
|
||||
private string GetOrSetBasketCookieAndUserName()
|
||||
{
|
||||
Guard.Against.Null(Request.HttpContext.User.Identity, nameof(Request.HttpContext.User.Identity));
|
||||
string? userName = null;
|
||||
|
||||
if (Request.HttpContext.User.Identity.IsAuthenticated)
|
||||
{
|
||||
return Request.HttpContext.User.Identity.Name;
|
||||
Guard.Against.Null(Request.HttpContext.User.Identity.Name, nameof(Request.HttpContext.User.Identity.Name));
|
||||
return Request.HttpContext.User.Identity.Name!;
|
||||
}
|
||||
|
||||
if (Request.Cookies.ContainsKey(Constants.BASKET_COOKIENAME))
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Ardalis.GuardClauses;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.eShopWeb.Infrastructure.Identity;
|
||||
@@ -33,17 +34,18 @@ public class Basket : ViewComponent
|
||||
{
|
||||
if (_signInManager.IsSignedIn(HttpContext.User))
|
||||
{
|
||||
Guard.Against.Null(User?.Identity?.Name, nameof(User.Identity.Name));
|
||||
return await _basketService.CountTotalBasketItems(User.Identity.Name);
|
||||
}
|
||||
|
||||
string anonymousId = GetAnnonymousIdFromCookie();
|
||||
string? anonymousId = GetAnnonymousIdFromCookie();
|
||||
if (anonymousId == null)
|
||||
return 0;
|
||||
|
||||
return await _basketService.CountTotalBasketItems(anonymousId);
|
||||
}
|
||||
|
||||
private string GetAnnonymousIdFromCookie()
|
||||
private string? GetAnnonymousIdFromCookie()
|
||||
{
|
||||
if (Request.Cookies.ContainsKey(Constants.BASKET_COOKIENAME))
|
||||
{
|
||||
|
||||
@@ -28,7 +28,7 @@ public class BasketViewModelService : IBasketViewModelService
|
||||
public async Task<BasketViewModel> GetOrCreateBasketForUser(string userName)
|
||||
{
|
||||
var basketSpec = new BasketWithItemsSpecification(userName);
|
||||
var basket = (await _basketRepository.GetBySpecAsync(basketSpec));
|
||||
var basket = (await _basketRepository.FirstOrDefaultAsync(basketSpec));
|
||||
|
||||
if (basket == null)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Threading.Tasks;
|
||||
using Ardalis.GuardClauses;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||
using Microsoft.eShopWeb.Web.Interfaces;
|
||||
@@ -18,7 +18,11 @@ public class CatalogItemViewModelService : ICatalogItemViewModelService
|
||||
public async Task UpdateCatalogItem(CatalogItemViewModel viewModel)
|
||||
{
|
||||
var existingCatalogItem = await _catalogItemRepository.GetByIdAsync(viewModel.Id);
|
||||
existingCatalogItem.UpdateDetails(viewModel.Name, existingCatalogItem.Description, viewModel.Price);
|
||||
|
||||
Guard.Against.Null(existingCatalogItem, nameof(existingCatalogItem));
|
||||
|
||||
CatalogItem.CatalogItemDetails details = new(viewModel.Name, existingCatalogItem.Description, viewModel.Price);
|
||||
existingCatalogItem.UpdateDetails(details);
|
||||
await _catalogItemRepository.UpdateAsync(existingCatalogItem);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,13 @@ namespace Microsoft.eShopWeb.Web;
|
||||
|
||||
public class SlugifyParameterTransformer : IOutboundParameterTransformer
|
||||
{
|
||||
public string? TransformOutbound(object value)
|
||||
public string? TransformOutbound(object? value)
|
||||
{
|
||||
if (value == null) { return null; }
|
||||
string? str = value.ToString();
|
||||
if (string.IsNullOrEmpty(str)) { return null; }
|
||||
|
||||
// Slugify value
|
||||
return Regex.Replace(value.ToString(), "([a-z])([A-Z])", "$1-$2").ToLower();
|
||||
return Regex.Replace(str, "([a-z])([A-Z])", "$1-$2").ToLower();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user