diff --git a/Common/WebStore.Domain/DTO/Identity/ClaimDTO.cs b/Common/WebStore.Domain/DTO/Identity/ClaimDTO.cs new file mode 100644 index 0000000..a359689 --- /dev/null +++ b/Common/WebStore.Domain/DTO/Identity/ClaimDTO.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using System.Security.Claims; + +namespace WebStore.Domain.DTO.Identity +{ + public abstract class ClaimDTO : UserDTO + { + public IEnumerable Claims { get; set; } + } + + public class AddClaimDTO : ClaimDTO { } + + public class RemoveClaimDTO : ClaimDTO { } + + public class ReplaceClaimDTO : UserDTO + { + public Claim Claim { get; set; } + + public Claim NewClaim { get; set; } + } +} diff --git a/Common/WebStore.Domain/DTO/Identity/UserDTO.cs b/Common/WebStore.Domain/DTO/Identity/UserDTO.cs new file mode 100644 index 0000000..465b7bb --- /dev/null +++ b/Common/WebStore.Domain/DTO/Identity/UserDTO.cs @@ -0,0 +1,26 @@ +using System; +using Microsoft.AspNetCore.Identity; +using WebStore.Domain.Entities.Identity; + +namespace WebStore.Domain.DTO.Identity +{ + public abstract class UserDTO + { + public User User { get; set; } + } + + public class AddLoginDTO : UserDTO + { + public UserLoginInfo UserLoginInfo { get; set; } + } + + public class PasswordHashDTO : UserDTO + { + public string Hash { get; set; } + } + + public class SetLockoutDTO : UserDTO + { + public DateTimeOffset? LockoutEnd { get; set; } + } +} diff --git a/Common/WebStore.Domain/DTO/Orders/OrderDTO.cs b/Common/WebStore.Domain/DTO/Orders/OrderDTO.cs new file mode 100644 index 0000000..0540696 --- /dev/null +++ b/Common/WebStore.Domain/DTO/Orders/OrderDTO.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using WebStore.Domain.ViewModels; + +namespace WebStore.Domain.DTO.Orders +{ + public record OrderItemDTO(int Id, decimal Price, int Quantity); + + public record OrderDTO( + int Id, + string Name, + string Phone, + string Address, + DateTime Date, + IEnumerable Items); + + public record CreateOrderModel(OrderViewModel Order, IList Items); +} diff --git a/Common/WebStore.Domain/DTO/Products/BrandDTO.cs b/Common/WebStore.Domain/DTO/Products/BrandDTO.cs new file mode 100644 index 0000000..1fd121a --- /dev/null +++ b/Common/WebStore.Domain/DTO/Products/BrandDTO.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WebStore.Domain.Entities.Base; + +namespace WebStore.Domain.DTO.Products +{ + public class BrandDTO: NamedEntity + { + public int Order { get; set; } + + public int ProductsCount { get; set; } + } +} diff --git a/Common/WebStore.Domain/DTO/Products/CategoryDTO.cs b/Common/WebStore.Domain/DTO/Products/CategoryDTO.cs new file mode 100644 index 0000000..996e962 --- /dev/null +++ b/Common/WebStore.Domain/DTO/Products/CategoryDTO.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WebStore.Domain.Entities.Base; + +namespace WebStore.Domain.DTO.Products +{ + public class CategoryDTO: NamedEntity + { + + public int Order { get; set; } + + public int? ParentId { get; set; } + + public int ProductsCount { get; set; } + } +} diff --git a/Common/WebStore.Domain/DTO/Products/ProductDTO.cs b/Common/WebStore.Domain/DTO/Products/ProductDTO.cs new file mode 100644 index 0000000..2255f9d --- /dev/null +++ b/Common/WebStore.Domain/DTO/Products/ProductDTO.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WebStore.Domain.Entities.Base; + +namespace WebStore.Domain.DTO.Products +{ + public class ProductDTO: NamedEntity + { + public int Order { get; set; } + public decimal Price { get; set; } + public string ImageUrl { get; set; } + public BrandDTO Brand { get; set; } + public CategoryDTO Category { get; set; } + public string Description { get; set; } + public int Discount { get; set; } + + } +} diff --git a/Common/WebStore.Domain/ViewModels/UserOrderViewModel.cs b/Common/WebStore.Domain/ViewModels/UserOrderViewModel.cs new file mode 100644 index 0000000..e8a77fd --- /dev/null +++ b/Common/WebStore.Domain/ViewModels/UserOrderViewModel.cs @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; + +namespace WebStore.Domain.ViewModels +{ + public class UserOrderViewModel + { + public int Id { get; set; } + + [Required] + public string Name { get; set; } + + [Required] + public string Phone { get; set; } + + [Required] + public string Address { get; set; } + + public decimal TotalSum { get; set; } + } +} diff --git a/Common/WebStore.Domain/WebStore.Domain.csproj b/Common/WebStore.Domain/WebStore.Domain.csproj index e9a2516..0632141 100644 --- a/Common/WebStore.Domain/WebStore.Domain.csproj +++ b/Common/WebStore.Domain/WebStore.Domain.csproj @@ -1,7 +1,7 @@ - + - netstandard2.0 + net5.0 diff --git a/Services/WebStore.Client/Base/BaseClient.cs b/Services/WebStore.Client/Base/BaseClient.cs index 00a968e..2e4853b 100644 --- a/Services/WebStore.Client/Base/BaseClient.cs +++ b/Services/WebStore.Client/Base/BaseClient.cs @@ -1,11 +1,13 @@ using System; using System.Net.Http; using System.Net.Http.Headers; +using System.Threading; +using System.Threading.Tasks; using Microsoft.Extensions.Configuration; namespace WebStore.Client.Base { - public abstract class BaseClient + public abstract class BaseClient : IDisposable { protected string Address { get; } protected HttpClient Http { get; } @@ -22,5 +24,46 @@ protected BaseClient(IConfiguration Configuration, string ServiceAddress) } }; } + + protected T Get(string url) => GetAsync(url).Result; + protected async Task GetAsync(string url, CancellationToken Cancel = default) + { + var response = await Http.GetAsync(url, Cancel); + return await response.EnsureSuccessStatusCode().Content.ReadAsAsync(Cancel); + } + + protected HttpResponseMessage Post(string url, T item) => PostAsync(url, item).Result; + protected async Task PostAsync(string url, T item, CancellationToken Cancel = default) + { + var response = await Http.PostAsJsonAsync(url, item, Cancel); + return response.EnsureSuccessStatusCode(); + } + + protected HttpResponseMessage Put(string url, T item) => PutAsync(url, item).Result; + protected async Task PutAsync(string url, T item, CancellationToken Cancel = default) + { + var response = await Http.PutAsJsonAsync(url, item, Cancel); + return response.EnsureSuccessStatusCode(); + } + + protected HttpResponseMessage Delete(string url) => DeleteAsync(url).Result; + protected async Task DeleteAsync(string url, CancellationToken Cancel = default) + { + var response = await Http.DeleteAsync(url, Cancel); + return response; + } + + public void Dispose() => Dispose(true); + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + // освобождение управляемых ресурсов + Http.Dispose(); + } + + // освобождение неуправляемых ресурсов + } } } diff --git a/Services/WebStore.Client/Employees/EmployeesClient.cs b/Services/WebStore.Client/Employees/EmployeesClient.cs new file mode 100644 index 0000000..2ef0a82 --- /dev/null +++ b/Services/WebStore.Client/Employees/EmployeesClient.cs @@ -0,0 +1,37 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Text; +using Webstore.Interfaces; +using Webstore.Interfaces.Services; +using WebStore.Client.Base; +using WebStore.Domain.Models; + +namespace WebStore.Client.Employees +{ + public class EmployeesClient: BaseClient, IEmployeesData + { + private readonly ILogger _Logger; + + public EmployeesClient(IConfiguration Configuration, ILogger Logger): base(Configuration, WebAPI.Employees) + { + _Logger = Logger; + } + + public int Add(Employee employee)=>Post(Address,employee).Content.ReadAsAsync().Result; + + public bool Delete(int id) => Delete($"{Address}/{id}").IsSuccessStatusCode; + + public IEnumerable Get() => Get>(Address); + + public Employee Get(int id) => Get($"{Address}/{id}"); + + public void Update(Employee employee) + { + _Logger.LogInformation("Редактирование сотрудника с id:{ 0}", employee.Id); + Put(Address, employee); + } + } +} diff --git a/Services/WebStore.Client/Identity/IdentityExtensions.cs b/Services/WebStore.Client/Identity/IdentityExtensions.cs new file mode 100644 index 0000000..5982b38 --- /dev/null +++ b/Services/WebStore.Client/Identity/IdentityExtensions.cs @@ -0,0 +1,32 @@ +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.DependencyInjection; +using WebStore.Domain.Entities.Identity; + +namespace WebStore.Clients.Identity +{ + public static class IdentityExtensions + { + public static IServiceCollection AddIdentityWebStoreWebAPIClients(this IServiceCollection services) + { + services + .AddTransient, UsersClient>() + .AddTransient, UsersClient>() + .AddTransient, UsersClient>() + .AddTransient, UsersClient>() + .AddTransient, UsersClient>() + .AddTransient, UsersClient>() + .AddTransient, UsersClient>() + .AddTransient, UsersClient>(); + + services.AddTransient, RolesClient>(); + + return services; + } + + public static IdentityBuilder AddIdentityWebStoreWebAPIClients(this IdentityBuilder builder) + { + builder.Services.AddIdentityWebStoreWebAPIClients(); + return builder; + } + } +} diff --git a/Services/WebStore.Client/Identity/RolesClient.cs b/Services/WebStore.Client/Identity/RolesClient.cs new file mode 100644 index 0000000..98a84a1 --- /dev/null +++ b/Services/WebStore.Client/Identity/RolesClient.cs @@ -0,0 +1,77 @@ +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Configuration; +using Webstore.Interfaces; +using WebStore.Client.Base; +using WebStore.Domain.Entities.Identity; +using WebStore.Interfaces.Services.Identity; + +namespace WebStore.Clients.Identity +{ + public class RolesClient : BaseClient, IRolesClient + { + public RolesClient(IConfiguration Configuration) : base(Configuration, WebAPI.Identity.Role) { } + + #region IRoleStore + + public async Task CreateAsync(Role role, CancellationToken cancel) => + await (await PostAsync(Address, role, cancel).ConfigureAwait(false)) + .Content + .ReadAsAsync(cancel) + ? IdentityResult.Success + : IdentityResult.Failed(); + + public async Task UpdateAsync(Role role, CancellationToken cancel) => + await (await PutAsync(Address, role, cancel).ConfigureAwait(false)) + .Content + .ReadAsAsync(cancel) + ? IdentityResult.Success + : IdentityResult.Failed(); + + public async Task DeleteAsync(Role role, CancellationToken cancel) => + await (await PostAsync($"{Address}/Delete", role, cancel).ConfigureAwait(false)) + .Content + .ReadAsAsync(cancel) + ? IdentityResult.Success + : IdentityResult.Failed(); + + public async Task GetRoleIdAsync(Role role, CancellationToken cancel) => + await (await PostAsync($"{Address}/GetRoleId", role, cancel).ConfigureAwait(false)) + .Content + .ReadAsAsync(cancel); + + public async Task GetRoleNameAsync(Role role, CancellationToken cancel) => + await (await PostAsync($"{Address}/GetRoleName", role, cancel).ConfigureAwait(false)) + .Content + .ReadAsAsync(cancel); + + public async Task SetRoleNameAsync(Role role, string name, CancellationToken cancel) + { + var response = await PostAsync($"{Address}/SetRoleName/{name}", role, cancel).ConfigureAwait(false); + role.Name = await response.Content.ReadAsAsync(cancel); + } + + public async Task GetNormalizedRoleNameAsync(Role role, CancellationToken cancel) => + await (await PostAsync($"{Address}/GetNormalizedRoleName", role, cancel).ConfigureAwait(false)) + .Content + .ReadAsAsync(cancel); + + public async Task SetNormalizedRoleNameAsync(Role role, string name, CancellationToken cancel) + { + var response = await PostAsync($"{Address}/SetNormalizedRoleName/{name}", role, cancel).ConfigureAwait(false); + role.NormalizedName = await response.Content.ReadAsAsync(cancel); + } + + public async Task FindByIdAsync(string id, CancellationToken cancel) => + await GetAsync($"{Address}/FindById/{id}", cancel) + .ConfigureAwait(false); + + public async Task FindByNameAsync(string name, CancellationToken cancel) => + await GetAsync($"{Address}/FindByName/{name}", cancel) + .ConfigureAwait(false); + + #endregion + } +} diff --git a/Services/WebStore.Client/Identity/UsersClient.cs b/Services/WebStore.Client/Identity/UsersClient.cs new file mode 100644 index 0000000..f0f4bbb --- /dev/null +++ b/Services/WebStore.Client/Identity/UsersClient.cs @@ -0,0 +1,378 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Security.Claims; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Configuration; +using Webstore.Interfaces; +using WebStore.Client.Base; +using WebStore.Domain.DTO.Identity; +using WebStore.Domain.Entities.Identity; +using WebStore.Interfaces.Services.Identity; + +namespace WebStore.Clients.Identity +{ + public class UsersClient : BaseClient, IUsersClient + { + public UsersClient(IConfiguration Configuration) : base(Configuration, WebAPI.Identity.User) { } + + #region Implementation of IUserStore + + public async Task GetUserIdAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/UserId", user, cancel)) + .Content + .ReadAsAsync(cancel) + .ConfigureAwait(false); + } + + public async Task GetUserNameAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/UserName", user, cancel)) + .Content + .ReadAsAsync(cancel) + .ConfigureAwait(false); + } + + public async Task SetUserNameAsync(User user, string name, CancellationToken cancel) + { + var response = await PostAsync($"{Address}/UserName/{name}", user, cancel); + user.UserName = await response.Content.ReadAsAsync(cancel); + } + + public async Task GetNormalizedUserNameAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/NormalUserName/", user, cancel)) + .Content + .ReadAsAsync(cancel) + .ConfigureAwait(false); + } + + public async Task SetNormalizedUserNameAsync(User user, string name, CancellationToken cancel) + { + var response = await PostAsync($"{Address}/NormalUserName/{name}", user, cancel); + user.NormalizedUserName = await response.Content.ReadAsAsync(cancel).ConfigureAwait(false); + } + + public async Task CreateAsync(User user, CancellationToken cancel) + { + var creation_success = await (await PostAsync($"{Address}/User", user, cancel)) + .Content + .ReadAsAsync(cancel) + .ConfigureAwait(false); + + return creation_success + ? IdentityResult.Success + : IdentityResult.Failed(); + } + + public async Task UpdateAsync(User user, CancellationToken cancel) + { + return await (await PutAsync($"{Address}/User", user, cancel)) + .Content + .ReadAsAsync(cancel).ConfigureAwait(false) + ? IdentityResult.Success + : IdentityResult.Failed(); + } + + public async Task DeleteAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/User/Delete", user, cancel)) + .Content + .ReadAsAsync(cancel) + ? IdentityResult.Success + : IdentityResult.Failed(); + } + + public async Task FindByIdAsync(string id, CancellationToken cancel) + { + return await GetAsync($"{Address}/User/Find/{id}", cancel); + } + + public async Task FindByNameAsync(string name, CancellationToken cancel) + { + return await GetAsync($"{Address}/User/Normal/{name}", cancel); + } + + #endregion + + #region Implementation of IUserRoleStore + + public async Task AddToRoleAsync(User user, string role, CancellationToken cancel) + { + await PostAsync($"{Address}/Role/{role}", user, cancel); + } + + public async Task RemoveFromRoleAsync(User user, string role, CancellationToken cancel) + { + await PostAsync($"{Address}/Role/Delete/{role}", user, cancel); + } + + public async Task> GetRolesAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/roles", user, cancel)) + .Content + .ReadAsAsync>(cancel); + } + + public async Task IsInRoleAsync(User user, string role, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/InRole/{role}", user, cancel)) + .Content + .ReadAsAsync(cancel); + } + + public async Task> GetUsersInRoleAsync(string role, CancellationToken cancel) + { + return await GetAsync>($"{Address}/UsersInRole/{role}", cancel); + } + + #endregion + + #region Implementation of IUserPasswordStore + + public async Task SetPasswordHashAsync(User user, string hash, CancellationToken cancel) + { + var response = await PostAsync( + $"{Address}/SetPasswordHash", new PasswordHashDTO { User = user, Hash = hash }, + cancel) + .ConfigureAwait(false); + user.PasswordHash = await response.Content.ReadAsAsync(cancel).ConfigureAwait(false); + } + + public async Task GetPasswordHashAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/GetPasswordHash", user, cancel)) + .Content + .ReadAsAsync(cancel) + .ConfigureAwait(false); + } + + public async Task HasPasswordAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/HasPassword", user, cancel)) + .Content + .ReadAsAsync(cancel) + .ConfigureAwait(false); + } + + #endregion + + #region Implementation of IUserEmailStore + + public async Task SetEmailAsync(User user, string email, CancellationToken cancel) + { + var response = await PostAsync($"{Address}/SetEmail/{email}", user, cancel); + user.Email = await response.Content.ReadAsAsync(cancel); + } + + public async Task GetEmailAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/GetEmail", user, cancel)) + .Content + .ReadAsAsync(cancel); + } + + public async Task GetEmailConfirmedAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/GetEmailConfirmed", user, cancel)) + .Content + .ReadAsAsync(cancel); + } + + public async Task SetEmailConfirmedAsync(User user, bool confirmed, CancellationToken cancel) + { + var response = await PostAsync($"{Address}/SetEmailConfirmed/{confirmed}", user, cancel); + user.EmailConfirmed = await response.Content.ReadAsAsync(cancel); + } + + public async Task FindByEmailAsync(string email, CancellationToken cancel) + { + return await GetAsync($"{Address}/User/FindByEmail/{email}", cancel); + } + + public async Task GetNormalizedEmailAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/User/GetNormalizedEmail", user, cancel)) + .Content + .ReadAsAsync(cancel); + } + + public async Task SetNormalizedEmailAsync(User user, string email, CancellationToken cancel) + { + var response = await PostAsync($"{Address}/SetNormalizedEmail/{email}", user, cancel); + user.NormalizedEmail = await response.Content.ReadAsAsync(cancel); + } + + #endregion + + #region Implementation of IUserPhoneNumberStore + + public async Task SetPhoneNumberAsync(User user, string phone, CancellationToken cancel) + { + var response = await PostAsync($"{Address}/SetPhoneNumber/{phone}", user, cancel); + user.PhoneNumber = await response.Content.ReadAsAsync(cancel); + } + + public async Task GetPhoneNumberAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/GetPhoneNumber", user, cancel)) + .Content + .ReadAsAsync(cancel); + } + + public async Task GetPhoneNumberConfirmedAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/GetPhoneNumberConfirmed", user, cancel)) + .Content + .ReadAsAsync(cancel); + } + + public async Task SetPhoneNumberConfirmedAsync(User user, bool confirmed, CancellationToken cancel) + { + var response = await PostAsync($"{Address}/SetPhoneNumberConfirmed/{confirmed}", user, cancel); + user.PhoneNumberConfirmed = await response.Content.ReadAsAsync(cancel); + } + + #endregion + + #region Implementation of IUserLoginStore + + public async Task AddLoginAsync(User user, UserLoginInfo login, CancellationToken cancel) + { + await PostAsync($"{Address}/AddLogin", new AddLoginDTO { User = user, UserLoginInfo = login }, cancel); + } + + public async Task RemoveLoginAsync(User user, string LoginProvider, string ProviderKey, CancellationToken cancel) + { + await PostAsync($"{Address}/RemoveLogin/{LoginProvider}/{ProviderKey}", user, cancel); + } + + public async Task> GetLoginsAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/GetLogins", user, cancel)) + .Content + .ReadAsAsync>(cancel); + } + + public async Task FindByLoginAsync(string LoginProvider, string ProviderKey, CancellationToken cancel) + { + return await GetAsync($"{Address}/User/FindByLogin/{LoginProvider}/{ProviderKey}", cancel); + } + + #endregion + + #region Implementation of IUserLockoutStore + + public async Task GetLockoutEndDateAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/GetLockoutEndDate", user, cancel)) + .Content + .ReadAsAsync(cancel); + } + + public async Task SetLockoutEndDateAsync(User user, DateTimeOffset? EndDate, CancellationToken cancel) + { + var response = await PostAsync( + $"{Address}/SetLockoutEndDate", + new SetLockoutDTO { User = user, LockoutEnd = EndDate }, + cancel); + user.LockoutEnd = await response.Content.ReadAsAsync(cancel); + } + + public async Task IncrementAccessFailedCountAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/IncrementAccessFailedCount", user, cancel)) + .Content + .ReadAsAsync(cancel); + } + + public async Task ResetAccessFailedCountAsync(User user, CancellationToken cancel) + { + await PostAsync($"{Address}/ResetAccessFailedCont", user, cancel); + } + + public async Task GetAccessFailedCountAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/GetAccessFailedCount", user, cancel)) + .Content + .ReadAsAsync(cancel); + } + + public async Task GetLockoutEnabledAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/GetLockoutEnabled", user, cancel)) + .Content + .ReadAsAsync(cancel); + } + + public async Task SetLockoutEnabledAsync(User user, bool enabled, CancellationToken cancel) + { + var response = await PostAsync($"{Address}/SetLockoutEnabled/{enabled}", user, cancel); + user.LockoutEnabled = await response.Content.ReadAsAsync(cancel); + } + + #endregion + + #region Implementation of IUserTwoFactorStore + + public async Task SetTwoFactorEnabledAsync(User user, bool enabled, CancellationToken cancel) + { + var response = await PostAsync($"{Address}/SetTwoFactor/{enabled}", user, cancel); + user.TwoFactorEnabled = await response.Content.ReadAsAsync(cancel); + } + + public async Task GetTwoFactorEnabledAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/GetTwoFactorEnabled", user, cancel)) + .Content + .ReadAsAsync(cancel); + } + + #endregion + + #region Implementation of IUserClaimStore + + public async Task> GetClaimsAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/GetClaims", user, cancel)) + .Content + .ReadAsAsync>(cancel); + } + + public async Task AddClaimsAsync(User user, IEnumerable claims, CancellationToken cancel) + { + await PostAsync( + $"{Address}/AddClaims", + new AddClaimDTO { User = user, Claims = claims }, + cancel); + } + + public async Task ReplaceClaimAsync(User user, Claim OldClaim, Claim NewClaim, CancellationToken cancel) + { + await PostAsync( + $"{Address}/ReplaceClaim", + new ReplaceClaimDTO { User = user, Claim = OldClaim, NewClaim = NewClaim }, + cancel); + } + + public async Task RemoveClaimsAsync(User user, IEnumerable claims, CancellationToken cancel) + { + await PostAsync( + $"{Address}/RemoveClaims", + new RemoveClaimDTO { User = user, Claims = claims }, + cancel); + } + + public async Task> GetUsersForClaimAsync(Claim claim, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/GetUsersForClaim", claim, cancel)) + .Content + .ReadAsAsync>(cancel); + } + + #endregion + } +} diff --git a/Services/WebStore.Client/Orders/OrdersClient.cs b/Services/WebStore.Client/Orders/OrdersClient.cs new file mode 100644 index 0000000..cb0e6dc --- /dev/null +++ b/Services/WebStore.Client/Orders/OrdersClient.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Webstore.Interfaces; +using Webstore.Interfaces.Services; +using WebStore.Client.Base; +using WebStore.Domain.DTO.Orders; +using WebStore.Domain.ViewModels; +using WebStore.Interfaces; + +namespace WebStore.Client.Orders +{ + public class OrdersClient : BaseClient, IOrderService + { + private readonly ILogger _Logger; + public OrdersClient(IConfiguration Configuration, ILogger Logger) + : base(Configuration, WebAPI.Orders) => + _Logger = Logger; + + + public async Task> GetUserOrders(string UserName) => + await GetAsync>($"{Address}/user/{UserName}"); + + public async Task GetOrderById(int id) => + await GetAsync($"{Address}/{id}"); + + public async Task CreateOrder(string UserName, CreateOrderModel OrderModel) + { + var response = await PostAsync($"{Address}/{UserName}", OrderModel); + return await response.Content.ReadAsAsync(); + } + } +} diff --git a/Services/WebStore.Client/Products/ProductsClient.cs b/Services/WebStore.Client/Products/ProductsClient.cs new file mode 100644 index 0000000..12d4d38 --- /dev/null +++ b/Services/WebStore.Client/Products/ProductsClient.cs @@ -0,0 +1,55 @@ +using Microsoft.Extensions.Configuration; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using Webstore.Interfaces; +using Webstore.Interfaces.Services; +using WebStore.Client.Base; +using WebStore.Domain; +using WebStore.Domain.DTO.Products; + +namespace WebStore.Client.Products +{ + public class ProductsClient : BaseClient, IProductData + { + public ProductsClient(IConfiguration Configuration) : base(Configuration, WebAPI.Products) + { + } + + public IEnumerable GetBrands() + { + return Get>($"{Address}/brands"); + } + + public BrandDTO GetBrandsById(int id) + { + return Get($"{Address}/brands/{id}"); + } + + public ProductDTO GetProductById(int id) + { + return Get($"{Address}/{id}"); + } + + public IEnumerable GetProducts(ProductFilter Filter = null) + { + return Post(Address, Filter ?? new ProductFilter()) + .Content + .ReadAsAsync>() + .Result; + } + + public IEnumerable GetСategories() + { + return Get>($"{Address}/categories"); + } + + public CategoryDTO GetСategoriesById(int id) + { + return Get($"{Address}/categories/{id}"); + } + } +} diff --git a/Services/WebStore.Client/Values/ValuesClient.cs b/Services/WebStore.Client/Values/ValuesClient.cs index 273b5e0..f2109d0 100644 --- a/Services/WebStore.Client/Values/ValuesClient.cs +++ b/Services/WebStore.Client/Values/ValuesClient.cs @@ -4,6 +4,7 @@ using System.Net; using System.Net.Http; using Microsoft.Extensions.Configuration; +using Webstore.Interfaces; using WebStore.Client.Base; using WebStore.Interfaces.TestAPI; @@ -11,7 +12,7 @@ namespace WebStore.Client.Values { public class ValuesClient : BaseClient, IValuesServices { - public ValuesClient(IConfiguration Configuration) : base(Configuration, "api/values") { } + public ValuesClient(IConfiguration Configuration) : base(Configuration, WebAPI.Values) { } public IEnumerable Get() { diff --git a/Services/WebStore.Client/WebStore.Client.csproj b/Services/WebStore.Client/WebStore.Client.csproj index 5af1b39..d23926e 100644 --- a/Services/WebStore.Client/WebStore.Client.csproj +++ b/Services/WebStore.Client/WebStore.Client.csproj @@ -1,7 +1,7 @@ - netstandard2.1 + net5.0 diff --git a/Services/WebStore.ServiceHosting/Controllers/EmployeesApiController.cs b/Services/WebStore.ServiceHosting/Controllers/EmployeesApiController.cs new file mode 100644 index 0000000..5ee2691 --- /dev/null +++ b/Services/WebStore.ServiceHosting/Controllers/EmployeesApiController.cs @@ -0,0 +1,79 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Webstore.Interfaces; +using Webstore.Interfaces.Services; +using WebStore.Domain.Models; + +namespace WebStore.ServiceHosting.Controllers +{ + [Route(WebAPI.Employees)] + [ApiController] + public class EmployeesApiController : ControllerBase, IEmployeesData + { + private readonly IEmployeesData _db; + private readonly ILogger _Logger; + + public EmployeesApiController(IEmployeesData db, ILogger Logger) + { + _db = db; + _Logger = Logger; + } + + [HttpPost] + public int Add(Employee employee) + { + if (!ModelState.IsValid) + { + _Logger.LogWarning("Ошибка модели данных при добавлении нового сотрудника {0} {1}", + employee.LastName, employee.FirstName); + return 0; + } + _Logger.LogInformation("Добавление сотрудника {0} {1}", + employee.LastName, employee.FirstName); + var id = _db.Add(employee); + if (id > 0) + _Logger.LogInformation("Cотрудник [id:{0}] {1} {2} добавлен успешно", + employee.Id, employee.LastName, employee.FirstName); + else + _Logger.LogWarning("Ошибка при добавлении сотрудника {0} {1}", + employee.LastName, employee.FirstName); + return id; + } + + [HttpDelete("{id}")] + public bool Delete(int id) + { + + var result = _db.Delete(id); + if (result) + _Logger.LogInformation("Сотрудник с id:{0} успешно удалён", id); + else + _Logger.LogWarning("ошибка при попытке удаления сотрдуника с id:{0}", id); + + return result; + } + + [HttpGet] + public IEnumerable Get() + { + return _db.Get(); + } + + [HttpGet("{id}")] + public Employee Get(int id) + { + return _db.Get(id); + } + + [HttpPut] + public void Update(Employee employee) + { + _db.Update(employee); + } + } +} diff --git a/Services/WebStore.ServiceHosting/Controllers/Identity/RolesApiController.cs b/Services/WebStore.ServiceHosting/Controllers/Identity/RolesApiController.cs new file mode 100644 index 0000000..5208a40 --- /dev/null +++ b/Services/WebStore.ServiceHosting/Controllers/Identity/RolesApiController.cs @@ -0,0 +1,78 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity.EntityFrameworkCore; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Webstore.DAL.Context; +using Webstore.Interfaces; +using WebStore.Domain.Entities.Identity; + +namespace WebStore.ServiceHosting.Controllers.Identity +{ + [Route(WebAPI.Identity.Role)] + [ApiController] + public class RolesApiController : ControllerBase + { + private readonly RoleStore _RoleStore; + + public RolesApiController(WebStoreDB db) + { + _RoleStore = new RoleStore(db); + } + + [HttpGet("all")] + public async Task> GetAllRoles() => await _RoleStore.Roles.ToArrayAsync(); + + [HttpPost] + public async Task CreateAsync(Role role) + { + var creation_result = await _RoleStore.CreateAsync(role); + return creation_result.Succeeded; + } + + [HttpPut] + public async Task UpdateAsync(Role role) + { + var uprate_result = await _RoleStore.UpdateAsync(role); + return uprate_result.Succeeded; + } + + [HttpPost("Delete")] + public async Task DeleteAsync(Role role) + { + var delete_result = await _RoleStore.DeleteAsync(role); + return delete_result.Succeeded; + } + + [HttpPost("GetRoleId")] + public async Task GetRoleIdAsync([FromBody] Role role) => await _RoleStore.GetRoleIdAsync(role); + + [HttpPost("GetRoleName")] + public async Task GetRoleNameAsync([FromBody] Role role) => await _RoleStore.GetRoleNameAsync(role); + + [HttpPost("SetRoleName/{name}")] + public async Task SetRoleNameAsync(Role role, string name) + { + await _RoleStore.SetRoleNameAsync(role, name); + await _RoleStore.UpdateAsync(role); + return role.Name; + } + + [HttpPost("GetNormalizedRoleName")] + public async Task GetNormalizedRoleNameAsync(Role role) => await _RoleStore.GetNormalizedRoleNameAsync(role); + + [HttpPost("SetNormalizedRoleName/{name}")] + public async Task SetNormalizedRoleNameAsync(Role role, string name) + { + await _RoleStore.SetNormalizedRoleNameAsync(role, name); + await _RoleStore.UpdateAsync(role); + return role.NormalizedName; + } + + [HttpGet("FindById/{id}")] + public async Task FindByIdAsync(string id) => await _RoleStore.FindByIdAsync(id); + + [HttpGet("FindByName/{name}")] + public async Task FindByNameAsync(string name) => await _RoleStore.FindByNameAsync(name); + } +} diff --git a/Services/WebStore.ServiceHosting/Controllers/Identity/UsersApiController.cs b/Services/WebStore.ServiceHosting/Controllers/Identity/UsersApiController.cs new file mode 100644 index 0000000..bb50d84 --- /dev/null +++ b/Services/WebStore.ServiceHosting/Controllers/Identity/UsersApiController.cs @@ -0,0 +1,299 @@ +using System; +using System.Collections.Generic; +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Identity.EntityFrameworkCore; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Webstore.DAL.Context; +using Webstore.Interfaces; +using WebStore.Domain.DTO.Identity; +using WebStore.Domain.Entities.Identity; + +namespace WebStore.ServiceHosting.Controllers.Identity +{ + [Route(WebAPI.Identity.User)] + [ApiController] + public class UsersApiController : ControllerBase + { + private readonly UserStore _UserStore; + + public UsersApiController(WebStoreDB db) + { + _UserStore = new UserStore(db); + } + + [HttpGet("all")] + public async Task> GetAllUsers() => await _UserStore.Users.ToArrayAsync(); + + #region Users + + [HttpPost("UserId")] // POST: api/users/UserId + public async Task GetUserIdAsync([FromBody] User user) => await _UserStore.GetUserIdAsync(user); + + [HttpPost("UserName")] + public async Task GetUserNameAsync([FromBody] User user) => await _UserStore.GetUserNameAsync(user); + + [HttpPost("UserName/{name}")] // api/users/UserName/TestUser + public async Task SetUserNameAsync([FromBody] User user, string name) + { + await _UserStore.SetUserNameAsync(user, name); + await _UserStore.UpdateAsync(user); + return user.UserName; + } + + [HttpPost("NormalUserName")] + public async Task GetNormalizedUserNameAsync([FromBody] User user) => await _UserStore.GetNormalizedUserNameAsync(user); + + [HttpPost("NormalUserName/{name}")] + public async Task SetNormalizedUserNameAsync([FromBody] User user, string name) + { + await _UserStore.SetNormalizedUserNameAsync(user, name); + await _UserStore.UpdateAsync(user); + return user.NormalizedUserName; + } + + [HttpPost("User")] // api/users/user + public async Task CreateAsync([FromBody] User user) + { + var creation_result = await _UserStore.CreateAsync(user); + // добавление ошибок создания нового пользователя в журнал + return creation_result.Succeeded; + } + + [HttpPut("User")] + public async Task UpdateAsync([FromBody] User user) + { + var update_result = await _UserStore.UpdateAsync(user); + return update_result.Succeeded; + } + + [HttpPost("User/Delete")] + public async Task DeleteAsync([FromBody] User user) + { + var delete_result = await _UserStore.DeleteAsync(user); + return delete_result.Succeeded; + } + + [HttpGet("User/Find/{id}")] // api/users/user/Find/9E5CB5E7-41DE-4449-829E-45F4C97AA54B + public async Task FindByIdAsync(string id) => await _UserStore.FindByIdAsync(id); + + [HttpGet("User/Normal/{name}")] // api/users/user/Normal/TestUser + public async Task FindByNameAsync(string name) => await _UserStore.FindByNameAsync(name); + + [HttpPost("Role/{role}")] + public async Task AddToRoleAsync([FromBody] User user, string role, [FromServices] WebStoreDB db) + { + await _UserStore.AddToRoleAsync(user, role); + await db.SaveChangesAsync(); + } + + [HttpPost("Role/Delete/{role}")] + public async Task RemoveFromRoleAsync([FromBody] User user, string role, [FromServices] WebStoreDB db) + { + await _UserStore.RemoveFromRoleAsync(user, role); + await db.SaveChangesAsync(); + } + + [HttpPost("Roles")] + public async Task> GetRolesAsync([FromBody] User user) => await _UserStore.GetRolesAsync(user); + + [HttpPost("InRole/{role}")] + public async Task IsInRoleAsync([FromBody] User user, string role) => await _UserStore.IsInRoleAsync(user, role); + + [HttpGet("UsersInRole/{role}")] + public async Task> GetUsersInRoleAsync(string role) => await _UserStore.GetUsersInRoleAsync(role); + + [HttpPost("GetPasswordHash")] + public async Task GetPasswordHashAsync([FromBody] User user) => await _UserStore.GetPasswordHashAsync(user); + + [HttpPost("SetPasswordHash")] + public async Task SetPasswordHashAsync([FromBody] PasswordHashDTO hash) + { + await _UserStore.SetPasswordHashAsync(hash.User, hash.Hash); + await _UserStore.UpdateAsync(hash.User); + return hash.User.PasswordHash; + } + + [HttpPost("HasPassword")] + public async Task HasPasswordAsync([FromBody] User user) => await _UserStore.HasPasswordAsync(user); + + #endregion + + #region Claims + + [HttpPost("GetClaims")] + public async Task> GetClaimsAsync([FromBody] User user) => await _UserStore.GetClaimsAsync(user); + + [HttpPost("AddClaims")] + public async Task AddClaimsAsync([FromBody] AddClaimDTO ClaimInfo, [FromServices] WebStoreDB db) + { + await _UserStore.AddClaimsAsync(ClaimInfo.User, ClaimInfo.Claims); + await db.SaveChangesAsync(); + } + + [HttpPost("ReplaceClaim")] + public async Task ReplaceClaimAsync([FromBody] ReplaceClaimDTO ClaimInfo, [FromServices] WebStoreDB db) + { + await _UserStore.ReplaceClaimAsync(ClaimInfo.User, ClaimInfo.Claim, ClaimInfo.NewClaim); + await db.SaveChangesAsync(); + } + + [HttpPost("RemoveClaim")] + public async Task RemoveClaimsAsync([FromBody] RemoveClaimDTO ClaimInfo, [FromServices] WebStoreDB db) + { + await _UserStore.RemoveClaimsAsync(ClaimInfo.User, ClaimInfo.Claims); + await db.SaveChangesAsync(); + } + + [HttpPost("GetUsersForClaim")] + public async Task> GetUsersForClaimAsync([FromBody] Claim claim) => + await _UserStore.GetUsersForClaimAsync(claim); + + #endregion + + #region TwoFactor + + [HttpPost("GetTwoFactorEnabled")] + public async Task GetTwoFactorEnabledAsync([FromBody] User user) => await _UserStore.GetTwoFactorEnabledAsync(user); + + [HttpPost("SetTwoFactor/{enable}")] + public async Task SetTwoFactorEnabledAsync([FromBody] User user, bool enable) + { + await _UserStore.SetTwoFactorEnabledAsync(user, enable); + await _UserStore.UpdateAsync(user); + return user.TwoFactorEnabled; + } + + #endregion + + #region Email/Phone + + [HttpPost("GetEmail")] + public async Task GetEmailAsync([FromBody] User user) => await _UserStore.GetEmailAsync(user); + + [HttpPost("SetEmail/{email}")] + public async Task SetEmailAsync([FromBody] User user, string email) + { + await _UserStore.SetEmailAsync(user, email); + await _UserStore.UpdateAsync(user); + return user.Email; + } + + [HttpPost("GetEmailConfirmed")] + public async Task GetEmailConfirmedAsync([FromBody] User user) => await _UserStore.GetEmailConfirmedAsync(user); + + [HttpPost("SetEmailConfirmed/{enable}")] + public async Task SetEmailConfirmedAsync([FromBody] User user, bool enable) + { + await _UserStore.SetEmailConfirmedAsync(user, enable); + await _UserStore.UpdateAsync(user); + return user.EmailConfirmed; + } + + [HttpGet("UserFindByEmail/{email}")] + public async Task FindByEmailAsync(string email) => await _UserStore.FindByEmailAsync(email); + + [HttpPost("GetNormalizedEmail")] + public async Task GetNormalizedEmailAsync([FromBody] User user) => await _UserStore.GetNormalizedEmailAsync(user); + + [HttpPost("SetNormalizedEmail/{email?}")] + public async Task SetNormalizedEmailAsync([FromBody] User user, string email) + { + await _UserStore.SetNormalizedEmailAsync(user, email); + await _UserStore.UpdateAsync(user); + return user.NormalizedEmail; + } + + [HttpPost("GetPhoneNumber")] + public async Task GetPhoneNumberAsync([FromBody] User user) => await _UserStore.GetPhoneNumberAsync(user); + + [HttpPost("SetPhoneNumber/{phone}")] + public async Task SetPhoneNumberAsync([FromBody] User user, string phone) + { + await _UserStore.SetPhoneNumberAsync(user, phone); + await _UserStore.UpdateAsync(user); + return user.PhoneNumber; + } + + [HttpPost("GetPhoneNumberConfirmed")] + public async Task GetPhoneNumberConfirmedAsync([FromBody] User user) => + await _UserStore.GetPhoneNumberConfirmedAsync(user); + + [HttpPost("SetPhoneNumberConfirmed/{confirmed}")] + public async Task SetPhoneNumberConfirmedAsync([FromBody] User user, bool confirmed) + { + await _UserStore.SetPhoneNumberConfirmedAsync(user, confirmed); + await _UserStore.UpdateAsync(user); + return user.PhoneNumberConfirmed; + } + + #endregion + + #region Login/Lockout + + [HttpPost("AddLogin")] + public async Task AddLoginAsync([FromBody] AddLoginDTO login, [FromServices] WebStoreDB db) + { + await _UserStore.AddLoginAsync(login.User, login.UserLoginInfo); + await db.SaveChangesAsync(); + } + + [HttpPost("RemoveLogin/{LoginProvider}/{ProviderKey}")] + public async Task RemoveLoginAsync([FromBody] User user, string LoginProvider, string ProviderKey, [FromServices] WebStoreDB db) + { + await _UserStore.RemoveLoginAsync(user, LoginProvider, ProviderKey); + await db.SaveChangesAsync(); + } + + [HttpPost("GetLogins")] + public async Task> GetLoginsAsync([FromBody] User user) => await _UserStore.GetLoginsAsync(user); + + [HttpGet("User/FindByLogin/{LoginProvider}/{ProviderKey}")] + public async Task FindByLoginAsync(string LoginProvider, string ProviderKey) => await _UserStore.FindByLoginAsync(LoginProvider, ProviderKey); + + [HttpPost("GetLockoutEndDate")] + public async Task GetLockoutEndDateAsync([FromBody] User user) => await _UserStore.GetLockoutEndDateAsync(user); + + [HttpPost("SetLockoutEndDate")] + public async Task SetLockoutEndDateAsync([FromBody] SetLockoutDTO LockoutInfo) + { + await _UserStore.SetLockoutEndDateAsync(LockoutInfo.User, LockoutInfo.LockoutEnd); + await _UserStore.UpdateAsync(LockoutInfo.User); + return LockoutInfo.User.LockoutEnd; + } + + [HttpPost("IncrementAccessFailedCount")] + public async Task IncrementAccessFailedCountAsync([FromBody] User user) + { + var count = await _UserStore.IncrementAccessFailedCountAsync(user); + await _UserStore.UpdateAsync(user); + return count; + } + + [HttpPost("ResetAccessFailedCount")] + public async Task ResetAccessFailedCountAsync([FromBody] User user) + { + await _UserStore.ResetAccessFailedCountAsync(user); + await _UserStore.UpdateAsync(user); + return user.AccessFailedCount; + } + + [HttpPost("GetAccessFailedCount")] + public async Task GetAccessFailedCountAsync([FromBody] User user) => await _UserStore.GetAccessFailedCountAsync(user); + + [HttpPost("GetLockoutEnabled")] + public async Task GetLockoutEnabledAsync([FromBody] User user) => await _UserStore.GetLockoutEnabledAsync(user); + + [HttpPost("SetLockoutEnabled/{enable}")] + public async Task SetLockoutEnabledAsync([FromBody] User user, bool enable) + { + await _UserStore.SetLockoutEnabledAsync(user, enable); + await _UserStore.UpdateAsync(user); + return user.LockoutEnabled; + } + + #endregion + } +} diff --git a/Services/WebStore.ServiceHosting/Controllers/OrdersApiController.cs b/Services/WebStore.ServiceHosting/Controllers/OrdersApiController.cs new file mode 100644 index 0000000..151c665 --- /dev/null +++ b/Services/WebStore.ServiceHosting/Controllers/OrdersApiController.cs @@ -0,0 +1,46 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Webstore.Interfaces; +using Webstore.Interfaces.Services; +using WebStore.Domain.DTO.Orders; +using WebStore.Domain.Entities.Orders; +using WebStore.Domain.ViewModels; + +namespace WebStore.ServiceHosting.Controllers +{ + [Route(WebAPI.Orders)] + [ApiController] + public class OrdersApiController : ControllerBase, IOrderService + { + private readonly IOrderService orderService; + private readonly ILogger logger; + + public OrdersApiController(IOrderService orderService, ILogger Logger) + { + this.orderService = orderService; + logger = Logger; + } + + [HttpPost("{UserName}")] + public async Task CreateOrder(string UserName, CreateOrderModel OrderModel) + { + return await orderService.CreateOrder(UserName, OrderModel); + } + + [HttpGet("{id}")] + public async Task GetOrderById(int id) + { + return await orderService.GetOrderById(id); + } + [HttpGet("user/{UserName}")] + public async Task> GetUserOrders(string UserName) + { + return await orderService.GetUserOrders(UserName); + } + } +} diff --git a/Services/WebStore.ServiceHosting/Controllers/ProductsApiController.cs b/Services/WebStore.ServiceHosting/Controllers/ProductsApiController.cs new file mode 100644 index 0000000..49063bd --- /dev/null +++ b/Services/WebStore.ServiceHosting/Controllers/ProductsApiController.cs @@ -0,0 +1,66 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Webstore.Interfaces; +using Webstore.Interfaces.Services; +using WebStore.Domain; +using WebStore.Domain.DTO.Products; +using WebStore.Domain.Entities; + +namespace WebStore.ServiceHosting.Controllers +{ + [Route(WebAPI.Products)] + [ApiController] + public class ProductsApiController : ControllerBase, IProductData + { + private readonly IProductData _db; + private readonly ILogger _Logger; + + public ProductsApiController(IProductData db, ILogger Logger) + { + _db = db; + _Logger = Logger; + } + + [HttpGet("brands")] + public IEnumerable GetBrands() + { + return _db.GetBrands(); + } + + [HttpGet("brands/{id}")] + public BrandDTO GetBrandsById(int id) + { + throw new NotImplementedException(); + } + + [HttpGet("{id}")] + public ProductDTO GetProductById(int id) + { + return _db.GetProductById(id); + } + + + [HttpPost] + public IEnumerable GetProducts([FromBody]ProductFilter Filter = null) + { + return _db.GetProducts(Filter); + } + + [HttpGet("categories")] + public IEnumerable GetСategories() + { + return _db.GetСategories(); + } + + [HttpGet("categories/{id}")] + public CategoryDTO GetСategoriesById(int id) + { + throw new NotImplementedException(); + } + } +} diff --git a/Services/WebStore.ServiceHosting/Controllers/ValuesController.cs b/Services/WebStore.ServiceHosting/Controllers/ValuesController.cs index 4976812..f1d1be6 100644 --- a/Services/WebStore.ServiceHosting/Controllers/ValuesController.cs +++ b/Services/WebStore.ServiceHosting/Controllers/ValuesController.cs @@ -2,10 +2,11 @@ using System.Linq; using Microsoft.AspNetCore.Mvc; +using Webstore.Interfaces; namespace WebStore.ServiceHosting.Controllers { - [Route("api/[controller]")] // http://localhost:5001/api/values + [Route(WebAPI.Values)] // http://localhost:5001/api/values [ApiController] public class ValuesController : ControllerBase { diff --git a/Services/WebStore.ServiceHosting/Startup.cs b/Services/WebStore.ServiceHosting/Startup.cs index f4cb774..8071915 100644 --- a/Services/WebStore.ServiceHosting/Startup.cs +++ b/Services/WebStore.ServiceHosting/Startup.cs @@ -1,6 +1,8 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -10,6 +12,13 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Webstore.DAL.Context; +using Webstore.Interfaces.Services; +using Webstore.Services.Data; +using Webstore.Services.Products; +using Webstore.Services.Products.InCookies; +using Webstore.Services.Products.InSql; +using WebStore.Domain.Entities.Identity; namespace WebStore.ServiceHosting { @@ -17,14 +26,43 @@ public class Startup { public Startup(IConfiguration configuration) { - Configuration = configuration; + _Configuration = configuration; } - public IConfiguration Configuration { get; } + private readonly IConfiguration _Configuration; // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { + services.AddDbContext(opt => opt.UseSqlServer(_Configuration.GetConnectionString("Default"))); + services.AddTransient(); + + services.AddIdentity() + .AddEntityFrameworkStores() + .AddDefaultTokenProviders(); + + services.AddSingleton(); + services.AddTransient(); + services.AddScoped(); + services.AddScoped(); + + services.Configure(opt => + { +#if DEBUG + opt.Password.RequiredLength = 3; + opt.Password.RequireDigit = false; + opt.Password.RequireLowercase = false; + opt.Password.RequireUppercase = false; + opt.Password.RequireNonAlphanumeric = false; + opt.Password.RequiredUniqueChars = 3; +#endif + opt.User.RequireUniqueEmail = false; + opt.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; + + opt.Lockout.AllowedForNewUsers = true; + opt.Lockout.MaxFailedAccessAttempts = 10; + opt.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(10); + }); services.AddControllers(); services.AddSwaggerGen(c => @@ -34,8 +72,9 @@ public void ConfigureServices(IServiceCollection services) } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + public void Configure(IApplicationBuilder app, IWebHostEnvironment env, WebStoreDbInitializer db) { + db.Initialize(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); diff --git a/Services/WebStore.ServiceHosting/WebStore.ServiceHosting.csproj b/Services/WebStore.ServiceHosting/WebStore.ServiceHosting.csproj index 2884716..7169942 100644 --- a/Services/WebStore.ServiceHosting/WebStore.ServiceHosting.csproj +++ b/Services/WebStore.ServiceHosting/WebStore.ServiceHosting.csproj @@ -8,4 +8,11 @@ + + + + + + + diff --git a/Services/WebStore.ServiceHosting/appsettings.json b/Services/WebStore.ServiceHosting/appsettings.json index d9d9a9b..f455cbb 100644 --- a/Services/WebStore.ServiceHosting/appsettings.json +++ b/Services/WebStore.ServiceHosting/appsettings.json @@ -1,4 +1,7 @@ { + "ConnectionStrings": { + "Default": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=WebStore-DB" + }, "Logging": { "LogLevel": { "Default": "Information", diff --git a/Services/Webstore.DAL/Webstore.DAL.csproj b/Services/Webstore.DAL/Webstore.DAL.csproj index be79c82..d57450a 100644 --- a/Services/Webstore.DAL/Webstore.DAL.csproj +++ b/Services/Webstore.DAL/Webstore.DAL.csproj @@ -1,7 +1,7 @@ - netstandard2.1 + net5.0 diff --git a/Services/Webstore.Interfaces/Services/IOrderService.cs b/Services/Webstore.Interfaces/Services/IOrderService.cs index 024e0c0..fba8b44 100644 --- a/Services/Webstore.Interfaces/Services/IOrderService.cs +++ b/Services/Webstore.Interfaces/Services/IOrderService.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Threading.Tasks; +using WebStore.Domain.DTO.Orders; using WebStore.Domain.Entities.Orders; using WebStore.Domain.ViewModels; @@ -7,10 +8,10 @@ namespace Webstore.Interfaces.Services { public interface IOrderService { - Task> GetUserOrders(string UserName); + Task> GetUserOrders(string UserName); - Task GetOrderById(int id); + Task GetOrderById(int id); - Task CreateOrder(string UserName, CartViewModel Cart, OrderViewModel OrderModel); + Task CreateOrder(string UserName, CreateOrderModel OrderModel); } } diff --git a/Services/Webstore.Interfaces/Services/IProductData.cs b/Services/Webstore.Interfaces/Services/IProductData.cs index 2c753ed..20811fd 100644 --- a/Services/Webstore.Interfaces/Services/IProductData.cs +++ b/Services/Webstore.Interfaces/Services/IProductData.cs @@ -1,17 +1,22 @@ using System.Collections.Generic; using WebStore.Domain; +using WebStore.Domain.DTO.Products; using WebStore.Domain.Entities; namespace Webstore.Interfaces.Services { public interface IProductData { - IEnumerable GetСategories(); + IEnumerable GetСategories(); - IEnumerable GetBrands(); + CategoryDTO GetСategoriesById(int id); - IEnumerable GetProducts(ProductFilter Filter = null); + IEnumerable GetBrands(); + + BrandDTO GetBrandsById(int id); - Product GetProductById(int id); + IEnumerable GetProducts(ProductFilter Filter = null); + + ProductDTO GetProductById(int id); } } diff --git a/Services/Webstore.Interfaces/Services/Identity/IRolesClient.cs b/Services/Webstore.Interfaces/Services/Identity/IRolesClient.cs new file mode 100644 index 0000000..e740a45 --- /dev/null +++ b/Services/Webstore.Interfaces/Services/Identity/IRolesClient.cs @@ -0,0 +1,7 @@ +using Microsoft.AspNetCore.Identity; +using WebStore.Domain.Entities.Identity; + +namespace WebStore.Interfaces.Services.Identity +{ + public interface IRolesClient : IRoleStore { } +} diff --git a/Services/Webstore.Interfaces/Services/Identity/IUsersClient.cs b/Services/Webstore.Interfaces/Services/Identity/IUsersClient.cs new file mode 100644 index 0000000..5b9bc66 --- /dev/null +++ b/Services/Webstore.Interfaces/Services/Identity/IUsersClient.cs @@ -0,0 +1,16 @@ +using Microsoft.AspNetCore.Identity; +using WebStore.Domain.Entities.Identity; + +namespace WebStore.Interfaces.Services.Identity +{ + public interface IUsersClient : + IUserRoleStore, + IUserPasswordStore, + IUserEmailStore, + IUserPhoneNumberStore, + IUserTwoFactorStore, + IUserLoginStore, + IUserClaimStore + { + } +} diff --git a/Services/Webstore.Interfaces/WebAPI.cs b/Services/Webstore.Interfaces/WebAPI.cs new file mode 100644 index 0000000..f1a1ce0 --- /dev/null +++ b/Services/Webstore.Interfaces/WebAPI.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Webstore.Interfaces +{ + public static class WebAPI + { + private const string api = "api/"; + + public const string Version = "v1"; + + public const string Products = api + Version + "api/products"; + public const string Values = api + Version + "api/values"; + public const string Employees = api + Version + "api/employees"; + public const string Orders = api + Version + "api/orders"; + + public static class Identity + { + public const string User = api + Version + "/users"; + public const string Role = api + Version + "/roles"; + } + } +} diff --git a/Services/Webstore.Interfaces/Webstore.Interfaces.csproj b/Services/Webstore.Interfaces/Webstore.Interfaces.csproj index aa3cb70..2f2fc48 100644 --- a/Services/Webstore.Interfaces/Webstore.Interfaces.csproj +++ b/Services/Webstore.Interfaces/Webstore.Interfaces.csproj @@ -1,7 +1,7 @@ - netstandard2.1 + net5.0 diff --git a/Services/Webstore.Services/Mapping/BrandMapper.cs b/Services/Webstore.Services/Mapping/BrandMapper.cs new file mode 100644 index 0000000..298a701 --- /dev/null +++ b/Services/Webstore.Services/Mapping/BrandMapper.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WebStore.Domain.DTO.Products; +using WebStore.Domain.Entities; + +namespace Webstore.Services.Mapping +{ + public static class BrandMapper + { + public static BrandDTO ToDTO(this Brand Brand) => Brand is null ? null + : new BrandDTO + { + Id = Brand.Id, + Name = Brand.Name, + Order = Brand.Order, + ProductsCount = Brand.Products.Count(), + }; + public static Brand FromDTO(this BrandDTO Brand) => Brand is null ? null + : new Brand + { + Id = Brand.Id, + Name = Brand.Name, + Order = Brand.Order + }; + public static IEnumerable ToDTO(this IEnumerable Brands) => Brands.Select(ToDTO); + + public static IEnumerable FromDTO(this IEnumerable Brands) => Brands.Select(FromDTO); + + } +} diff --git a/Services/Webstore.Services/Mapping/CategoryMapper.cs b/Services/Webstore.Services/Mapping/CategoryMapper.cs new file mode 100644 index 0000000..813a4d1 --- /dev/null +++ b/Services/Webstore.Services/Mapping/CategoryMapper.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WebStore.Domain.DTO.Products; +using WebStore.Domain.Entities; + +namespace Webstore.Services.Mapping +{ + public static class CategoryMapper + { + public static CategoryDTO ToDTO(this Category Category) => Category is null ? null + : new CategoryDTO + { + Id = Category.Id, + Name = Category.Name, + Order = Category.Order, + ParentId = Category.ParentId, + ProductsCount = Category.Products.Count() + }; + public static Category FromDTO(this CategoryDTO Category) => Category is null ? null + : new Category + { + Id = Category.Id, + Name = Category.Name, + Order = Category.Order, + ParentId = Category.ParentId + }; + public static IEnumerable ToDTO(this IEnumerable Categories) => Categories.Select(ToDTO); + + public static IEnumerable FromDTO(this IEnumerable Categories) => Categories.Select(FromDTO); + } +} diff --git a/Services/Webstore.Services/Mapping/OrderMapper.cs b/Services/Webstore.Services/Mapping/OrderMapper.cs new file mode 100644 index 0000000..e90ae88 --- /dev/null +++ b/Services/Webstore.Services/Mapping/OrderMapper.cs @@ -0,0 +1,38 @@ +using System.Linq; +using WebStore.Domain.DTO.Orders; +using WebStore.Domain.Entities.Orders; + +namespace WebStore.Services.Mapping +{ + public static class OrderMapper + { + public static OrderItemDTO ToDTO(this OrderItem Item) => Item is null + ? null + : new OrderItemDTO(Item.Id, Item.Price, Item.Quantity); + + public static OrderItem FromDTO(this OrderItemDTO Item) => Item is null + ? null + : new OrderItem + { + Id = Item.Id, + Price = Item.Price, + Quantity = Item.Quantity + }; + + public static OrderDTO ToDTO(this Order Order) => Order is null + ? null + : new OrderDTO(Order.Id, Order.Name, Order.Phone, Order.Address, Order.Date, Order.Items.Select(ToDTO)); + + public static Order FromDTO(this OrderDTO Order) => Order is null + ? null + : new Order + { + Id = Order.Id, + Name = Order.Name, + Phone = Order.Phone, + Address = Order.Address, + Date = Order.Date, + Items = Order.Items.Select(FromDTO).ToList() + }; + } +} diff --git a/Services/Webstore.Services/Mapping/ProductMapper.cs b/Services/Webstore.Services/Mapping/ProductMapper.cs index 9ecb34b..85af67a 100644 --- a/Services/Webstore.Services/Mapping/ProductMapper.cs +++ b/Services/Webstore.Services/Mapping/ProductMapper.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using WebStore.Domain.DTO.Products; using WebStore.Domain.Entities; using WebStore.Domain.ViewModels; @@ -21,9 +22,43 @@ public static class ProductMapper ImageUrl = p.ImageUrl, Name = p.Name, Order = p.Order, - Price = p.Price + Price = p.Price }; public static IEnumerable ToView(this IEnumerable p) => p.Select(ToView); + + public static ProductDTO ToDTO(this Product product) => product is null ? null + : new ProductDTO + { + Id = product.Id, + Name = product.Name, + Order = product.Order, + Price = product.Price, + ImageUrl = product.ImageUrl, + Brand = product.Brand.ToDTO(), + Category = product.Category.ToDTO(), + Description = product.Description, + Discount = product.Discount + }; + + public static Product FromDTO(this ProductDTO Product) => Product is null ? null + : new Product + { + Id = Product.Id, + Name = Product.Name, + Order = Product.Order, + Price = Product.Price, + ImageUrl = Product.ImageUrl, + Description = Product.Description, + Discount = Product.Discount, + Brand = Product.Brand.FromDTO(), + Category = Product.Category.FromDTO(), + BrandId = Product.Brand.Id, + CategoryId = Product.Category.Id + + }; + public static IEnumerable ToDTO(this IEnumerable products) => products.Select(ToDTO); + + public static IEnumerable FromDTO(this IEnumerable products) => products.Select(FromDTO); } } diff --git a/Services/Webstore.Services/Products/InCookies/InCookiesCartService.cs b/Services/Webstore.Services/Products/InCookies/InCookiesCartService.cs index dc77a4b..eb32380 100644 --- a/Services/Webstore.Services/Products/InCookies/InCookiesCartService.cs +++ b/Services/Webstore.Services/Products/InCookies/InCookiesCartService.cs @@ -113,7 +113,7 @@ public CartViewModel TransformFromCart() Ids = Cart.Items.Select(item => item.ProductId).ToArray() }); - var product_view_models = products.ToView().ToDictionary(p => p.Id); + var product_view_models = products.FromDTO().ToView().ToDictionary(p => p.Id); return new CartViewModel { diff --git a/Services/Webstore.Services/Products/InMemoryProductsData.cs b/Services/Webstore.Services/Products/InMemoryProductsData.cs index 885aca1..e042302 100644 --- a/Services/Webstore.Services/Products/InMemoryProductsData.cs +++ b/Services/Webstore.Services/Products/InMemoryProductsData.cs @@ -6,17 +6,19 @@ using WebStore.Domain; using WebStore.Domain.Entities; using Webstore.Services.Data; +using WebStore.Domain.DTO.Products; +using Webstore.Services.Mapping; namespace Webstore.Services.Products { [Obsolete("Класс устарел и не реализует необходимые методы")] public class InMemoryProductsData : IProductData { - public IEnumerable GetBrands() => TestDB.Brands; + public IEnumerable GetBrands() => TestDB.Brands.ToDTO(); - public IEnumerable GetСategories() => TestDB.Сategories; + public IEnumerable GetСategories() => TestDB.Сategories.ToDTO(); - public IEnumerable GetProducts(ProductFilter Filter = null) + public IEnumerable GetProducts(ProductFilter Filter = null) { var query = TestDB.Products; @@ -24,10 +26,20 @@ public IEnumerable GetProducts(ProductFilter Filter = null) query = query.Where(product => product.CategoryId == category_id).ToList(); if (Filter?.BrandId is { } brand_id) query = query.Where(product => product.BrandId == brand_id).ToList(); - return query; + return query.ToDTO(); } - public Product GetProductById(int id) + public ProductDTO GetProductById(int id) + { + throw new NotImplementedException(); + } + + public CategoryDTO GetСategoriesById(int id) + { + throw new NotImplementedException(); + } + + public BrandDTO GetBrandsById(int id) { throw new NotImplementedException(); } diff --git a/Services/Webstore.Services/Products/InSql/InSqIProductData.cs b/Services/Webstore.Services/Products/InSql/InSqIProductData.cs index 250a022..e8fc7cc 100644 --- a/Services/Webstore.Services/Products/InSql/InSqIProductData.cs +++ b/Services/Webstore.Services/Products/InSql/InSqIProductData.cs @@ -7,6 +7,8 @@ using Webstore.Interfaces.Services; using WebStore.Domain; using WebStore.Domain.Entities; +using Webstore.Services.Mapping; +using WebStore.Domain.DTO.Products; namespace Webstore.Services.Products.InSql { @@ -19,14 +21,19 @@ public InSqIProductData(WebStoreDB db) _db = db; } - public IEnumerable GetBrands() => _db.Brands.Include(brand => brand.Products); + public IEnumerable GetBrands() => _db.Brands.Include(brand => brand.Products).ToDTO(); - public Product GetProductById(int id) + public BrandDTO GetBrandsById(int id) { - return _db.Products.Include(p => p.Brand).Include(p => p.Category).FirstOrDefault(p => p.Id == id); + return _db.Brands.Include(brand => brand.Products).FirstOrDefault(brand => brand.Id == id).ToDTO(); } - public IEnumerable GetProducts(ProductFilter Filter = null) + public ProductDTO GetProductById(int id) + { + return _db.Products.Include(p => p.Brand).Include(p => p.Category).FirstOrDefault(p => p.Id == id).ToDTO(); + } + + public IEnumerable GetProducts(ProductFilter Filter = null) { IQueryable query = _db.Products.Include(p => p.Category).Include(p => p.Brand); @@ -43,9 +50,14 @@ public IEnumerable GetProducts(ProductFilter Filter = null) query = query.Where(product => product.CategoryId == Filter.СategoryId); } - return query; + return query.AsEnumerable().ToDTO(); } - public IEnumerable GetСategories() => _db.Categories.Include(category => category.Products); + public IEnumerable GetСategories() => _db.Categories.Include(category => category.Products).ToDTO(); + + public CategoryDTO GetСategoriesById(int id) + { + return _db.Categories.Include(category => category.Products).FirstOrDefault(category => category.Id == id).ToDTO(); + } } } diff --git a/Services/Webstore.Services/Products/InSql/SqlOrderService.cs b/Services/Webstore.Services/Products/InSql/SqlOrderService.cs index 30be498..9f5876d 100644 --- a/Services/Webstore.Services/Products/InSql/SqlOrderService.cs +++ b/Services/Webstore.Services/Products/InSql/SqlOrderService.cs @@ -7,9 +7,11 @@ using Microsoft.EntityFrameworkCore; using Webstore.DAL.Context; using Webstore.Interfaces.Services; +using WebStore.Domain.DTO.Orders; using WebStore.Domain.Entities.Identity; using WebStore.Domain.Entities.Orders; using WebStore.Domain.ViewModels; +using WebStore.Services.Mapping; namespace Webstore.Services.Products.InSql { @@ -24,18 +26,18 @@ public SqlOrderService(WebStoreDB db, UserManager UserManager) _UserManager = UserManager; } - public async Task> GetUserOrders(string UserName) => await _db.Orders + public async Task> GetUserOrders(string UserName) => (await _db.Orders .Include(order => order.User) .Include(order => order.Items) .Where(order => order.User.UserName == UserName) - .ToArrayAsync(); + .ToArrayAsync()).Select(o => o.ToDTO()); - public async Task GetOrderById(int id) => await _db.Orders + public async Task GetOrderById(int id) => (await _db.Orders .Include(order => order.User) .Include(order => order.Items) - .FirstOrDefaultAsync(order => order.Id == id); + .FirstOrDefaultAsync(order => order.Id == id)).ToDTO(); - public async Task CreateOrder(string UserName, CartViewModel Cart, OrderViewModel OrderModel) + public async Task CreateOrder(string UserName, CreateOrderModel OrderModel) { var user = await _UserManager.FindByNameAsync(UserName); if (user is null) @@ -45,32 +47,27 @@ public async Task CreateOrder(string UserName, CartViewModel Cart, OrderV var order = new Order { - Name = OrderModel.Name, - Address = OrderModel.Address, - Phone = OrderModel.Phone, + Name = OrderModel.Order.Name, + Address = OrderModel.Order.Address, + Phone = OrderModel.Order.Phone, User = user, Date = DateTime.Now, }; - var product_ids = Cart.Items.Select(i => i.Product.Id).ToArray(); - var cart_products = await _db.Products - .Where(p => product_ids.Contains(p.Id)) - .ToArrayAsync(); + foreach (var (id, _, quantity) in OrderModel.Items) + { + var product = await _db.Products.FindAsync(id); + if (product is null) continue; - var items = - from cart_item in Cart.Items - join product in cart_products - on cart_item.Product.Id equals product.Id - select new OrderItem + var order_item = new OrderItem { Order = order, Price = product.Price, - Quantity = cart_item.Quantity, + Quantity = quantity, Product = product }; - - foreach (var order_item in items) order.Items.Add(order_item); + } await _db.Orders.AddAsync(order); @@ -78,7 +75,7 @@ on cart_item.Product.Id equals product.Id await transaction.CommitAsync(); - return order; + return order.ToDTO(); } } } diff --git a/Services/Webstore.Services/Webstore.Services.csproj b/Services/Webstore.Services/Webstore.Services.csproj index 794bced..459e7cd 100644 --- a/Services/Webstore.Services/Webstore.Services.csproj +++ b/Services/Webstore.Services/Webstore.Services.csproj @@ -1,7 +1,7 @@  - netstandard2.1 + net5.0 diff --git a/UI/WebStore/Controllers/CartController.cs b/UI/WebStore/Controllers/CartController.cs index 6771fdc..58aa5d2 100644 --- a/UI/WebStore/Controllers/CartController.cs +++ b/UI/WebStore/Controllers/CartController.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Threading.Tasks; using Webstore.Interfaces.Services; +using WebStore.Domain.DTO.Orders; using WebStore.Domain.ViewModels; namespace WebStore.Controllers @@ -60,10 +61,18 @@ public async Task CheckOut(OrderViewModel OrderModel, [FromServic Order = OrderModel }); + var create_order_model = new CreateOrderModel( + OrderModel, + _CartService.TransformFromCart().Items + .Select(item => new OrderItemDTO( + item.Product.Id, + item.Product.Price, + item.Quantity)) + .ToList()); + var order = await OrderService.CreateOrder( User.Identity!.Name, - _CartService.TransformFromCart(), - OrderModel); + create_order_model); _CartService.Clear(); diff --git a/UI/WebStore/Controllers/ShopController.cs b/UI/WebStore/Controllers/ShopController.cs index 334b6bc..2a530af 100644 --- a/UI/WebStore/Controllers/ShopController.cs +++ b/UI/WebStore/Controllers/ShopController.cs @@ -5,7 +5,6 @@ using WebStore.Domain; using WebStore.Domain.ViewModels; using WebStore.Domain.Entities; -using WebStore.Domain.ViewModels; using Webstore.Interfaces.Services; using Webstore.Services.Mapping; @@ -24,9 +23,9 @@ public IActionResult Index(int? BrandId, int? CategoryID) СategoryId = CategoryID, }; - var productc = _ProductData.GetProducts(filter); - var brends = _ProductData.GetBrands(); - var categories = _ProductData.GetСategories(); + var productc = _ProductData.GetProducts(filter).FromDTO(); + var brends = _ProductData.GetBrands().FromDTO(); + var categories = _ProductData.GetСategories().FromDTO(); @@ -73,7 +72,7 @@ private IEnumerable Categories(IEnumerable Icateg } public IActionResult Product(int id) { - var product = _ProductData.GetProductById(id); + var product = _ProductData.GetProductById(id).FromDTO(); if (product is null) return NotFound(); return View(product.ToView()); diff --git a/UI/WebStore/Controllers/UserProfileController.cs b/UI/WebStore/Controllers/UserProfileController.cs new file mode 100644 index 0000000..57d0d57 --- /dev/null +++ b/UI/WebStore/Controllers/UserProfileController.cs @@ -0,0 +1,31 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Webstore.Interfaces.Services; +using WebStore.Domain.ViewModels; + +namespace WebStore.Controllers +{ + [Authorize] + public class UserProfileController : Controller + { + public IActionResult Index() => View(); + + public async Task Orders([FromServices] IOrderService OrderService) + { + var orders = await OrderService.GetUserOrders(User.Identity!.Name); + + return View(orders.Select(order => new UserOrderViewModel + { + Id = order.Id, + Name = order.Name, + Phone = order.Phone, + Address = order.Address, + TotalSum = order.Items.Sum(item => item.Price * item.Quantity) + })); + } + } +} diff --git a/UI/WebStore/Startup.cs b/UI/WebStore/Startup.cs index de4f804..05fb28f 100644 --- a/UI/WebStore/Startup.cs +++ b/UI/WebStore/Startup.cs @@ -19,6 +19,10 @@ using Webstore.Services.Products.InSql; using WebStore.Client.Values; using WebStore.Interfaces.TestAPI; +using WebStore.Client.Employees; +using WebStore.Client.Products; +using WebStore.Client.Orders; +using WebStore.Clients.Identity; namespace WebStore { @@ -26,16 +30,14 @@ public class Startup { // This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 + private readonly IConfiguration _Configuration; public Startup(IConfiguration Configuration) => _Configuration = Configuration; public void ConfigureServices(IServiceCollection services) { - services.AddDbContext(opt => opt.UseSqlServer(_Configuration.GetConnectionString("Default"))); - services.AddTransient(); - services.AddIdentity() - .AddEntityFrameworkStores() + .AddIdentityWebStoreWebAPIClients() .AddDefaultTokenProviders(); services.Configure(opt => @@ -70,21 +72,18 @@ public void ConfigureServices(IServiceCollection services) }); services.AddControllersWithViews().AddRazorRuntimeCompilation(); - services.AddSingleton(); - //services.AddTransient(); - services.AddTransient(); - //InMemoryBlogsData: IBlogsData + services.AddSingleton(); + services.AddTransient(); services.AddSingleton(); services.AddScoped(); - services.AddScoped(); + services.AddScoped(); services.AddScoped(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env, WebStoreDbInitializer db) + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { - db.Initialize(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); diff --git a/UI/WebStore/Views/Shared/Components/UserInfo/UserInfo.cshtml b/UI/WebStore/Views/Shared/Components/UserInfo/UserInfo.cshtml index e4ffcc0..eaa69a3 100644 --- a/UI/WebStore/Views/Shared/Components/UserInfo/UserInfo.cshtml +++ b/UI/WebStore/Views/Shared/Components/UserInfo/UserInfo.cshtml @@ -1,5 +1,5 @@ @using WebStore.Domain.Entities.Identity - + @if (User.IsInRole(Role.Administrator)) { diff --git a/UI/WebStore/Views/UserProfile/Index.cshtml b/UI/WebStore/Views/UserProfile/Index.cshtml new file mode 100644 index 0000000..82d9a69 --- /dev/null +++ b/UI/WebStore/Views/UserProfile/Index.cshtml @@ -0,0 +1,8 @@ + +@{ + Layout = "_UserProfileLayout"; + ViewData["Title"] = "Профиль пользователя"; +} + +

Профиль пользователя

+ diff --git a/UI/WebStore/Views/UserProfile/Orders.cshtml b/UI/WebStore/Views/UserProfile/Orders.cshtml new file mode 100644 index 0000000..9dfa990 --- /dev/null +++ b/UI/WebStore/Views/UserProfile/Orders.cshtml @@ -0,0 +1,31 @@ +@model IEnumerable +@{ + Layout = "_UserProfileLayout"; + ViewData["Title"] = "Заказы"; +} + + + + + + + + + + + + + @{ var i = 1; } + @foreach (var order in Model) + { + + + + + + + + } + +
ИмяАдресТелефонСумма
@(i++)@order.Name@order.Address@order.Phone@order.TotalSum
+ diff --git a/UI/WebStore/Views/UserProfile/Partial/_Index_Scripts.cshtml b/UI/WebStore/Views/UserProfile/Partial/_Index_Scripts.cshtml new file mode 100644 index 0000000..f5b2aed --- /dev/null +++ b/UI/WebStore/Views/UserProfile/Partial/_Index_Scripts.cshtml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/UI/WebStore/Views/UserProfile/Partial/_Index_Styles.cshtml b/UI/WebStore/Views/UserProfile/Partial/_Index_Styles.cshtml new file mode 100644 index 0000000..40166d6 --- /dev/null +++ b/UI/WebStore/Views/UserProfile/Partial/_Index_Styles.cshtml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/UI/WebStore/Views/UserProfile/Partial/_UserProfileMenu.cshtml b/UI/WebStore/Views/UserProfile/Partial/_UserProfileMenu.cshtml new file mode 100644 index 0000000..f7dbebb --- /dev/null +++ b/UI/WebStore/Views/UserProfile/Partial/_UserProfileMenu.cshtml @@ -0,0 +1,15 @@ +
+ +
+ +
+ +
+ +
+ +
\ No newline at end of file diff --git a/UI/WebStore/Views/UserProfile/_UserProfileLayout.cshtml b/UI/WebStore/Views/UserProfile/_UserProfileLayout.cshtml new file mode 100644 index 0000000..9da4ea5 --- /dev/null +++ b/UI/WebStore/Views/UserProfile/_UserProfileLayout.cshtml @@ -0,0 +1,20 @@ +@section Styles { + +} +@section Scripts { + +} +@{ + Layout = "_Layout"; +} + +
+
+
+ +
+
+ @RenderBody() +
+
+
\ No newline at end of file