Basket persistence (#41)

* Renamed Cart to Basket throughout
* Implemented cookie-based anonymous basket handling and transfer to user upon login. Still need to implement transfer upon registration.
This commit is contained in:
Steve Smith
2017-08-22 13:51:08 -04:00
committed by GitHub
parent 3a95375ae7
commit ecb4889dd3
10 changed files with 173 additions and 118 deletions

View File

@@ -5,6 +5,10 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using Infrastructure.Identity;
using System;
using Microsoft.eShopWeb.ApplicationCore.Entities;
using ApplicationCore.Interfaces;
using Web;
namespace Microsoft.eShopWeb.Controllers
{
@@ -14,20 +18,21 @@ namespace Microsoft.eShopWeb.Controllers
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly string _externalCookieScheme;
private readonly IBasketService _basketService;
public AccountController(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
IOptions<IdentityCookieOptions> identityCookieOptions
)
IOptions<IdentityCookieOptions> identityCookieOptions,
IBasketService basketService)
{
_userManager = userManager;
_signInManager = signInManager;
_externalCookieScheme = identityCookieOptions.Value.ExternalCookieAuthenticationScheme;
_basketService = basketService;
}
// GET: /Account/SignIn
// GET: /Account/SignIn
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> SignIn(string returnUrl = null)
@@ -53,6 +58,12 @@ namespace Microsoft.eShopWeb.Controllers
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
string anonymousBasketId = Request.Cookies[Constants.BASKET_COOKIENAME];
if (!String.IsNullOrEmpty(anonymousBasketId))
{
_basketService.TransferBasket(anonymousBasketId, model.Email);
Response.Cookies.Delete(Constants.BASKET_COOKIENAME);
}
return RedirectToLocal(returnUrl);
}
ModelState.AddModelError(string.Empty, "Invalid login attempt.");

View File

@@ -0,0 +1,86 @@
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using ApplicationCore.Interfaces;
using Microsoft.AspNetCore.Http;
using Microsoft.eShopWeb.ViewModels;
using Microsoft.AspNetCore.Identity;
using Infrastructure.Identity;
using System;
using Web;
namespace Microsoft.eShopWeb.Controllers
{
[Route("[controller]/[action]")]
public class BasketController : Controller
{
private readonly IBasketService _basketService;
private const string _basketSessionKey = "basketId";
private readonly IUriComposer _uriComposer;
private readonly SignInManager<ApplicationUser> _signInManager;
public BasketController(IBasketService basketService,
IUriComposer uriComposer,
SignInManager<ApplicationUser> signInManager)
{
_basketService = basketService;
_uriComposer = uriComposer;
_signInManager = signInManager;
}
[HttpGet]
public async Task<IActionResult> Index()
{
var basketModel = await GetBasketViewModelAsync();
return View(basketModel);
}
// POST: /Basket/AddToBasket
[HttpPost]
public async Task<IActionResult> AddToBasket(CatalogItemViewModel productDetails)
{
if (productDetails?.Id == null)
{
return RedirectToAction("Index", "Catalog");
}
var basketViewModel = await GetBasketViewModelAsync();
await _basketService.AddItemToBasket(basketViewModel.Id, productDetails.Id, productDetails.Price, 1);
return RedirectToAction("Index");
}
[HttpPost]
public async Task<IActionResult> Checkout()
{
var basket = await GetBasketViewModelAsync();
await _basketService.Checkout(basket.Id);
return View("Checkout");
}
private async Task<BasketViewModel> GetBasketViewModelAsync()
{
if (_signInManager.IsSignedIn(HttpContext.User))
{
return await _basketService.GetOrCreateBasketForUser(User.Identity.Name);
}
string anonymousId = GetOrSetBasketCookie();
return await _basketService.GetOrCreateBasketForUser(anonymousId);
}
private string GetOrSetBasketCookie()
{
if (Request.Cookies.ContainsKey(Constants.BASKET_COOKIENAME))
{
return Request.Cookies[Constants.BASKET_COOKIENAME];
}
string anonymousId = Guid.NewGuid().ToString();
var cookieOptions = new CookieOptions();
cookieOptions.Expires = DateTime.Today.AddYears(10);
Response.Cookies.Append(Constants.BASKET_COOKIENAME, anonymousId, cookieOptions);
return anonymousId;
}
}
}

View File

@@ -1,72 +0,0 @@
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using ApplicationCore.Interfaces;
using Microsoft.AspNetCore.Http;
using Microsoft.eShopWeb.ViewModels;
namespace Microsoft.eShopWeb.Controllers
{
[Route("[controller]/[action]")]
public class BasketController : Controller
{
private readonly IBasketService _basketService;
private const string _basketSessionKey = "basketId";
private readonly IUriComposer _uriComposer;
public BasketController(IBasketService basketService,
IUriComposer uriComposer)
{
_basketService = basketService;
_uriComposer = uriComposer;
}
[HttpGet]
public async Task<IActionResult> Index()
{
var basketModel = await GetBasketFromSessionAsync();
return View(basketModel);
}
// POST: /Basket/AddToBasket
[HttpPost]
public async Task<IActionResult> AddToBasket(CatalogItemViewModel productDetails)
{
if (productDetails?.Id == null)
{
return RedirectToAction("Index", "Catalog");
}
var basket = await GetBasketFromSessionAsync();
await _basketService.AddItemToBasket(basket.Id, productDetails.Id, productDetails.Price, 1);
return RedirectToAction("Index");
}
[HttpPost]
public async Task<IActionResult> Checkout()
{
var basket = await GetBasketFromSessionAsync();
await _basketService.Checkout(basket.Id);
return View("Checkout");
}
private async Task<BasketViewModel> GetBasketFromSessionAsync()
{
string basketId = HttpContext.Session.GetString(_basketSessionKey);
BasketViewModel basket = null;
if (basketId == null)
{
basket = await _basketService.CreateBasketForUser(User.Identity.Name);
HttpContext.Session.SetString(_basketSessionKey, basket.Id.ToString());
}
else
{
basket = await _basketService.GetBasket(int.Parse(basketId));
}
return basket;
}
}
}