(feat): shop cart item controller

This commit is contained in:
Maksym Sadovnychyy 2022-08-14 22:27:55 +02:00
parent 1bb5e6728c
commit f20da5eb0f
21 changed files with 423 additions and 194 deletions

View File

@ -7,6 +7,7 @@ using System.Threading.Tasks;
namespace Core.Abstractions.Models { namespace Core.Abstractions.Models {
public abstract class RequestModelBase<T> : ModelBase { public abstract class RequestModelBase<T> : ModelBase {
public abstract T ApplyTo(T obj);
public abstract T ToDomainObject(); public abstract T ToDomainObject();
} }

View File

@ -1,27 +0,0 @@
using Core.Abstractions.DomainObjects;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Core.DomainObjects.Documents {
public class ShopCart : DomainObjectDocumentBase<ShopCart> {
public Guid SiteId { get; set; }
public Guid UserId { get; set; }
public string Slug { get; set; }
public string Sku { get; set; }
public Image Image { get; set; }
public string Title { get; set; }
public string BrandName { get; set; }
public string ShortText { get; set; }
public DateTime Created { get; set; }
public double Price { get; set; }
public double NewPrice { get; set; }
public uint Quantity { get; set; }
public override int GetHashCode() {
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,41 @@
using Core.Abstractions.DomainObjects;
namespace Core.DomainObjects.Documents {
public class ShopCartItem : DomainObjectDocumentBase<ShopCartItem> {
public Guid SiteId { get; set; }
public Guid UserId { get; set; }
public string Slug { get; set; }
public string Sku { get; set; }
public Image Image { get; set; }
public string Title { get; set; }
public string BrandName { get; set; }
public string ShortText { get; set; }
public DateTime Created { get; set; }
public double Price { get; set; }
public double NewPrice { get; set; }
public uint Quantity { get; set; }
public override int GetHashCode() {
// https://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-overriding-gethashcode
// Overflow is fine, just wrap
unchecked {
int hash = 17;
// Suitable nullity checks etc, of course :)
hash = hash * 23 + SiteId.GetHashCode();
hash = hash * 23 + UserId.GetHashCode();
hash = hash * 23 + Slug.GetHashCode();
hash = hash * 23 + Sku.GetHashCode();
hash = hash * 23 + Image.GetHashCode();
hash = hash * 23 + Title.GetHashCode();
hash = hash * 23 + BrandName.GetHashCode();
hash = hash * 23 + ShortText.GetHashCode();
hash = hash * 23 + Created.GetHashCode();
hash = hash * 23 + Price.GetHashCode();
hash = hash * 23 + NewPrice.GetHashCode();
hash = hash * 23 + Quantity.GetHashCode();
return hash;
}
}
}
}

View File

@ -1,7 +1,7 @@
using Core.Abstractions.DomainObjects; using Core.Abstractions.DomainObjects;
namespace Core.DomainObjects.Documents { namespace Core.DomainObjects.Documents {
public class ShopItem : PostItemBase<ShopItem> { public class ShopCatalogItem : PostItemBase<ShopCatalogItem> {
public string Sku { get; set; } public string Sku { get; set; }
public int Rating { get; set; } public int Rating { get; set; }

View File

@ -6,7 +6,10 @@ namespace Core.DomainObjects {
public string Alt { get; set; } public string Alt { get; set; }
public override int GetHashCode() { public override int GetHashCode() {
throw new NotImplementedException(); int hash = 17;
hash = hash * 23 + Src.GetHashCode();
hash = hash * 23 + Alt.GetHashCode();
return hash;
} }
} }
} }

View File

@ -290,8 +290,8 @@ namespace DataProviders {
#endregion #endregion
#region ShopItem #region ShopItem
if (!BsonClassMap.IsClassMapRegistered(typeof(ShopItem))) { if (!BsonClassMap.IsClassMapRegistered(typeof(ShopCatalogItem))) {
BsonClassMap.RegisterClassMap<ShopItem>(cm => { BsonClassMap.RegisterClassMap<ShopCatalogItem>(cm => {
cm.AutoMap(); cm.AutoMap();
}); });
} }

View File

@ -11,19 +11,42 @@ using Core.DomainObjects.Documents;
namespace DataProviders { namespace DataProviders {
public interface IShopCartDataProvider { public interface IShopCartDataProvider {
(List<ShopCart>?, IDomainResult) Get(Guid siteId, Guid userId); (Guid?, IDomainResult) Insert(ShopCartItem obj);
(List<ShopCartItem>?, IDomainResult) GetAll(Guid siteId, Guid userId);
(ShopCartItem?, IDomainResult) Get(Guid siteId, Guid userId, string sku);
(Guid?, IDomainResult) Update(ShopCartItem shopCart);
IDomainResult Delete(Guid siteId, Guid userId, string sku);
} }
public class ShopCartDataProvider : DataProviderBase<ShopCart>, IShopCartDataProvider { public class ShopCartDataProvider : DataProviderBase<ShopCartItem>, IShopCartDataProvider {
private const string _collectionName = "shopcart"; private const string _collectionName = "shopcart";
public ShopCartDataProvider( public ShopCartDataProvider(
ILogger<DataProviderBase<ShopCart>> logger, ILogger<DataProviderBase<ShopCartItem>> logger,
IMongoClient client, IMongoClient client,
IIdGenerator idGenerator, IIdGenerator idGenerator,
ISessionService sessionService) : base(logger, client, idGenerator, sessionService) { ISessionService sessionService) : base(logger, client, idGenerator, sessionService) {
} }
public (List<ShopCart>?, IDomainResult) Get(Guid siteId, Guid userId) => public (Guid?, IDomainResult) Insert(ShopCartItem obj) =>
Insert(obj, _collectionName);
public (List<ShopCartItem>?, IDomainResult) GetAll(Guid siteId, Guid userId) =>
GetWithPredicate(x => x.SiteId == siteId && x.UserId == userId, _collectionName); GetWithPredicate(x => x.SiteId == siteId && x.UserId == userId, _collectionName);
public (ShopCartItem?, IDomainResult) Get(Guid siteId, Guid userId, string sku) {
var (list, result) = GetWithPredicate(x => x.SiteId == siteId && x.UserId == userId && x.Sku == sku, _collectionName);
if (!result.IsSuccess || list == null || list.Count == 0)
return (null, result);
return (list.First(), result);
}
public (Guid?, IDomainResult) Update(ShopCartItem shopCart) =>
UpdateWithPredicate(shopCart, x => x.Id == shopCart.Id, _collectionName);
public IDomainResult Delete(Guid siteId, Guid userId, string sku) {
throw new NotImplementedException();
}
} }
} }

View File

@ -3,29 +3,29 @@ using Microsoft.AspNetCore.Mvc;
using WeatherForecast.Models; using WeatherForecast.Models;
namespace WeatherForecast.Controllers; namespace WeatherForecast.Controllers {
public class PostLoginRequest : RequestModelBase { //public class PostLoginRequest : RequestModelBase {
public string Username { get; set; } // public string Username { get; set; }
public string Password { get; set; } // public string Password { get; set; }
} //}
[ApiController] //[ApiController]
[Route("[controller]")] //[Route("[controller]")]
public class LoginController : ControllerBase { //public class LoginController : ControllerBase {
private readonly ILogger<LoginController> _logger; // private readonly ILogger<LoginController> _logger;
public LoginController(ILogger<LoginController> logger) { // public LoginController(ILogger<LoginController> logger) {
_logger = logger; // _logger = logger;
} // }
[HttpPost(Name = "Login")] // [HttpPost(Name = "Login")]
public IActionResult Post([FromBody] PostLoginRequest requestBody) { // public IActionResult Post([FromBody] PostLoginRequest requestBody) {
return BadRequest(); // return BadRequest();
} // }
} }

View File

@ -0,0 +1,84 @@
using DomainResults.Mvc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using WeatherForecast.Models.Requests;
using WeatherForecast.Services;
namespace WeatherForecast.Controllers {
/// <summary>
///
/// </summary>
[ApiController]
[AllowAnonymous]
[Route("api/[controller]")]
public class ShopCartItemController : ControllerBase {
private readonly ILogger<ContentController> _logger;
private readonly IShopCartItemService _shopCartItemService;
/// <summary>
///
/// </summary>
/// <param name="logger"></param>
public ShopCartItemController(
ILogger<ContentController> logger,
IShopCartItemService shopCartItemService
) {
_logger = logger;
_shopCartItemService = shopCartItemService;
}
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <param name="sku"></param>
/// <param name="requestData"></param>
/// <returns></returns>
[HttpPost("{siteId}/{userId}/{sku}")]
public IActionResult Post([FromRoute] Guid siteId, [FromRoute] Guid userId, [FromRoute] string sku, [FromBody] PostShopCartItemRequestModel requestData) {
var result = _shopCartItemService.Post(siteId, userId, sku, requestData);
return result.ToActionResult();
}
/// <summary>
///
/// </summary>
/// <returns></returns>
[HttpGet("{siteId}/{userId}/{sku}")]
public IActionResult Get([FromRoute] Guid siteId, [FromRoute] Guid userId, [FromRoute] string sku) {
var result = _shopCartItemService.Get(siteId, userId, sku);
return result.ToActionResult();
}
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <param name="sku"></param>
/// <param name="requestData"></param>
/// <returns></returns>
[HttpPut("{siteId}/{userId}/{sku}")]
public IActionResult Update([FromRoute] Guid siteId, [FromRoute] Guid userId, [FromRoute] string sku, [FromBody] PutShopCartItemRequestModel requestData) {
var result = _shopCartItemService.Update(siteId, userId, sku, requestData);
return result.ToActionResult();
}
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <param name="sku"></param>
/// <returns></returns>
[HttpDelete("{siteId}/{userId}/{sku}")]
public IActionResult Delete([FromRoute] Guid siteId, [FromRoute] Guid userId, [FromRoute] string sku) {
var result = _shopCartItemService.Delete(siteId, userId, sku);
return result.ToActionResult();
}
}
}

View File

@ -13,21 +13,21 @@ namespace WeatherForecast.Controllers {
[ApiController] [ApiController]
[AllowAnonymous] [AllowAnonymous]
[Route("api/[controller]")] [Route("api/[controller]")]
public class ShopCartController : ControllerBase { public class ShopCartItemsController : ControllerBase {
private readonly ILogger<ContentController> _logger; private readonly ILogger<ContentController> _logger;
private readonly IShopCartService _shopCartService; private readonly IShopCartItemsService _shopCartItemsService;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="logger"></param> /// <param name="logger"></param>
public ShopCartController( public ShopCartItemsController(
ILogger<ContentController> logger, ILogger<ContentController> logger,
IShopCartService shopCartService IShopCartItemsService shopCartItemsService
) { ) {
_logger = logger; _logger = logger;
_shopCartService = shopCartService; _shopCartItemsService = shopCartItemsService;
} }
/// <summary> /// <summary>
@ -36,14 +36,9 @@ namespace WeatherForecast.Controllers {
/// <returns></returns> /// <returns></returns>
[HttpGet("{siteId}/{userId}")] [HttpGet("{siteId}/{userId}")]
public IActionResult Get([FromRoute] Guid siteId, [FromRoute] Guid userId) { public IActionResult Get([FromRoute] Guid siteId, [FromRoute] Guid userId) {
var result = _shopCartService.GetShopCart(siteId, userId); var result = _shopCartItemsService.Get(siteId, userId);
return result.ToActionResult(); return result.ToActionResult();
} }
[HttpPut("{siteId}/{userId}/{shopCartId}")]
public IActionResult Update([FromRoute] Guid siteId, [FromRoute] Guid userId, [FromRoute] Guid shopCartId, [FromBody] PutShopCatalogRequestModel requestData) {
var result = _shopCartService.UpdateShopCart(siteId, userId, shopCartId, requestData);
return result.ToActionResult();
}
} }
} }

View File

@ -0,0 +1,37 @@
using Core.Abstractions.Models;
using Core.DomainObjects;
using Core.DomainObjects.Documents;
namespace WeatherForecast.Models.Requests {
public class PostShopCartItemRequestModel : RequestModelBase<ShopCartItem> {
public string Slug { get; set; }
public ImageModel Image { get; set; }
public string Title { get; set; }
public string BrandName { get; set; }
public string ShortText { get; set; }
public DateTime Created { get; set; }
public double Price { get; set; }
public double NewPrice { get; set; }
public uint Quantity { get; set; }
public override ShopCartItem ApplyTo(ShopCartItem shopCart) {
shopCart.Slug = Slug;
shopCart.Image = new Image {
Src = Image.Src,
Alt = Image.Alt
};
shopCart.Title = Title;
shopCart.BrandName = BrandName;
shopCart.ShortText = ShortText;
shopCart.Created = Created;
shopCart.Price = Price;
shopCart.NewPrice = NewPrice;
shopCart.Quantity = Quantity;
return shopCart;
}
public override ShopCartItem ToDomainObject() => ApplyTo(new ShopCartItem());
}
}

View File

@ -0,0 +1,37 @@
using Core.Abstractions.Models;
using Core.DomainObjects;
using Core.DomainObjects.Documents;
namespace WeatherForecast.Models.Requests {
public class PutShopCartItemRequestModel : RequestModelBase<ShopCartItem> {
public string Slug { get; set; }
public ImageModel Image { get; set; }
public string Title { get; set; }
public string BrandName { get; set; }
public string ShortText { get; set; }
public DateTime Created { get; set; }
public double Price { get; set; }
public double NewPrice { get; set; }
public uint Quantity { get; set; }
public override ShopCartItem ApplyTo(ShopCartItem shopCart) {
shopCart.Slug = Slug;
shopCart.Image = new Image {
Src = Image.Src,
Alt = Image.Alt
};
shopCart.Title = Title;
shopCart.BrandName = BrandName;
shopCart.ShortText = ShortText;
shopCart.Created = Created;
shopCart.Price = Price;
shopCart.NewPrice = NewPrice;
shopCart.Quantity = Quantity;
return shopCart;
}
public override ShopCartItem ToDomainObject() => ApplyTo(new ShopCartItem());
}
}

View File

@ -1,37 +0,0 @@
using Core.Abstractions.Models;
using Core.DomainObjects;
using Core.DomainObjects.Documents;
namespace WeatherForecast.Models.Requests {
public class PutShopCatalogRequestModel : RequestModelBase<ShopCart> {
public string Slug { get; set; }
public string Sku { get; set; }
public ImageModel Image { get; set; }
public string Title { get; set; }
public string BrandName { get; set; }
public string ShortText { get; set; }
public DateTime Created { get; set; }
public double Price { get; set; }
public double NewPrice { get; set; }
public uint Quantity { get; set; }
public override ShopCart ToDomainObject() {
return new ShopCart {
Slug = Slug,
Sku = Sku,
Image = new Image {
Src = Image.Src,
Alt = Image.Alt
},
Title = Title,
BrandName = BrandName,
ShortText = ShortText,
Created = Created,
Price = Price,
NewPrice = NewPrice,
Quantity = Quantity
};
}
}
}

View File

@ -0,0 +1,33 @@
using Core.Abstractions.Models;
using Core.DomainObjects.Documents;
namespace WeatherForecast.Models.Responses {
public class GetShopCartItemResponseModel : ResponseModelBase {
public string Slug { get; set; }
public string Sku { get; set; }
public ImageModel Image { get; set; }
public string Title { get; set; }
public string BrandName { get; set; }
public string ShortText { get; set; }
public DateTime Created { get; set; }
public double Price { get; set; }
public double NewPrice { get; set; }
public uint Quantity { get; set; }
public GetShopCartItemResponseModel() { }
public GetShopCartItemResponseModel(ShopCartItem shopCartItem) {
Slug = shopCartItem.Slug;
Sku = shopCartItem.Sku;
Image = new ImageModel(shopCartItem.Image);
Title = shopCartItem.Title;
BrandName = shopCartItem.BrandName;
ShortText = shopCartItem.ShortText;
Created = shopCartItem.Created;
Price = shopCartItem.Price;
NewPrice = shopCartItem.NewPrice;
Quantity = shopCartItem.Quantity;
}
}
}

View File

@ -0,0 +1,14 @@
using Core.Abstractions.Models;
using Core.DomainObjects.Documents;
namespace WeatherForecast.Models.Responses {
public class GetShopCartItemsResponseModel : ResponseModelBase {
public List<GetShopCartItemResponseModel> Items { get; set; }
public GetShopCartItemsResponseModel(List<ShopCartItem> items) {
Items = items.Select(x => new GetShopCartItemResponseModel(x)).ToList();
}
}
}

View File

@ -1,14 +0,0 @@
using Core.Abstractions.Models;
using Core.DomainObjects.Documents;
namespace WeatherForecast.Models.Responses {
public class GetShopCartResponseModel : ResponseModelBase {
public List<ShopCartModel> Items { get; set; }
public GetShopCartResponseModel(List<ShopCart> items) {
Items = items.Select(x => new ShopCartModel(x)).ToList();
}
}
}

View File

@ -1,33 +0,0 @@
using Core.Abstractions.Models;
using Core.DomainObjects.Documents;
namespace WeatherForecast.Models {
public class ShopCartModel : ModelBase {
public string Slug { get; set; }
public string Sku { get; set; }
public ImageModel Image { get; set; }
public string Title { get; set; }
public string BrandName { get; set; }
public string ShortText { get; set; }
public DateTime Created { get; set; }
public double Price { get; set; }
public double NewPrice { get; set; }
public uint Quantity { get; set; }
public ShopCartModel() { }
public ShopCartModel(ShopCart shopCart) {
Slug = shopCart.Slug;
Sku = shopCart.Sku;
Image = new ImageModel(shopCart.Image);
Title = shopCart.Title;
BrandName = shopCart.BrandName;
ShortText = shopCart.ShortText;
Created = shopCart.Created;
Price = shopCart.Price;
NewPrice = shopCart.NewPrice;
Quantity = shopCart.Quantity;
}
}
}

View File

@ -0,0 +1,81 @@
using DataProviders;
using DomainResults.Common;
using WeatherForecast.Models.Requests;
using WeatherForecast.Models.Responses;
namespace WeatherForecast.Services {
public interface IShopCartItemService {
(Guid?, IDomainResult) Post(Guid siteId, Guid userId, string sku, PostShopCartItemRequestModel requestModel);
(GetShopCartItemResponseModel?, IDomainResult) Get(Guid siteId, Guid userId, string sku);
(Guid?, IDomainResult) Update(Guid siteId, Guid userId, string sku, PutShopCartItemRequestModel requestData);
IDomainResult Delete(Guid siteId, Guid userId, string sku);
}
public class ShopCartItemService : IShopCartItemService {
ILogger<ShopCartItemService> _logger;
IShopCartDataProvider _shopCartDataProvider;
public ShopCartItemService(
ILogger<ShopCartItemService> logger,
IShopCartDataProvider shopCartDataprovider
) {
_logger = logger;
_shopCartDataProvider = shopCartDataprovider;
}
public (Guid?, IDomainResult) Post(Guid siteId, Guid userId, string sku, PostShopCartItemRequestModel requestModel) {
var (_, getResult) = _shopCartDataProvider.Get(siteId, userId, sku);
if (getResult.IsSuccess)
return IDomainResult.Failed<Guid?>();
var obj = requestModel.ToDomainObject();
obj.SiteId = siteId;
obj.UserId = userId;
obj.Sku = sku;
var (id, insertResult) = _shopCartDataProvider.Insert(obj);
if (!insertResult.IsSuccess)
return IDomainResult.Failed<Guid?>();
return IDomainResult.Success(id);
}
public (GetShopCartItemResponseModel?, IDomainResult) Get(Guid siteId, Guid userId, string sku) {
var (item, result) = _shopCartDataProvider.Get(siteId, userId, sku);
if (!result.IsSuccess || item == null)
return (null, result);
return IDomainResult.Success(new GetShopCartItemResponseModel(item));
}
public (Guid?, IDomainResult) Update(Guid siteId, Guid userId, string sku, PutShopCartItemRequestModel requestData) {
var (item, getResult) = _shopCartDataProvider.Get(siteId, userId, sku);
if (!getResult.IsSuccess || item == null)
return (null, getResult);
var newShopCart = requestData.ApplyTo(item);
if (!item.Equals(newShopCart)) {
var (id, updateResult) = _shopCartDataProvider.Update(item);
if (!updateResult.IsSuccess || id == null)
return (null, updateResult);
}
return IDomainResult.Success(item.Id);
}
public IDomainResult Delete(Guid siteId, Guid userId, string sku) {
var result = _shopCartDataProvider.Delete(siteId, userId, sku);
if (!result.IsSuccess)
return result;
return IDomainResult.Success();
}
}
}

View File

@ -0,0 +1,36 @@
using DataProviders;
using DomainResults.Common;
using WeatherForecast.Models.Requests;
using WeatherForecast.Models.Responses;
namespace WeatherForecast.Services {
public interface IShopCartItemsService {
(GetShopCartItemsResponseModel?, IDomainResult) Get(Guid siteId, Guid userId);
}
public class ShopCartItemsService : IShopCartItemsService {
ILogger<ShopCartItemsService> _logger;
IShopCartDataProvider _shopCartDataProvider;
public ShopCartItemsService(
ILogger<ShopCartItemsService> logger,
IShopCartDataProvider shopCartDataprovider
) {
_logger = logger;
_shopCartDataProvider = shopCartDataprovider;
}
public (GetShopCartItemsResponseModel?, IDomainResult) Get(Guid siteId, Guid userId) {
var (items, result) = _shopCartDataProvider.GetAll(siteId, userId);
if (!result.IsSuccess || items == null)
return (null, result);
return IDomainResult.Success(new GetShopCartItemsResponseModel(items));
}
}
}

View File

@ -1,46 +0,0 @@
using DataProviders;
using DomainResults.Common;
using WeatherForecast.Models.Requests;
using WeatherForecast.Models.Responses;
namespace WeatherForecast.Services {
public interface IShopCartService {
(GetShopCartResponseModel?, IDomainResult) GetShopCart(Guid siteId, Guid userId);
(Guid?, IDomainResult) UpdateShopCart(Guid siteId, Guid userId, Guid shopCartId, PutShopCatalogRequestModel requestData);
}
public class ShopCartService : IShopCartService {
ILogger<ShopCartService> _logger;
IShopCartDataProvider _shopCartDataProvider;
public ShopCartService(
ILogger<ShopCartService> logger,
IShopCartDataProvider shopCartDataprovider
) {
_logger = logger;
_shopCartDataProvider = shopCartDataprovider;
}
public (GetShopCartResponseModel?, IDomainResult) GetShopCart(Guid siteId, Guid userId) {
var (items, result) = _shopCartDataProvider.Get(siteId, userId);
if (!result.IsSuccess || items == null)
return (null, result);
return IDomainResult.Success(new GetShopCartResponseModel(items));
}
public (Guid?, IDomainResult) UpdateShopCart(Guid siteId, Guid userId, Guid shopCartId, PutShopCatalogRequestModel requestData) {
var shopCart = requestData.ToDomainObject();
shopCart.Id = shopCartId;
shopCart.SiteId = siteId;
shopCart.UserId = userId;
return IDomainResult.Failed<Guid?>();
}
}
}

View File

@ -58,7 +58,8 @@ namespace WeatherForecast {
services.AddHttpContextAccessor(); services.AddHttpContextAccessor();
services.AddScoped<IContentService, ContentService>(); services.AddScoped<IContentService, ContentService>();
services.AddScoped<IShopCartService, ShopCartService>(); services.AddScoped<IShopCartItemService, ShopCartItemService>();
services.AddScoped<IShopCartItemsService, ShopCartItemsService>();
services.RegisterDataproviders(appSettings); services.RegisterDataproviders(appSettings);