From 3506afda39d372a901d37648b5072c7d82ed05ec Mon Sep 17 00:00:00 2001 From: Maksym Sadovnychyy Date: Thu, 18 Aug 2022 21:04:24 +0200 Subject: [PATCH] (feat): shop item dataprovider and controllers --- db/DML/shopcart.json | 6 +- db/DML/shopcatalog.json | 187 ++++++++++++++++++ postman/reactredux.postman_collection.json | 159 ++++++++++++++- .../Abstractions/DomainObjects/Category.cs | 1 + .../DomainObjects/PostItemBase.cs | 26 +-- .../Models/PaginationModelBase.cs | 6 + .../Abstractions/Models/RequestModelBase.cs | 2 +- webapi/Core/DomainObjects/Author.cs | 15 +- .../Core/DomainObjects/Documents/BlogItem.cs | 4 +- .../DomainObjects/Documents/ShopCartItem.cs | 6 +- .../Documents/ShopCatalogItem.cs | 16 -- .../Core/DomainObjects/Documents/ShopItem.cs | 39 ++++ .../Abstractions/DataProviderBase.cs | 10 +- webapi/DataProviders/ContentDataProvider.cs | 2 +- .../Extensions/ServiceCollectionExtensions.cs | 1 + webapi/DataProviders/Mappings.cs | 4 +- webapi/DataProviders/ShopCartDataProvider.cs | 4 +- .../DataProviders/ShopCatalogDataProvider.cs | 52 +++++ .../Controllers/BlogCatalogController.cs | 44 ++--- .../Controllers/BlogFeaturedController.cs | 29 +-- .../Controllers/ContentController.cs | 2 +- .../Controllers/ShopCatalogController.cs | 72 ------- .../Controllers/ShopItemController.cs | 18 +- .../Controllers/ShopItemsController.cs | 42 ++++ .../Controllers/ShopRelatedController.cs | 3 + .../Models/Abstractions/PersonModelBase.cs | 10 +- ...delBase.cs => PostItemRequestModelBase.cs} | 10 +- .../Abstractions/PostItemResponseModelBase.cs | 37 ++++ webapi/WeatherForecast/Models/AuthorModel.cs | 9 +- .../WeatherForecast/Models/BlogItemModel.cs | 16 +- .../Requests/PostShopCartItemRequestModel.cs | 2 +- .../Requests/PostShopItemRequestModel.cs | 32 +++ .../Requests/PutShopCartItemRequestModel.cs | 2 +- .../Requests/PutShopItemRequestModel.cs | 10 + .../Responses/GetShopCatalogResponseModel.cs | 8 - .../Responses/GetShopItemResponseModel.cs | 23 +++ .../Responses/GetShopItemsResponseModel.cs | 9 + .../WeatherForecast/Models/ReviewerModel.cs | 4 +- .../WeatherForecast/Models/ShopItemModel.cs | 16 -- .../Services/ShopItemService.cs | 85 ++++++++ .../Services/ShopItemsService.cs | 33 ++++ webapi/WeatherForecast/Startup.cs | 2 + 42 files changed, 828 insertions(+), 230 deletions(-) create mode 100644 db/DML/shopcatalog.json delete mode 100644 webapi/Core/DomainObjects/Documents/ShopCatalogItem.cs create mode 100644 webapi/Core/DomainObjects/Documents/ShopItem.cs create mode 100644 webapi/DataProviders/ShopCatalogDataProvider.cs delete mode 100644 webapi/WeatherForecast/Controllers/ShopCatalogController.cs create mode 100644 webapi/WeatherForecast/Controllers/ShopItemsController.cs rename webapi/WeatherForecast/Models/Abstractions/{PostItemModelBase.cs => PostItemRequestModelBase.cs} (58%) create mode 100644 webapi/WeatherForecast/Models/Abstractions/PostItemResponseModelBase.cs create mode 100644 webapi/WeatherForecast/Models/Requests/PostShopItemRequestModel.cs create mode 100644 webapi/WeatherForecast/Models/Requests/PutShopItemRequestModel.cs delete mode 100644 webapi/WeatherForecast/Models/Responses/GetShopCatalogResponseModel.cs create mode 100644 webapi/WeatherForecast/Models/Responses/GetShopItemResponseModel.cs create mode 100644 webapi/WeatherForecast/Models/Responses/GetShopItemsResponseModel.cs delete mode 100644 webapi/WeatherForecast/Models/ShopItemModel.cs create mode 100644 webapi/WeatherForecast/Services/ShopItemService.cs create mode 100644 webapi/WeatherForecast/Services/ShopItemsService.cs diff --git a/db/DML/shopcart.json b/db/DML/shopcart.json index 0947b41..72f783b 100644 --- a/db/DML/shopcart.json +++ b/db/DML/shopcart.json @@ -6,7 +6,7 @@ "slug": "shop-catalog-item", "sku": "SKU-01", "image": { "src": "https://dummyimage.com/450x300/dee2e6/6c757d.jpg", "alt": "..." }, - "title": "Shop item title", + "title": "Mongo Shop item title", "brandName": "Brand & Name", "shortText": "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...", "created": { "$date": "2022-01-01T00:00:00.000Z" }, @@ -21,7 +21,7 @@ "slug": "shop-catalog-item", "sku": "SKU-02", "image": { "src": "https://dummyimage.com/450x300/dee2e6/6c757d.jpg", "alt": "..." }, - "title": "Shop item title", + "title": "Mongo Shop item title", "brandName": "Brand & Name", "shortText": "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...", "created": { "$date": "2022-01-01T00:00:00.000Z" }, @@ -36,7 +36,7 @@ "slug": "shop-catalog-item", "sku": "SKU-03", "image": { "src": "https://dummyimage.com/450x300/dee2e6/6c757d.jpg", "alt": "..." }, - "title": "Shop item title", + "title": "Mongo Shop item title", "brandName": "Brand & Name", "shortText": "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...", "created": { "$date": "2022-01-01T00:00:00.000Z" }, diff --git a/db/DML/shopcatalog.json b/db/DML/shopcatalog.json new file mode 100644 index 0000000..c0e46bb --- /dev/null +++ b/db/DML/shopcatalog.json @@ -0,0 +1,187 @@ +[ + { + "_id": "e2dd785c-f036-453a-886b-d842b7c31366", + "siteId": "404c8232-9048-4519-bfba-6e78dc7005ca", + "slug": "shop-catalog-item", + + "images": [ + { + "src": "https://dummyimage.com/450x300/dee2e6/6c757d.jpg", + "alt": "..." + } + ], + "title": "Shop item title", + "shortText": "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...", + "text": "", + "author": { + "_id": "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60", + "image": { + "src": "https://dummyimage.com/40x40/ced4da/6c757d", + "alt": "..." + }, + "nickName": "Admin" + }, + "created": { + "$date": "2022-01-01T00:00:00.000Z" + }, + "badges": [ + "sale" + ], + "tags": [ + "react", + "redux", + "webapi" + ], + "categories": [ + { + "_id": "e154e33f-3cc7-468d-bb66-e0390ddb9ae0", + "slug": "default", + "text": "Default category" + } + ], + "brandName": "Mongodb Brand & Name", + "sku": "SKU-01", + "rating": 4.5, + "price": 20, + "newPrice": 10, + "quantity": 100 + }, + { + "_id": "055ede3f-7449-47d1-83b1-387dc3573711", + "siteId": "404c8232-9048-4519-bfba-6e78dc7005ca", + "slug": "shop-catalog-item", + "images": [ + { + "src": "https://dummyimage.com/450x300/dee2e6/6c757d.jpg", + "alt": "..." + } + ], + "title": "Shop item title", + "shortText": "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...", + "text": "", + "author": { + "_id": "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60", + "image": { + "src": "https://dummyimage.com/40x40/ced4da/6c757d", + "alt": "..." + }, + "nickName": "Admin" + }, + "created": { + "$date": "2022-01-01T00:00:00.000Z" + }, + "badges": [ + "sale" + ], + "tags": [ + "react", + "redux", + "webapi" + ], + "categories": [ + { + "_id": "e154e33f-3cc7-468d-bb66-e0390ddb9ae0", + "slug": "default", + "text": "Default category" + } + ], + "brandName": "Mongodb Brand & Name", + "sku": "SKU-02", + "rating": 4.5, + "price": 20, + "newPrice": 10, + "quantity": 100 + }, + { + "_id": "d17accca-6666-43ef-a91f-b63604e6113c", + "siteId": "404c8232-9048-4519-bfba-6e78dc7005ca", + "slug": "shop-catalog-item", + "images": [ + { + "src": "https://dummyimage.com/450x300/dee2e6/6c757d.jpg", + "alt": "..." + } + ], + "brandName": "Brand & Name", + "shortText": "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...", + "text": "", + "author": { + "_id": "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60", + "image": { + "src": "https://dummyimage.com/40x40/ced4da/6c757d", + "alt": "..." + }, + "nickName": "Admin" + }, + "created": { + "$date": "2022-01-01T00:00:00.000Z" + }, + "badges": [ + "sale" + ], + "tags": [ + "react", + "redux", + "webapi" + ], + "categories": [ + { + "_id": "e154e33f-3cc7-468d-bb66-e0390ddb9ae0", + "slug": "default", + "text": "Default category" + } + ], + "brandName": "Mongodb Brand & Name", + "sku": "SKU-03", + "rating": 4.5, + "price": 20, + "newPrice": 10, + "quantity": 100 + }, + { + "_id": "0dc37621-0925-41d8-90db-552224d59c2a", + "siteId": "404c8232-9048-4519-bfba-6e78dc7005ca", + "slug": "shop-catalog-item", + "images": [ + { + "src": "https://dummyimage.com/450x300/dee2e6/6c757d.jpg", + "alt": "..." + } + ], + "title": "Shop item title", + "shortText": "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...", + "text": "", + "author": { + "_id": "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60", + "image": { + "src": "https://dummyimage.com/40x40/ced4da/6c757d", + "alt": "..." + }, + "nickName": "Admin" + }, + "created": { + "$date": "2022-01-01T00:00:00.000Z" + }, + "badges": [ + "sale" + ], + "tags": [ + "react", + "redux", + "webapi" + ], + "categories": [ + { + "_id": "e154e33f-3cc7-468d-bb66-e0390ddb9ae0", + "slug": "default", + "text": "Default category" + } + ], + "brandName": "Mongodb Brand & Name", + "sku": "SKU-04", + "rating": 4.5, + "price": 20, + "newPrice": 10, + "quantity": 100 + } +] \ No newline at end of file diff --git a/postman/reactredux.postman_collection.json b/postman/reactredux.postman_collection.json index b1f7531..f6a6228 100644 --- a/postman/reactredux.postman_collection.json +++ b/postman/reactredux.postman_collection.json @@ -9,7 +9,7 @@ "name": "Content", "item": [ { - "name": "GetContent", + "name": "01-Get", "request": { "method": "GET", "header": [ @@ -49,10 +49,10 @@ ] }, { - "name": "ShopCart", + "name": "ShopCartItems", "item": [ { - "name": "GetShopCart", + "name": "01-Get", "request": { "method": "GET", "header": [ @@ -68,7 +68,7 @@ } ], "url": { - "raw": "https://localhost:7151/api/ShopCart/404c8232-9048-4519-bfba-6e78dc7005ca/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60", + "raw": "https://localhost:7151/api/ShopCartItems/404c8232-9048-4519-bfba-6e78dc7005ca/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60", "protocol": "https", "host": [ "localhost" @@ -76,7 +76,7 @@ "port": "7151", "path": [ "api", - "ShopCart", + "ShopCartItems", "404c8232-9048-4519-bfba-6e78dc7005ca", "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60" ] @@ -85,6 +85,155 @@ "response": [] } ] + }, + { + "name": "ShopCartItem", + "item": [ + { + "name": "01-Get", + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "default" + }, + { + "key": "Accept", + "value": "application/json", + "type": "default" + } + ], + "url": { + "raw": "https://localhost:7151/api/ShopCartItem/404c8232-9048-4519-bfba-6e78dc7005ca/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60/SKU-01", + "protocol": "https", + "host": [ + "localhost" + ], + "port": "7151", + "path": [ + "api", + "ShopCartItem", + "404c8232-9048-4519-bfba-6e78dc7005ca", + "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60", + "SKU-01" + ] + } + }, + "response": [] + }, + { + "name": "02-Post", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "default" + }, + { + "key": "Accept", + "value": "application/json", + "type": "default" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"slug\": \"shop-catalog-item\",\r\n \"image\": {\r\n \"src\": \"https://dummyimage.com/450x300/dee2e6/6c757d.jpg\",\r\n \"alt\": \"...\"\r\n },\r\n \"title\": \"Shop item title\",\r\n \"brandName\": \"Brand & Name\",\r\n \"shortText\": \"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...\",\r\n \"created\": \"2022-01-01T00:00:00Z\",\r\n \"price\": 20,\r\n \"newPrice\": 10,\r\n \"quantity\": 1\r\n}" + }, + "url": { + "raw": "https://localhost:7151/api/ShopCartItem/404c8232-9048-4519-bfba-6e78dc7005ca/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60/SKU-04", + "protocol": "https", + "host": [ + "localhost" + ], + "port": "7151", + "path": [ + "api", + "ShopCartItem", + "404c8232-9048-4519-bfba-6e78dc7005ca", + "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60", + "SKU-04" + ] + } + }, + "response": [] + }, + { + "name": "03-Put", + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "default" + }, + { + "key": "Accept", + "value": "application/json", + "type": "default" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"slug\": \"shop-catalog-item\",\r\n \"image\": {\r\n \"src\": \"https://dummyimage.com/450x300/dee2e6/6c757d.jpg\",\r\n \"alt\": \"...\"\r\n },\r\n \"title\": \"Shop item title\",\r\n \"brandName\": \"New Brand & Name\",\r\n \"shortText\": \"Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...\",\r\n \"created\": \"2022-01-01T00:00:00Z\",\r\n \"price\": 40,\r\n \"newPrice\": 50,\r\n \"quantity\": 2\r\n}" + }, + "url": { + "raw": "https://localhost:7151/api/ShopCartItem/404c8232-9048-4519-bfba-6e78dc7005ca/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60/SKU-04", + "protocol": "https", + "host": [ + "localhost" + ], + "port": "7151", + "path": [ + "api", + "ShopCartItem", + "404c8232-9048-4519-bfba-6e78dc7005ca", + "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60", + "SKU-04" + ] + } + }, + "response": [] + }, + { + "name": "04-Delete", + "request": { + "method": "DELETE", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "default" + }, + { + "key": "Accept", + "value": "application/json", + "type": "default" + } + ], + "url": { + "raw": "https://localhost:7151/api/ShopCartItem/404c8232-9048-4519-bfba-6e78dc7005ca/fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60/SKU-04", + "protocol": "https", + "host": [ + "localhost" + ], + "port": "7151", + "path": [ + "api", + "ShopCartItem", + "404c8232-9048-4519-bfba-6e78dc7005ca", + "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60", + "SKU-04" + ] + } + }, + "response": [] + } + ] } ] } \ No newline at end of file diff --git a/webapi/Core/Abstractions/DomainObjects/Category.cs b/webapi/Core/Abstractions/DomainObjects/Category.cs index 2db22a0..480e2e3 100644 --- a/webapi/Core/Abstractions/DomainObjects/Category.cs +++ b/webapi/Core/Abstractions/DomainObjects/Category.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; namespace Core.Abstractions.DomainObjects { public class Category { public Guid Id { get; set; } + public string Slug { get; set; } public string Text { get; set; } } } diff --git a/webapi/Core/Abstractions/DomainObjects/PostItemBase.cs b/webapi/Core/Abstractions/DomainObjects/PostItemBase.cs index 8cf7b0c..5e2b189 100644 --- a/webapi/Core/Abstractions/DomainObjects/PostItemBase.cs +++ b/webapi/Core/Abstractions/DomainObjects/PostItemBase.cs @@ -9,28 +9,28 @@ namespace Core.Abstractions.DomainObjects { public abstract class PostItemBase : DomainObjectDocumentBase { - public List Images { get; set; } + public Guid SiteId { get; set; } - /// - /// Author / Owner - /// - public Guid UserId { get; set; } + public string Slug { get; set; } + + public List Images { get; set; } public string Title { get; set; } public string Text { get; set; } - public string Badge { get; set; } + public string ShortText { get; set; } - public List Tags { get; set; } - - public List Categories { get; set; } + public Author Author { get; set; } public DateTime Created { get; set; } - /// - /// Edit dateTime, and Author - /// - public Dictionary Edited { get; set; } + public List Badges { get; set; } + + public List Tags { get; set; } + + public List Categories { get; set; } + + } } diff --git a/webapi/Core/Abstractions/Models/PaginationModelBase.cs b/webapi/Core/Abstractions/Models/PaginationModelBase.cs index 340c10e..50aebcf 100644 --- a/webapi/Core/Abstractions/Models/PaginationModelBase.cs +++ b/webapi/Core/Abstractions/Models/PaginationModelBase.cs @@ -11,5 +11,11 @@ namespace Core.Models { public int TotalPages { get; set; } public int CurrentPage { get; set; } public List Items { get; set; } + + public PaginationModelBase(int currentPage, int totalPages, List items) { + CurrentPage = currentPage; + TotalPages = totalPages; + Items = items; + } } } diff --git a/webapi/Core/Abstractions/Models/RequestModelBase.cs b/webapi/Core/Abstractions/Models/RequestModelBase.cs index b539d65..77b0489 100644 --- a/webapi/Core/Abstractions/Models/RequestModelBase.cs +++ b/webapi/Core/Abstractions/Models/RequestModelBase.cs @@ -5,7 +5,7 @@ using System.Text; using System.Threading.Tasks; namespace Core.Abstractions.Models { - public abstract class RequestModelBase : ModelBase { + public abstract class PostItemRequestModel : ModelBase { public abstract T ToDomainObject(); } } diff --git a/webapi/Core/DomainObjects/Author.cs b/webapi/Core/DomainObjects/Author.cs index 6dbc752..84a2d97 100644 --- a/webapi/Core/DomainObjects/Author.cs +++ b/webapi/Core/DomainObjects/Author.cs @@ -1,16 +1,19 @@ using Core.Abstractions.DomainObjects; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Core.DomainObjects { public class Author : PersonBase{ public string NickName { get; set; } public override int GetHashCode() { - throw new NotImplementedException(); + unchecked { + int hash = 17; + hash = hash * 23 + Id.GetHashCode(); + if(Image != null) + hash = hash * 23 + Image.GetHashCode(); + hash = hash * 23 + NickName.GetHashCode(); + + return hash; + } } } } diff --git a/webapi/Core/DomainObjects/Documents/BlogItem.cs b/webapi/Core/DomainObjects/Documents/BlogItem.cs index f73b383..d9a04cf 100644 --- a/webapi/Core/DomainObjects/Documents/BlogItem.cs +++ b/webapi/Core/DomainObjects/Documents/BlogItem.cs @@ -3,9 +3,9 @@ namespace Core.DomainObjects.Documents { public class BlogItem : PostItemBase { - public int? ReadTime { get; set; } + public uint? ReadTime { get; set; } - public int? Likes { get; set; } + public uint? Likes { get; set; } public override int GetHashCode() { throw new NotImplementedException(); diff --git a/webapi/Core/DomainObjects/Documents/ShopCartItem.cs b/webapi/Core/DomainObjects/Documents/ShopCartItem.cs index 47c58db..1dfa74d 100644 --- a/webapi/Core/DomainObjects/Documents/ShopCartItem.cs +++ b/webapi/Core/DomainObjects/Documents/ShopCartItem.cs @@ -19,9 +19,9 @@ namespace Core.DomainObjects.Documents { // 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 :) + // Suitable nullity checks etc, of course :) + hash = hash * 23 + Id.GetHashCode(); hash = hash * 23 + SiteId.GetHashCode(); hash = hash * 23 + UserId.GetHashCode(); hash = hash * 23 + Slug.GetHashCode(); @@ -35,7 +35,7 @@ namespace Core.DomainObjects.Documents { hash = hash * 23 + NewPrice.GetHashCode(); hash = hash * 23 + Quantity.GetHashCode(); return hash; - } + } } } } diff --git a/webapi/Core/DomainObjects/Documents/ShopCatalogItem.cs b/webapi/Core/DomainObjects/Documents/ShopCatalogItem.cs deleted file mode 100644 index be4d314..0000000 --- a/webapi/Core/DomainObjects/Documents/ShopCatalogItem.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Core.Abstractions.DomainObjects; - -namespace Core.DomainObjects.Documents { - public class ShopCatalogItem : PostItemBase { - - public string Sku { get; set; } - public int Rating { get; set; } - public int Price { get; set; } - public int NewPrice { get; set; } - public int Quantity { get; set; } - - public override int GetHashCode() { - throw new NotImplementedException(); - } - } -} diff --git a/webapi/Core/DomainObjects/Documents/ShopItem.cs b/webapi/Core/DomainObjects/Documents/ShopItem.cs new file mode 100644 index 0000000..2b7011c --- /dev/null +++ b/webapi/Core/DomainObjects/Documents/ShopItem.cs @@ -0,0 +1,39 @@ +using Core.Abstractions.DomainObjects; + +namespace Core.DomainObjects.Documents { + public class ShopItem : PostItemBase { + public string BrandName { get; set; } + public string Sku { get; set; } + public decimal? Rating { get; set; } + public double Price { get; set; } + public double? NewPrice { get; set; } + public uint? Quantity { get; set; } + + public override int GetHashCode() { + unchecked { + int hash = 17; + hash = hash * 23 + Id.GetHashCode(); + hash = hash * 23 + SiteId.GetHashCode(); + hash = hash * 23 + Slug.GetHashCode(); + hash = hash * 23 + Images.Sum(x => x.GetHashCode()); + hash = hash * 23 + Title.GetHashCode(); + hash = hash * 23 + Text.GetHashCode(); + hash = hash * 23 + ShortText.GetHashCode(); + hash = hash * 23 + Author.GetHashCode(); + hash = hash * 23 + Created.GetHashCode(); + hash = hash * 23 + Badges.Sum(x => x.GetHashCode()); + hash = hash * 23 + Tags.Sum(x => x.GetHashCode()); + hash = hash * 23 + Categories.Sum(x => x.GetHashCode()); + + hash = hash * 23 + BrandName.GetHashCode(); + hash = hash * 23 + Sku.GetHashCode(); + hash = hash * 23 + Rating.GetHashCode(); + hash = hash * 23 + Price.GetHashCode(); + hash = hash * 23 + NewPrice.GetHashCode(); + hash = hash * 23 + Quantity.GetHashCode(); + + return hash; + } + } + } +} diff --git a/webapi/DataProviders/Abstractions/DataProviderBase.cs b/webapi/DataProviders/Abstractions/DataProviderBase.cs index 8dc4b8c..0badd6f 100644 --- a/webapi/DataProviders/Abstractions/DataProviderBase.cs +++ b/webapi/DataProviders/Abstractions/DataProviderBase.cs @@ -85,7 +85,9 @@ namespace DataProviders.Abstractions { #region Get private protected (List?, IDomainResult) GetWithPredicate(Expression> predicate, string collectionName) => - GetWithPredicateCore(predicate, collectionName); + GetWithPredicateCore(predicate, 0, 0, collectionName); + private protected (List?, IDomainResult) GetWithPredicate(Expression> predicate, int skip, int limit, string collectionName) => + GetWithPredicateCore(predicate, skip, limit, collectionName); #endregion #region Update @@ -104,7 +106,7 @@ namespace DataProviders.Abstractions { #region Exists private protected (Guid?, IDomainResult) Exists(Guid id, string collectionName) { - var (_resultList, result) = GetWithPredicate(x => x.Id == id, collectionName); + var (_resultList, result) = GetWithPredicate(x => x.Id == id, 0, 0, collectionName); return (result.Status != DomainOperationStatus.Failed && _resultList != null && _resultList.Count > 0 ? id @@ -189,7 +191,7 @@ namespace DataProviders.Abstractions { } } - private (List?, IDomainResult) GetWithPredicateCore(Expression> predicate, string collectionName) { + private (List?, IDomainResult) GetWithPredicateCore(Expression> predicate, int skip, int limit, string collectionName) { try { List? result; @@ -199,7 +201,7 @@ namespace DataProviders.Abstractions { } else { result = _client.GetDatabase(_databaseName).GetCollection(collectionName) - .Find(predicate).ToList(); + .Find(predicate).Skip(skip).Limit(limit).ToList(); } return result != null && result.Count > 0 diff --git a/webapi/DataProviders/ContentDataProvider.cs b/webapi/DataProviders/ContentDataProvider.cs index 871c90f..75f1ac5 100644 --- a/webapi/DataProviders/ContentDataProvider.cs +++ b/webapi/DataProviders/ContentDataProvider.cs @@ -23,7 +23,7 @@ namespace DataProviders { public (Content?, IDomainResult) Get(Guid siteId, string locale) { var (list, result) = GetWithPredicate(x => x.SiteId == siteId - && (x.Localization.Locale == null || x.Localization.Locale.ToLower() == locale.ToLower()), _collectionName); + && (x.Localization.Locale == null || x.Localization.Locale.ToLower() == locale.ToLower()), 0, 0, _collectionName); if (!result.IsSuccess || list == null || list.Count == 0) return (null, result); diff --git a/webapi/DataProviders/Extensions/ServiceCollectionExtensions.cs b/webapi/DataProviders/Extensions/ServiceCollectionExtensions.cs index 0695d54..311b4b0 100644 --- a/webapi/DataProviders/Extensions/ServiceCollectionExtensions.cs +++ b/webapi/DataProviders/Extensions/ServiceCollectionExtensions.cs @@ -16,6 +16,7 @@ namespace DataProviders.Extensions services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); Mappings.RegisterClassMap(); diff --git a/webapi/DataProviders/Mappings.cs b/webapi/DataProviders/Mappings.cs index aaeabbc..912b5ba 100644 --- a/webapi/DataProviders/Mappings.cs +++ b/webapi/DataProviders/Mappings.cs @@ -290,8 +290,8 @@ namespace DataProviders { #endregion #region ShopItem - if (!BsonClassMap.IsClassMapRegistered(typeof(ShopCatalogItem))) { - BsonClassMap.RegisterClassMap(cm => { + if (!BsonClassMap.IsClassMapRegistered(typeof(ShopItem))) { + BsonClassMap.RegisterClassMap(cm => { cm.AutoMap(); }); } diff --git a/webapi/DataProviders/ShopCartDataProvider.cs b/webapi/DataProviders/ShopCartDataProvider.cs index c5691d2..db0e627 100644 --- a/webapi/DataProviders/ShopCartDataProvider.cs +++ b/webapi/DataProviders/ShopCartDataProvider.cs @@ -31,10 +31,10 @@ namespace DataProviders { Insert(obj, _collectionName); public (List?, IDomainResult) GetAll(Guid siteId, Guid userId) => - GetWithPredicate(x => x.SiteId == siteId && x.UserId == userId, _collectionName); + GetWithPredicate(x => x.SiteId == siteId && x.UserId == userId, 0, 0,_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); + var (list, result) = GetWithPredicate(x => x.SiteId == siteId && x.UserId == userId && x.Sku == sku, 0, 0, _collectionName); if (!result.IsSuccess || list == null || list.Count == 0) return (null, result); diff --git a/webapi/DataProviders/ShopCatalogDataProvider.cs b/webapi/DataProviders/ShopCatalogDataProvider.cs new file mode 100644 index 0000000..46aabfd --- /dev/null +++ b/webapi/DataProviders/ShopCatalogDataProvider.cs @@ -0,0 +1,52 @@ +using Microsoft.Extensions.Logging; + +using DomainResults.Common; + +using MongoDB.Bson.Serialization; +using MongoDB.Driver; + +using Core.DomainObjects.Documents; +using DataProviders.Abstractions; + +namespace DataProviders { + public interface IShopCatalogDataProvider { + (Guid?, IDomainResult) Insert(ShopItem obj); + (ShopItem?, IDomainResult) Get(Guid siteId, string sku); + (List?, IDomainResult) GetAll(Guid siteId, int skip, int take); + (Guid?, IDomainResult) Update(ShopItem shopCart); + IDomainResult Delete(Guid id); + } + + public class ShopCatalogDataProvider : DataProviderBase, IShopCatalogDataProvider { + + private const string _collectionName = "shopcatalog"; + + public ShopCatalogDataProvider( + ILogger> logger, + IMongoClient client, + IIdGenerator idGenerator, + ISessionService sessionService) : base(logger, client, idGenerator, sessionService) { + } + + public (Guid?, IDomainResult) Insert(ShopItem obj) => + Insert(obj, _collectionName); + + public (ShopItem?, IDomainResult) Get(Guid siteId, string sku) { + var (list, result) = GetWithPredicate(x => x.SiteId == siteId && x.Sku == sku, _collectionName); + + if (!result.IsSuccess || list == null || list.Count == 0) + return (null, result); + + return (list.First(), result); + } + + public (List?, IDomainResult) GetAll(Guid siteId, int skip, int take) => + GetWithPredicate(x => x.SiteId == siteId, skip, take, _collectionName); + + public (Guid?, IDomainResult) Update(ShopItem shopCart) => + UpdateWithPredicate(shopCart, x => x.Id == shopCart.Id, _collectionName); + + public IDomainResult Delete(Guid id) => + DeleteWithPredicate(x => x.Id == id, _collectionName); + } +} diff --git a/webapi/WeatherForecast/Controllers/BlogCatalogController.cs b/webapi/WeatherForecast/Controllers/BlogCatalogController.cs index 5547579..bc20c37 100644 --- a/webapi/WeatherForecast/Controllers/BlogCatalogController.cs +++ b/webapi/WeatherForecast/Controllers/BlogCatalogController.cs @@ -32,31 +32,31 @@ public class BlogCatalogController : ControllerBase { public IActionResult Get([FromQuery] Guid? category, [FromQuery] string? searchText, [FromQuery] int currentPage = 1, [FromQuery] int itemsPerPage = 4) { - var blogModels = new List(); - for (int i = 0; i < 100; i++) { - var blogItemModel = new BlogItemModel { - Id = Guid.NewGuid(), - Slug = "blog-post-title", - Image = new ImageModel { Src = "https://dummyimage.com/850x350/dee2e6/6c757d.jpg", Alt = "..." }, - Badge = "news", - Title = $"Blog post title {i}", - ShortText = "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...", - Text = "", - Author = new AuthorModel { - Image = new ImageModel { Src = "https://dummyimage.com/40x40/ced4da/6c757d", Alt = "..." }, - NickName = "Admin" - }, - Created = DateTime.UtcNow, - Tags = new List { "react", "redux", "webapi" }, + //var blogModels = new List(); + //for (int i = 0; i < 100; i++) { + // var blogItemModel = new BlogItemModel { + // Id = Guid.NewGuid(), + // Slug = "blog-post-title", + // Image = new ImageModel { Src = "https://dummyimage.com/850x350/dee2e6/6c757d.jpg", Alt = "..." }, + // Badge = "news", + // Title = $"Blog post title {i}", + // ShortText = "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...", + // Text = "", + // Author = new AuthorModel { + // Image = new ImageModel { Src = "https://dummyimage.com/40x40/ced4da/6c757d", Alt = "..." }, + // NickName = "Admin" + // }, + // Created = DateTime.UtcNow, + // Tags = new List { "react", "redux", "webapi" }, - ReadTime = 10, - Likes = 200, - }; + // ReadTime = 10, + // Likes = 200, + // }; - blogModels.Add(blogItemModel); - } + // blogModels.Add(blogItemModel); + //} - var totalPages = blogModels.Count() / itemsPerPage; + //var totalPages = blogModels.Count() / itemsPerPage; var blogCatalogResponse = new GetBlogCatalogResponseModel { diff --git a/webapi/WeatherForecast/Controllers/BlogFeaturedController.cs b/webapi/WeatherForecast/Controllers/BlogFeaturedController.cs index efa391f..aac1614 100644 --- a/webapi/WeatherForecast/Controllers/BlogFeaturedController.cs +++ b/webapi/WeatherForecast/Controllers/BlogFeaturedController.cs @@ -22,36 +22,9 @@ namespace WeatherForecast.Controllers { /// [HttpGet] public IActionResult Get() { -#if MOCK_SERVER - var blogItems = new List(); - for (int i = 0; i < 3; i++) { - blogItems.Add(new BlogItemModel { - Id = Guid.NewGuid(), - Slug = "blog-post-title", - Image = new ImageModel { Src = "https://dummyimage.com/600x350/ced4da/6c757d", Alt = "..." }, - Badge = "news", - Title = "C# Blog post title", - ShortText = "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...", - Text = "", - Author = new AuthorModel { - //Id = Guid.NewGuid(), - Image = new ImageModel { Src = "https://dummyimage.com/40x40/ced4da/6c757d", Alt = "..." }, - NickName = "Admin" - }, - Created = DateTime.UtcNow, - Tags = new List { "react", "redux", "webapi" }, - ReadTime = 10, - Likes = 200, - }); - } - - var result = new GetBlogFeaturedResponseModel(blogItems); - - return Ok(result); -#else return Ok(); -#endif + } } } diff --git a/webapi/WeatherForecast/Controllers/ContentController.cs b/webapi/WeatherForecast/Controllers/ContentController.cs index beb64a2..5f72412 100644 --- a/webapi/WeatherForecast/Controllers/ContentController.cs +++ b/webapi/WeatherForecast/Controllers/ContentController.cs @@ -39,7 +39,7 @@ public class ContentController : ControllerBase { /// [HttpGet("{siteId}")] public IActionResult Get([FromRoute] Guid siteId, [FromQuery] string? locale) { - var result = _contentService.GetContent(siteId, locale ?? "en-Us") ; + var result = _contentService.GetContent(siteId, locale ?? "en-US") ; return result.ToActionResult(); } } diff --git a/webapi/WeatherForecast/Controllers/ShopCatalogController.cs b/webapi/WeatherForecast/Controllers/ShopCatalogController.cs deleted file mode 100644 index 5803481..0000000 --- a/webapi/WeatherForecast/Controllers/ShopCatalogController.cs +++ /dev/null @@ -1,72 +0,0 @@ -using Core.Abstractions.Models; -using Core.Models; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using WeatherForecast.Models; -using WeatherForecast.Models.Responses; - -namespace WeatherForecast.Controllers; - -[AllowAnonymous] -[ApiController] -[Route("api/[controller]")] -public class ShopCatalogController : ControllerBase { - - private readonly ILogger _logger; - - public ShopCatalogController(ILogger logger) { - _logger = logger; - } - - /// - /// - /// - /// - /// - /// - /// - /// - [HttpGet] - public IActionResult Get([FromQuery] Guid? category, [FromQuery] string? searchText, [FromQuery] int currentPage = 1, [FromQuery] int itemsPerPage = 8) { - - var shopModels = new List(); - for (int i = 0; i < 8; i++) { - var shopItemModel = new ShopItemModel { - Id = Guid.NewGuid(), - Sku = "SKU-0", - Slug = "shop-catalog-item", - Image = new ImageModel { Src = "https://dummyimage.com/450x300/dee2e6/6c757d.jpg", Alt = "..." }, - Badge = "sale", - Title = "Shop item title", - - ShortText = "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...", - Text = "", - Author = new AuthorModel { - // Id = Guid.NewGuid(), - Image = new ImageModel { Src = "https://dummyimage.com/40x40/ced4da/6c757d", Alt = "..." }, - NickName = "Admin" - }, - Created = DateTime.UtcNow, - - Tags = new List { "react", "redux", "webapi" }, - - Rating = 4.5, - Price = 20, - NewPrice = 10 - }; - - shopModels.Add(shopItemModel); - } - - var shopCatalogResponse = new GetShopCatalogResponseModel { - /*ShopItemsPagination = new PaginationModelBase { - CurrentPage = currentPage, - TotalPages = 100, - Items = shopModels - }*/ - }; - - - return Ok(shopCatalogResponse); - } -} diff --git a/webapi/WeatherForecast/Controllers/ShopItemController.cs b/webapi/WeatherForecast/Controllers/ShopItemController.cs index dac0b3a..462c079 100644 --- a/webapi/WeatherForecast/Controllers/ShopItemController.cs +++ b/webapi/WeatherForecast/Controllers/ShopItemController.cs @@ -1,5 +1,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization; +using WeatherForecast.Services; +using DomainResults.Mvc; namespace WeatherForecast.Controllers { @@ -9,18 +11,26 @@ namespace WeatherForecast.Controllers { public class ShopItemController : ControllerBase { private readonly ILogger _logger; + private readonly IShopItemService _shopItemService; - public ShopItemController(ILogger logger) { + public ShopItemController( + ILogger logger, + IShopItemService shopItemService + ) { _logger = logger; + _shopItemService = shopItemService; } /// /// /// + /// + /// /// - [HttpGet] - public IActionResult Get() { - return Ok(); + [HttpGet("{siteId}/{sku}")] + public IActionResult Get([FromRoute] Guid siteId, [FromRoute] string sku) { + var result = _shopItemService.Get(siteId, sku); + return result.ToActionResult(); } } } diff --git a/webapi/WeatherForecast/Controllers/ShopItemsController.cs b/webapi/WeatherForecast/Controllers/ShopItemsController.cs new file mode 100644 index 0000000..794ca47 --- /dev/null +++ b/webapi/WeatherForecast/Controllers/ShopItemsController.cs @@ -0,0 +1,42 @@ +using Core.Abstractions.Models; +using Core.Models; +using DomainResults.Mvc; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using WeatherForecast.Models; +using WeatherForecast.Models.Responses; +using WeatherForecast.Services; + +namespace WeatherForecast.Controllers; + +[AllowAnonymous] +[ApiController] +[Route("api/[controller]")] +public class ShopItemsController : ControllerBase { + + private readonly ILogger _logger; + private readonly IShopItemsService _shopItemsService; + + public ShopItemsController( + ILogger logger, + IShopItemsService shopCatalogService + ) { + _logger = logger; + _shopItemsService = shopCatalogService; + + } + + /// + /// + /// + /// + /// + /// + /// + /// + [HttpGet("{siteId}")] + public IActionResult Get([FromRoute] Guid siteId, [FromQuery] Guid? category, [FromQuery] int? currentPage, [FromQuery] int? itemsPerPage, [FromQuery] string? searchText) { + var result = _shopItemsService.Get(siteId, category, currentPage ?? 1, itemsPerPage ?? 8, searchText); + return result.ToActionResult(); + } +} diff --git a/webapi/WeatherForecast/Controllers/ShopRelatedController.cs b/webapi/WeatherForecast/Controllers/ShopRelatedController.cs index 7ad41b2..ba2d2b1 100644 --- a/webapi/WeatherForecast/Controllers/ShopRelatedController.cs +++ b/webapi/WeatherForecast/Controllers/ShopRelatedController.cs @@ -10,6 +10,9 @@ namespace WeatherForecast.Controllers { private readonly ILogger _logger; + + + public ShopRelatedController(ILogger logger) { _logger = logger; } diff --git a/webapi/WeatherForecast/Models/Abstractions/PersonModelBase.cs b/webapi/WeatherForecast/Models/Abstractions/PersonModelBase.cs index 6b687b4..c04d679 100644 --- a/webapi/WeatherForecast/Models/Abstractions/PersonModelBase.cs +++ b/webapi/WeatherForecast/Models/Abstractions/PersonModelBase.cs @@ -1,14 +1,16 @@ -using Core.Abstractions.Models; +using Core.Abstractions.DomainObjects; +using Core.Abstractions.Models; using Core.DomainObjects; namespace WeatherForecast.Models.Abstractions { - public abstract class PersonModelBase : ModelBase { + public abstract class PersonModelBase : ModelBase { public ImageModel? Image { get; set; } public PersonModelBase() { } - public PersonModelBase(Image? image) { - Image = new ImageModel(image); + public PersonModelBase(PersonBase person) { + if(person.Image != null) + Image = new ImageModel(person.Image); } } } diff --git a/webapi/WeatherForecast/Models/Abstractions/PostItemModelBase.cs b/webapi/WeatherForecast/Models/Abstractions/PostItemRequestModelBase.cs similarity index 58% rename from webapi/WeatherForecast/Models/Abstractions/PostItemModelBase.cs rename to webapi/WeatherForecast/Models/Abstractions/PostItemRequestModelBase.cs index b6ff872..b2a93ca 100644 --- a/webapi/WeatherForecast/Models/Abstractions/PostItemModelBase.cs +++ b/webapi/WeatherForecast/Models/Abstractions/PostItemRequestModelBase.cs @@ -1,14 +1,14 @@ -using Core.Abstractions.Models; +using Core.Abstractions.DomainObjects; +using Core.Abstractions.Models; namespace WeatherForecast.Models.Abstractions { - public abstract class PostItemModelBase : ModelBase { - public Guid Id { get; set; } + public abstract class PostItemRequestModelBase : PostItemRequestModel { public string Slug { get; set; } - public ImageModel Image { get; set; } + public List Images { get; set; } - public string Badge { get; set; } + public List Badges { get; set; } public string Title { get; set; } diff --git a/webapi/WeatherForecast/Models/Abstractions/PostItemResponseModelBase.cs b/webapi/WeatherForecast/Models/Abstractions/PostItemResponseModelBase.cs new file mode 100644 index 0000000..1829c68 --- /dev/null +++ b/webapi/WeatherForecast/Models/Abstractions/PostItemResponseModelBase.cs @@ -0,0 +1,37 @@ +using Core.Abstractions.DomainObjects; +using Core.Abstractions.Models; + +namespace WeatherForecast.Models.Abstractions { + public abstract class PostItemResponseModelBase : ResponseModelBase { + + public string Slug { get; set; } + + public List Images { get; set; } + + public List Badges { get; set; } + + public string Title { get; set; } + + public string? ShortText { get; set; } + + public string? Text { get; set; } + + public AuthorModel Author { get; set; } + + public DateTime Created { get; set; } + + public List Tags { get; set; } + + public PostItemResponseModelBase(PostItemBase postItem) { + Slug = postItem.Slug; + Images = postItem.Images.Select(x => new ImageModel(x)).ToList(); + Badges = postItem.Badges; + Title = postItem.Title; + Text = postItem.Text; + ShortText = postItem.ShortText; + Author = new AuthorModel(postItem.Author); + Created = postItem.Created; + Tags = postItem.Tags; + } + } +} diff --git a/webapi/WeatherForecast/Models/AuthorModel.cs b/webapi/WeatherForecast/Models/AuthorModel.cs index 4146a68..9b8fdc2 100644 --- a/webapi/WeatherForecast/Models/AuthorModel.cs +++ b/webapi/WeatherForecast/Models/AuthorModel.cs @@ -1,7 +1,12 @@ -using WeatherForecast.Models.Abstractions; +using Core.DomainObjects; +using WeatherForecast.Models.Abstractions; namespace WeatherForecast.Models { - public class AuthorModel : PersonModelBase { + public class AuthorModel : PersonModelBase { public string NickName { get; set; } + + public AuthorModel(Author author) { + NickName = author.NickName; + } } } diff --git a/webapi/WeatherForecast/Models/BlogItemModel.cs b/webapi/WeatherForecast/Models/BlogItemModel.cs index 79945e5..4c34adb 100644 --- a/webapi/WeatherForecast/Models/BlogItemModel.cs +++ b/webapi/WeatherForecast/Models/BlogItemModel.cs @@ -1,13 +1,17 @@ -using WeatherForecast.Models.Abstractions; +using Core.Abstractions.DomainObjects; +using Core.DomainObjects.Documents; +using WeatherForecast.Models.Abstractions; namespace WeatherForecast.Models { - public class BlogItemModel : PostItemModelBase { + public class BlogItemModel : PostItemResponseModelBase { + public uint? ReadTime { get; set; } - public int? ReadTime { get; set; } + public uint? Likes { get; set; } - public int? Likes { get; set; } - - + public BlogItemModel(BlogItem postItem) : base(postItem) { + ReadTime = postItem.ReadTime; + Likes = postItem.Likes; + } } } diff --git a/webapi/WeatherForecast/Models/Requests/PostShopCartItemRequestModel.cs b/webapi/WeatherForecast/Models/Requests/PostShopCartItemRequestModel.cs index 094c1cd..d36bcf1 100644 --- a/webapi/WeatherForecast/Models/Requests/PostShopCartItemRequestModel.cs +++ b/webapi/WeatherForecast/Models/Requests/PostShopCartItemRequestModel.cs @@ -3,7 +3,7 @@ using Core.DomainObjects; using Core.DomainObjects.Documents; namespace WeatherForecast.Models.Requests { - public class PostShopCartItemRequestModel : RequestModelBase { + public class PostShopCartItemRequestModel : PostItemRequestModel { public string Slug { get; set; } public ImageModel Image { get; set; } diff --git a/webapi/WeatherForecast/Models/Requests/PostShopItemRequestModel.cs b/webapi/WeatherForecast/Models/Requests/PostShopItemRequestModel.cs new file mode 100644 index 0000000..871dce1 --- /dev/null +++ b/webapi/WeatherForecast/Models/Requests/PostShopItemRequestModel.cs @@ -0,0 +1,32 @@ +using Core.Abstractions.Models; +using Core.DomainObjects; +using Core.DomainObjects.Documents; + +namespace WeatherForecast.Models.Requests { + public class PostShopItemRequestModel : PostItemRequestModel { + public string Slug { get; set; } + public List Images { 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 ShopItem ToDomainObject() => new ShopItem { + Slug = Slug, + Images = Images.Select(x => new Image { + Src = x.Src, + Alt = x.Alt + }).ToList(), + Title = Title, + BrandName = BrandName, + ShortText = ShortText, + Created = Created, + Price = Price, + NewPrice = NewPrice, + Quantity = Quantity + }; + } +} diff --git a/webapi/WeatherForecast/Models/Requests/PutShopCartItemRequestModel.cs b/webapi/WeatherForecast/Models/Requests/PutShopCartItemRequestModel.cs index 53db0ed..77db6f8 100644 --- a/webapi/WeatherForecast/Models/Requests/PutShopCartItemRequestModel.cs +++ b/webapi/WeatherForecast/Models/Requests/PutShopCartItemRequestModel.cs @@ -3,7 +3,7 @@ using Core.DomainObjects; using Core.DomainObjects.Documents; namespace WeatherForecast.Models.Requests { - public class PutShopCartItemRequestModel : RequestModelBase { + public class PutShopCartItemRequestModel : PostItemRequestModel { public string Slug { get; set; } public ImageModel Image { get; set; } diff --git a/webapi/WeatherForecast/Models/Requests/PutShopItemRequestModel.cs b/webapi/WeatherForecast/Models/Requests/PutShopItemRequestModel.cs new file mode 100644 index 0000000..5b2c46e --- /dev/null +++ b/webapi/WeatherForecast/Models/Requests/PutShopItemRequestModel.cs @@ -0,0 +1,10 @@ +using Core.Abstractions.Models; +using Core.DomainObjects.Documents; + +namespace WeatherForecast.Models.Requests { + public class PutShopItemRequestModel : PostItemRequestModel { + public override ShopItem ToDomainObject() { + throw new NotImplementedException(); + } + } +} diff --git a/webapi/WeatherForecast/Models/Responses/GetShopCatalogResponseModel.cs b/webapi/WeatherForecast/Models/Responses/GetShopCatalogResponseModel.cs deleted file mode 100644 index 306fe46..0000000 --- a/webapi/WeatherForecast/Models/Responses/GetShopCatalogResponseModel.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Core.Abstractions.Models; -using Core.Models; - -namespace WeatherForecast.Models.Responses { - public class GetShopCatalogResponseModel : ResponseModelBase { - public PaginationModelBase ShopItemsPagination { get; set; } - } -} diff --git a/webapi/WeatherForecast/Models/Responses/GetShopItemResponseModel.cs b/webapi/WeatherForecast/Models/Responses/GetShopItemResponseModel.cs new file mode 100644 index 0000000..24bd576 --- /dev/null +++ b/webapi/WeatherForecast/Models/Responses/GetShopItemResponseModel.cs @@ -0,0 +1,23 @@ +using Core.DomainObjects.Documents; +using Core.DomainObjects.Pages; +using WeatherForecast.Models.Abstractions; + +namespace WeatherForecast.Models { + public class GetShopItemResponseModel : PostItemResponseModelBase { + public List? Images { get; set; } + public string Sku { get; set; } + public decimal? Rating { get; set; } + public double Price { get; set; } + public double? NewPrice { get; set; } + public uint? Quantity { get; set; } + + public GetShopItemResponseModel(ShopItem shopCatalogItem) : base(shopCatalogItem) { + Images = shopCatalogItem.Images.Select(x => new ImageModel(x)).ToList(); + Sku = shopCatalogItem.Sku; + Rating = shopCatalogItem.Rating; + Price = shopCatalogItem.Price; + NewPrice = shopCatalogItem.NewPrice; + Quantity = shopCatalogItem.Quantity; + } + } +} diff --git a/webapi/WeatherForecast/Models/Responses/GetShopItemsResponseModel.cs b/webapi/WeatherForecast/Models/Responses/GetShopItemsResponseModel.cs new file mode 100644 index 0000000..ec66802 --- /dev/null +++ b/webapi/WeatherForecast/Models/Responses/GetShopItemsResponseModel.cs @@ -0,0 +1,9 @@ +using Core.Abstractions.Models; +using Core.Models; + +namespace WeatherForecast.Models.Responses { + public class GetShopItemsResponseModel : PaginationModelBase { + public GetShopItemsResponseModel(int currentPage, int totalPages, List items) + : base(currentPage, totalPages, items) { } + } +} diff --git a/webapi/WeatherForecast/Models/ReviewerModel.cs b/webapi/WeatherForecast/Models/ReviewerModel.cs index df17219..9cdebd3 100644 --- a/webapi/WeatherForecast/Models/ReviewerModel.cs +++ b/webapi/WeatherForecast/Models/ReviewerModel.cs @@ -2,11 +2,11 @@ using WeatherForecast.Models.Abstractions; namespace WeatherForecast.Models { - public class ReviewerModel : PersonModelBase { + public class ReviewerModel : PersonModelBase { public string FullName { get; set; } public string Position { get; set; } - public ReviewerModel(Reviewer reviewer) : base(reviewer.Image) { + public ReviewerModel(Reviewer reviewer) : base(reviewer) { FullName = reviewer.FullName; Position = reviewer.Position; } diff --git a/webapi/WeatherForecast/Models/ShopItemModel.cs b/webapi/WeatherForecast/Models/ShopItemModel.cs deleted file mode 100644 index 351b017..0000000 --- a/webapi/WeatherForecast/Models/ShopItemModel.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Core.DomainObjects.Documents; -using Core.DomainObjects.Pages; -using WeatherForecast.Models.Abstractions; - -namespace WeatherForecast.Models { - public class ShopItemModel : PostItemModelBase { - public List? Images { get; set; } - public string Sku { get; set; } - public double? Rating { get; set; } - public double Price { get; set; } - public double? NewPrice { get; set; } - public int? Quantity { get; set; } - - - } -} diff --git a/webapi/WeatherForecast/Services/ShopItemService.cs b/webapi/WeatherForecast/Services/ShopItemService.cs new file mode 100644 index 0000000..b508ee0 --- /dev/null +++ b/webapi/WeatherForecast/Services/ShopItemService.cs @@ -0,0 +1,85 @@ +using DataProviders; +using DomainResults.Common; +using WeatherForecast.Models; +using WeatherForecast.Models.Requests; + +namespace WeatherForecast.Services { + + public interface IShopItemService { + (GetShopItemResponseModel, IDomainResult) Get(Guid siteId, string sku); + } + + public class ShopItemService : IShopItemService { + + private readonly ILogger _logger; + private readonly IShopCatalogDataProvider _shopCatalogDataProvider; + + public ShopItemService( + ILogger logger, + IShopCatalogDataProvider shopCatalogDataProvider + ) { + _logger = logger; + _shopCatalogDataProvider = shopCatalogDataProvider; + } + + public (Guid?, IDomainResult) Post(Guid siteId, string sku, PostShopItemRequestModel requestModel) { + var (_, getResult) = _shopCatalogDataProvider.Get(siteId, sku); + if (getResult.IsSuccess) + return IDomainResult.Failed(); + + var item = requestModel.ToDomainObject(); + + item.SiteId = siteId; + item.Sku = sku; + + var (id, insertResult) = _shopCatalogDataProvider.Insert(item); + + if (!insertResult.IsSuccess) + return IDomainResult.Failed(); + + return IDomainResult.Success(id); + } + + public (GetShopItemResponseModel?, IDomainResult) Get(Guid siteId, string sku) { + var (item, result) = _shopCatalogDataProvider.Get(siteId, sku); + + if (!result.IsSuccess || item == null) + return (null, result); + + return IDomainResult.Success(new GetShopItemResponseModel(item)); + } + + public (Guid?, IDomainResult) Update(Guid siteId, string sku, PutShopItemRequestModel requestData) { + var (item, getResult) = _shopCatalogDataProvider.Get(siteId, sku); + if (!getResult.IsSuccess || item == null) + return (null, getResult); + + // construct domain object from model + var newItem = requestData.ToDomainObject(); + newItem.Id = item.Id; + newItem.SiteId = siteId; + newItem.Sku = sku; + + if (!item.Equals(newItem)) { + var (id, updateResult) = _shopCatalogDataProvider.Update(newItem); + if (!updateResult.IsSuccess || id == null) + return (null, updateResult); + } + + return IDomainResult.Success(item.Id); + } + + public IDomainResult Delete(Guid siteId, string sku) { + var (item, getResult) = _shopCatalogDataProvider.Get(siteId, sku); + if (!getResult.IsSuccess || item == null) + return getResult; + + var result = _shopCatalogDataProvider.Delete(item.Id); + if (!result.IsSuccess) + return result; + + return IDomainResult.Success(); + } + + } +} diff --git a/webapi/WeatherForecast/Services/ShopItemsService.cs b/webapi/WeatherForecast/Services/ShopItemsService.cs new file mode 100644 index 0000000..01459d8 --- /dev/null +++ b/webapi/WeatherForecast/Services/ShopItemsService.cs @@ -0,0 +1,33 @@ +using DataProviders; +using DomainResults.Common; +using WeatherForecast.Models; +using WeatherForecast.Models.Responses; + +namespace WeatherForecast.Services { + + public interface IShopItemsService { + (GetShopItemsResponseModel?, IDomainResult) Get(Guid siteId, Guid? category, int currentPage, int itemsPerPage, string? searchText); + } + + public class ShopItemsService : IShopItemsService { + ILogger _logger; + IShopCatalogDataProvider _shopCatalogDataProvider; + + public ShopItemsService( + ILogger logger, + IShopCatalogDataProvider shopCatalogDataprovider + ) { + _logger = logger; + _shopCatalogDataProvider = shopCatalogDataprovider; + } + + public (GetShopItemsResponseModel?, IDomainResult) Get(Guid siteId, Guid? category, int currentPage, int itemsPerPage, string? searchText) { + var (items, result) = _shopCatalogDataProvider.GetAll(siteId, currentPage > 0 ? ((currentPage - 1) * itemsPerPage) : 0, itemsPerPage); + + if (!result.IsSuccess || items == null) + return (null, result); + + return IDomainResult.Success(new GetShopItemsResponseModel(currentPage, 0, items.Select(x => new GetShopItemResponseModel(x)).ToList())); + } + } +} diff --git a/webapi/WeatherForecast/Startup.cs b/webapi/WeatherForecast/Startup.cs index 4041fa9..714ba23 100644 --- a/webapi/WeatherForecast/Startup.cs +++ b/webapi/WeatherForecast/Startup.cs @@ -58,6 +58,8 @@ namespace WeatherForecast { services.AddHttpContextAccessor(); services.AddScoped(); + services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped();