From 8bb27130693e0a4964a464293dad6fac0595d678 Mon Sep 17 00:00:00 2001 From: "Amir.H Khademi" Date: Tue, 28 May 2024 18:50:02 +0330 Subject: [PATCH] feat(MartenDB) , feat(Brew) , feat(BrewService) -Add MartentDB and MartenEntity -Add MartenRepository -Add BaseBrew entity and CoffeBrew -Add BrewService for manage brews entity --- .../AppSettings/appsettings.Development.json | 3 +- Brizco.Api/Brizco.Api.csproj | 16 +++ Brizco.Api/Controllers/RecipeController.cs | 35 ++++++ Brizco.Api/Dockerfile | 13 +- Brizco.Api/Program.cs | 26 +--- .../Configurations/ServiceExtensions.cs | 20 +-- Brizco.Common/Brizco.Common.csproj | 24 ++-- .../Models/Claims/ApplicationClaims.cs | 32 +++++ .../Models/Claims/ApplicationPermission.cs | 3 + Brizco.Common/Models/Entity/IMartenEntity.cs | 9 ++ Brizco.Common/Models/Entity/MartenEntity.cs | 42 +++++++ Brizco.Core/Brizco.Core.csproj | 5 +- .../Abstracts/IJwtService.cs | 4 +- .../JwtService.cs | 26 ++-- .../TaskReportCommandHandler.cs | 3 +- .../EntityServices/Abstracts/IBrewService.cs | 8 ++ Brizco.Core/EntityServices/BrewService.cs | 116 ++++++++++++++++++ .../EntityServices/ShiftPlanService.cs | 4 +- Brizco.Core/Models/Api/ApiResult.cs | 6 +- Brizco.Domain/Brizco.Domain.csproj | 2 +- .../MartenEntities/Brews/BaseBrew.cs | 10 ++ .../MartenEntities/Brews/BaseRecipeLDto.cs | 8 ++ .../MartenEntities/Brews/CoffeeBrew.cs | 11 ++ .../Brizco.Infrastructure.csproj | 4 + .../Marten/MartenRepository.cs | 62 ++++++++++ .../Marten/MartenRepositoryWrapper.cs | 16 +++ .../Repositories/Marten/IMartenRepository.cs | 15 +++ .../Marten/IMartenRepositoryWrapper.cs | 6 + 28 files changed, 449 insertions(+), 80 deletions(-) create mode 100644 Brizco.Api/Controllers/RecipeController.cs create mode 100644 Brizco.Common/Models/Entity/IMartenEntity.cs create mode 100644 Brizco.Common/Models/Entity/MartenEntity.cs rename Brizco.Core/{BaseServices => CoreServices}/Abstracts/IJwtService.cs (88%) rename Brizco.Core/{BaseServices => CoreServices}/JwtService.cs (88%) create mode 100644 Brizco.Core/EntityServices/Abstracts/IBrewService.cs create mode 100644 Brizco.Core/EntityServices/BrewService.cs create mode 100644 Brizco.Domain/MartenEntities/Brews/BaseBrew.cs create mode 100644 Brizco.Domain/MartenEntities/Brews/BaseRecipeLDto.cs create mode 100644 Brizco.Domain/MartenEntities/Brews/CoffeeBrew.cs create mode 100644 Brizco.Infrastructure/Marten/MartenRepository.cs create mode 100644 Brizco.Infrastructure/Marten/MartenRepositoryWrapper.cs create mode 100644 Brizco.Repository/Repositories/Marten/IMartenRepository.cs create mode 100644 Brizco.Repository/Repositories/Marten/IMartenRepositoryWrapper.cs diff --git a/Brizco.Api/AppSettings/appsettings.Development.json b/Brizco.Api/AppSettings/appsettings.Development.json index 4ac73f7..aaafaa7 100644 --- a/Brizco.Api/AppSettings/appsettings.Development.json +++ b/Brizco.Api/AppSettings/appsettings.Development.json @@ -1,7 +1,8 @@ { "ConnectionStrings": { "PostgresServer": "Host=185.220.227.123;port=5432;Username=postgres;Password=ub0J7sFFThkSBmkc0TzSKsCfheRnQpyu;Database=BrizcoDB", - "Postgres": "Host=pg-0,pg-1;Username=igarsonAgent;Password=xHTpBf4wC+bBeNg2pL6Ga7VEWKFJx7VPEUpqxwPFfOc2YYTVwFQuHfsiqoVeT9+6;Database=BrizcoDB;Load Balance Hosts=true;Target Session Attributes=primary;Application Name=iGLS" + "Postgres": "Host=pg-0,pg-1;Username=igarsonAgent;Password=xHTpBf4wC+bBeNg2pL6Ga7VEWKFJx7VPEUpqxwPFfOc2YYTVwFQuHfsiqoVeT9+6;Database=BrizcoDB;Load Balance Hosts=true;Target Session Attributes=primary;Application Name=iGLS", + "MartenDB": "Host=pg-0,pg-1;Username=igarsonAgent;Password=xHTpBf4wC+bBeNg2pL6Ga7VEWKFJx7VPEUpqxwPFfOc2YYTVwFQuHfsiqoVeT9+6;Database=BrizcoMartenDB;" }, "Logging": { "LogLevel": { diff --git a/Brizco.Api/Brizco.Api.csproj b/Brizco.Api/Brizco.Api.csproj index e5892c1..b6dcaec 100644 --- a/Brizco.Api/Brizco.Api.csproj +++ b/Brizco.Api/Brizco.Api.csproj @@ -56,20 +56,36 @@ + + + + + + + + + + + + + + + + diff --git a/Brizco.Api/Controllers/RecipeController.cs b/Brizco.Api/Controllers/RecipeController.cs new file mode 100644 index 0000000..35d451c --- /dev/null +++ b/Brizco.Api/Controllers/RecipeController.cs @@ -0,0 +1,35 @@ +using Marten; +using System.Text.Json; + +namespace Brizco.Api.Controllers; + +public class RecipeController : ICarterModule +{ + public void AddRoutes(IEndpointRouteBuilder app) + { + var group = app.NewVersionedApi("Brews") + .MapGroup("api/brew"); + + group.MapGet("{recipeName}/latest", GetLatestBrewAsync) + .WithDisplayName("Get Latest Brew") + .WithDescription("Get latest brew that has been set for day , you have pass recipe name in route") + .HasApiVersion(1.0); + + group.MapPost("{recipeName}", AddBrewAsync) + .WithDisplayName("Add Brew") + .WithDescription("Add latest brew that has been set for day , you have pass recipe model") + .HasApiVersion(1.0); + } + + private async Task GetLatestBrewAsync([FromRoute] string recipeName, + [FromServices] IBrewService brewService, CancellationToken cancellationToken) + => TypedResults.Ok(await brewService.GetLastBrewAsync(recipeName, cancellationToken)); + + private async Task AddBrewAsync([FromRoute] string recipeName, + [FromBody] JsonDocument recipeObj, [FromServices] IBrewService brewService, + CancellationToken cancellationToken) + { + await brewService.AddBrewAsync(recipeName, recipeObj, cancellationToken); + return TypedResults.Ok(); + } +} \ No newline at end of file diff --git a/Brizco.Api/Dockerfile b/Brizco.Api/Dockerfile index 3484f81..0b30706 100644 --- a/Brizco.Api/Dockerfile +++ b/Brizco.Api/Dockerfile @@ -1,19 +1,20 @@ #See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +ENV ASPNETCORE_URLS=https://0.0.0.0:8010 WORKDIR /app -EXPOSE 80 +EXPOSE 8010 FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /src -COPY ["Berizco.Api/Berizco.Api.csproj", "Berizco.Api/"] -RUN dotnet restore "Berizco.Api/Berizco.Api.csproj" +COPY ["Brizco.Api.csproj", "Brizco.Api/"] +RUN dotnet restore "Brizco.Api/Brizco.Api.csproj" COPY . . -WORKDIR "/src/Berizco.Api" -RUN dotnet build "Berizco.Api.csproj" -c Release -o /app/build +WORKDIR "/src/Brizco.Api" +RUN dotnet build "Brizco.Api.csproj" -c Release -o /app/build FROM build AS publish -RUN dotnet publish "Berizco.Api.csproj" -c Release -o /app/publish /p:UseAppHost=false +RUN dotnet publish "Brizco.Api.csproj" -c Release -o /app/publish /p:UseAppHost=false FROM base AS final WORKDIR /app diff --git a/Brizco.Api/Program.cs b/Brizco.Api/Program.cs index dd8f963..d8dd0af 100644 --- a/Brizco.Api/Program.cs +++ b/Brizco.Api/Program.cs @@ -1,18 +1,3 @@ -using Brizco.Api.WebFramework.Configurations; -using Brizco.Api.WebFramework.Swagger; -using Brizco.Common.Models; -using Brizco.Core; -using Brizco.Domain; -using Brizco.Domain.Models.Settings; -using Brizco.Infrastructure; -using Brizco.Repository; -using System.Configuration; -using Brizco.Api.WebFramework.ScalarUi; -using Carter; -using FluentValidation; -using MediatR.Extensions.Autofac.DependencyInjection; -using MediatR.Extensions.Autofac.DependencyInjection.Builder; - var builder = WebApplication.CreateBuilder(args); builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()); builder.Host.UseSerilog(); @@ -51,6 +36,7 @@ builder.Services.AddJwtCustomAuthentication(siteSetting.JwtSettings); builder.Services.AddMvcCore().AddRazorPages().AddRazorViewEngine().AddViews(); builder.Services.AddCustomIdentity(); builder.Services.AddCustomDbContext(configuration); +builder.Services.AddMarten(configuration, builder.Environment); builder.Services.AddCarter(); @@ -101,16 +87,10 @@ builder.Host.ConfigureContainer(builder => var app = builder.Build(); -// Configure the HTTP request pipeline. -if (app.Environment.IsDevelopment()) -{ - //app.UseCustomSwagger(siteSetting.BaseUrl); - //app.UseSwagger(); - //app.UseSwaggerUI(); -} +// Configure the HTTP request pipeline + app.UseCors("CorsPolicy"); -//app.UseCustomSwagger(siteSetting.BaseUrl); app.UseSwagger(); app.MapScalarUi(); diff --git a/Brizco.Api/WebFramework/Configurations/ServiceExtensions.cs b/Brizco.Api/WebFramework/Configurations/ServiceExtensions.cs index 00e377a..a3d53f4 100644 --- a/Brizco.Api/WebFramework/Configurations/ServiceExtensions.cs +++ b/Brizco.Api/WebFramework/Configurations/ServiceExtensions.cs @@ -2,16 +2,11 @@ using Asp.Versioning; using AspNetCoreRateLimit; using AspNetCoreRateLimit.Redis; -using Brizco.Common.Models.Api; -using Brizco.Core.Models.Api; -using Brizco.Domain.Entities.User; -using Brizco.Domain.Models.Settings; -using Brizco.Repository.Extensions; -using Brizco.Repository.Models; +using Marten; using Microsoft.AspNetCore.ResponseCompression; -using Newtonsoft.Json.Serialization; using StackExchange.Redis.Extensions.Core.Configuration; using StackExchange.Redis.Extensions.Newtonsoft; +using Weasel.Core; using Task = System.Threading.Tasks.Task; namespace Brizco.Api.WebFramework.Configurations; @@ -99,6 +94,17 @@ public static class ServiceExtensions })); } + public static void AddMarten(this IServiceCollection serviceCollection, IConfigurationRoot configuration, IWebHostEnvironment environment) + { + var marten = serviceCollection.AddMarten(options => + { + options.Connection(configuration.GetConnectionString("MartenDB")!); + if (environment.IsDevelopment()) + options.AutoCreateSchemaObjects = AutoCreate.All; + }); + } + + public static void AddCustomController(this IServiceCollection serviceCollection) { serviceCollection.AddControllers(options => { options.Filters.Add(new AuthorizeFilter()); }) diff --git a/Brizco.Common/Brizco.Common.csproj b/Brizco.Common/Brizco.Common.csproj index c2f2938..9b1165a 100644 --- a/Brizco.Common/Brizco.Common.csproj +++ b/Brizco.Common/Brizco.Common.csproj @@ -1,20 +1,20 @@  - + - + - - - + + + diff --git a/Brizco.Common/Models/Claims/ApplicationClaims.cs b/Brizco.Common/Models/Claims/ApplicationClaims.cs index b108fb0..5a9f70c 100644 --- a/Brizco.Common/Models/Claims/ApplicationClaims.cs +++ b/Brizco.Common/Models/Claims/ApplicationClaims.cs @@ -3,6 +3,22 @@ namespace Brizco.Common.Models.Claims; public static class ApplicationClaims { + + public static ClaimDto ManageRecipes { get; } = new ClaimDto + { + Type = CustomClaimType.Permission, + Value = ApplicationPermission.ManageRecipes, + Title = "دسترسی کامل به رسپی ها", + Detail = "دسترسی به افزودن و مدیریت مجموعه های سیستم" + }; + public static ClaimDto ViewRecipes { get; } = new ClaimDto + { + Type = CustomClaimType.Permission, + Value = ApplicationPermission.ViewRecipes, + Title = "مشاهده رسپی ها", + Detail = "دسترسی به مشاهده مجموعه ها" + }; + public static ClaimDto ManageComplexes { get; } = new ClaimDto { Type = CustomClaimType.Permission, @@ -207,6 +223,9 @@ public static class ApplicationClaims public static List AllClaimDtos = new List { + ManageRecipes, + ViewRecipes, + ManageActivities, ViewTasks, ManageTasks, @@ -241,6 +260,9 @@ public static class ApplicationClaims public static List AllClaims = new List { + ManageRecipes.GetClaim, + ViewRecipes.GetClaim, + ManageStaffs.GetClaim, ViewStaffs.GetClaim, ManageReports.GetClaim, @@ -282,6 +304,9 @@ public static class ApplicationClaims public static List ManagerClaims = new List { + ManageRecipes.GetClaim, + ViewRecipes.GetClaim, + ManageStaffs.GetClaim, ViewStaffs.GetClaim, ManageReports.GetClaim, @@ -319,6 +344,8 @@ public static class ApplicationClaims public static List ViewerOwnerClaims = new List { + ViewRecipes.GetClaim, + ManageReports.GetClaim, ViewStaffs.GetClaim, @@ -346,6 +373,9 @@ public static class ApplicationClaims public static List SuperVisorClaims = new List { + ManageRecipes.GetClaim, + ViewRecipes.GetClaim, + ManageActivities.GetClaim, ChangeActivityStatus.GetClaim, ViewMineActivities.GetClaim, @@ -369,6 +399,8 @@ public static class ApplicationClaims public static List StaffClaims = new List { + ViewRecipes.GetClaim, + ChangeActivityStatus.GetClaim, ViewMineActivities.GetClaim, diff --git a/Brizco.Common/Models/Claims/ApplicationPermission.cs b/Brizco.Common/Models/Claims/ApplicationPermission.cs index 37083b5..c195279 100644 --- a/Brizco.Common/Models/Claims/ApplicationPermission.cs +++ b/Brizco.Common/Models/Claims/ApplicationPermission.cs @@ -1,6 +1,9 @@ namespace Brizco.Common.Models.Claims; public static class ApplicationPermission { + public const string ViewRecipes = nameof(ViewRecipes); + public const string ManageRecipes = nameof(ManageRecipes); + public const string ManageReports = nameof(ManageReports); public const string ManageRoles = nameof(ManageRoles); public const string ViewRoles = nameof(ViewRoles); diff --git a/Brizco.Common/Models/Entity/IMartenEntity.cs b/Brizco.Common/Models/Entity/IMartenEntity.cs new file mode 100644 index 0000000..e390b8b --- /dev/null +++ b/Brizco.Common/Models/Entity/IMartenEntity.cs @@ -0,0 +1,9 @@ +namespace Brizco.Common.Models.Entity; + +public interface IMartenEntity +{ + string CreatedBy { get; } + string ModifiedBy { get; } + DateTime CreatedAt { get; } + DateTime ModifiedAt { get; } +} \ No newline at end of file diff --git a/Brizco.Common/Models/Entity/MartenEntity.cs b/Brizco.Common/Models/Entity/MartenEntity.cs new file mode 100644 index 0000000..5adf940 --- /dev/null +++ b/Brizco.Common/Models/Entity/MartenEntity.cs @@ -0,0 +1,42 @@ +namespace Brizco.Common.Models.Entity; + + +public class MartenEntity : IMartenEntity +{ + public Guid Id { get; set; } + + + [Display(Name = "تاریخ ساخت")] + public DateTime CreatedAt { get; set; } + + [Display(Name = "ساخته شده توسط")] + public string CreatedBy { get; set; } = string.Empty; + + [Display(Name = "اخرین تغییر در")] + public DateTime ModifiedAt { get; set; } + + [Display(Name = "اخرین تغییر توسط")] + public string ModifiedBy { get; set; } = string.Empty; + + + + public bool Equals(ApiEntity other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return Id.Equals(other.Id); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((ApiEntity)obj); + } + + public override int GetHashCode() + { + return Id.GetHashCode(); + } +} \ No newline at end of file diff --git a/Brizco.Core/Brizco.Core.csproj b/Brizco.Core/Brizco.Core.csproj index e7ddde3..28f13d4 100644 --- a/Brizco.Core/Brizco.Core.csproj +++ b/Brizco.Core/Brizco.Core.csproj @@ -31,7 +31,6 @@ - @@ -46,8 +45,11 @@ + + + @@ -57,6 +59,7 @@ + diff --git a/Brizco.Core/BaseServices/Abstracts/IJwtService.cs b/Brizco.Core/CoreServices/Abstracts/IJwtService.cs similarity index 88% rename from Brizco.Core/BaseServices/Abstracts/IJwtService.cs rename to Brizco.Core/CoreServices/Abstracts/IJwtService.cs index dec7e79..042cf3b 100644 --- a/Brizco.Core/BaseServices/Abstracts/IJwtService.cs +++ b/Brizco.Core/CoreServices/Abstracts/IJwtService.cs @@ -1,8 +1,8 @@ -namespace Brizco.Core.BaseServices.Abstracts; +namespace Brizco.Core.CoreServices.Abstracts; public interface IJwtService : IScopedDependency { - Task> Generate(TUser user, Guid complexId,Guid roleId) where TUser : ApplicationUser; + Task> Generate(TUser user, Guid complexId, Guid roleId) where TUser : ApplicationUser; Task> Generate(TUser user, Guid complexId) where TUser : ApplicationUser; Task> Generate(TUser user) where TUser : ApplicationUser; diff --git a/Brizco.Core/BaseServices/JwtService.cs b/Brizco.Core/CoreServices/JwtService.cs similarity index 88% rename from Brizco.Core/BaseServices/JwtService.cs rename to Brizco.Core/CoreServices/JwtService.cs index c4d4f8c..1dceb38 100644 --- a/Brizco.Core/BaseServices/JwtService.cs +++ b/Brizco.Core/CoreServices/JwtService.cs @@ -1,16 +1,8 @@ -using Brizco.Common.Models.Claims; -using Brizco.Core.BaseServices.Abstracts; -using Brizco.Domain.Models.Settings; -using Mapster; -using Microsoft.AspNetCore.Identity; -using Microsoft.Extensions.Options; -using Microsoft.IdentityModel.Tokens; +using Microsoft.Extensions.Options; using System.IdentityModel.Tokens.Jwt; -using System.Security.Claims; using System.Text; -using Brizco.Common.Extensions; -namespace Brizco.Core.BaseServices; +namespace Brizco.Core.CoreServices; public class JwtService : IJwtService { @@ -33,7 +25,7 @@ public class JwtService : IJwtService var claims = await GetClaims(user, tokenId, roleId.ToString()); claims.Add(new Claim("ComplexId", complexId.ToString())); - var token = BaseGenerate(user, claims); + var token = BaseGenerate(user, claims); token.Permissions = claims.Where(c => c.Type == "Permission").Select(c => c.Value).ToList(); return token; } @@ -64,10 +56,10 @@ public class JwtService : IJwtService return token; } - public async Task> Generate(TUser user, Guid complexId, Guid roleId) where TUser : ApplicationUser + public async Task> Generate(TUser user, Guid complexId, Guid roleId) where TUser : ApplicationUser { var tokenId = StringExtensions.GetId(8); - var claims = await GetClaims(user, tokenId,roleId.ToString()); + var claims = await GetClaims(user, tokenId, roleId.ToString()); claims.Add(new Claim("ComplexId", complexId.ToString())); return BaseGenerate(user, claims); @@ -132,7 +124,7 @@ public class JwtService : IJwtService return token; } - private AccessToken BaseGenerate(TUser user, List claims) where TUser : ApplicationUser + private AccessToken BaseGenerate(TUser user, List claims) where TUser : ApplicationUser { var secretKey = Encoding.UTF8.GetBytes(_siteSettings.JwtSettings.SecretKey); var signingCredintial = new SigningCredentials(new SymmetricSecurityKey(secretKey), SecurityAlgorithms.HmacSha512Signature); @@ -157,7 +149,7 @@ public class JwtService : IJwtService private async Task> GetClaims(TUser baseUser, string jwtId) where TUser : ApplicationUser { - var clFac = (await _signInManager.ClaimsFactory.CreateAsync(baseUser)); + var clFac = await _signInManager.ClaimsFactory.CreateAsync(baseUser); var claims = new List(); claims.Add(new Claim("JwtID", jwtId)); claims.Add(new Claim(ClaimTypes.Name, baseUser.UserName)); @@ -175,10 +167,10 @@ public class JwtService : IJwtService var applicationRole = await _roleManager.FindByIdAsync(roleId); var roleClaims = await _roleManager.GetClaimsAsync(applicationRole); var claims = new List(); - claims.Add(new Claim("SignUpStatus",((int)baseUser.SignUpStatus).ToString())); + claims.Add(new Claim("SignUpStatus", ((int)baseUser.SignUpStatus).ToString())); claims.Add(new Claim(ClaimTypes.Name, baseUser.UserName)); claims.Add(new Claim(ClaimTypes.NameIdentifier, baseUser.Id.ToString())); - claims.Add(new Claim(ClaimTypes.Role,applicationRole.EnglishName)); + claims.Add(new Claim(ClaimTypes.Role, applicationRole.EnglishName)); claims.Add(new Claim("RoleId", applicationRole.Id.ToString())); if (baseUser.Email != null) claims.Add(new Claim(ClaimTypes.Email, baseUser.Email)); diff --git a/Brizco.Core/CoreServices/ReportServices/TaskReportCommandHandler.cs b/Brizco.Core/CoreServices/ReportServices/TaskReportCommandHandler.cs index ff25ef7..b5e01fa 100644 --- a/Brizco.Core/CoreServices/ReportServices/TaskReportCommandHandler.cs +++ b/Brizco.Core/CoreServices/ReportServices/TaskReportCommandHandler.cs @@ -1,5 +1,4 @@ -using Brizco.Domain.Dtos.LargeDtos; -using Brizco.Domain.Entities.Task; +using Brizco.Domain.Entities.Task; using Task = System.Threading.Tasks.Task; namespace Brizco.Core.CoreServices.ReportServices; diff --git a/Brizco.Core/EntityServices/Abstracts/IBrewService.cs b/Brizco.Core/EntityServices/Abstracts/IBrewService.cs new file mode 100644 index 0000000..7c5cd11 --- /dev/null +++ b/Brizco.Core/EntityServices/Abstracts/IBrewService.cs @@ -0,0 +1,8 @@ +namespace Brizco.Core.EntityServices.Abstracts; + +public interface IBrewService : IScopedDependency +{ + public Task GetLastBrewAsync(string recipeName, CancellationToken cancellationToken = default); + public Task GetBrewAsync(string recipeName , CancellationToken cancellationToken = default); + public Task AddBrewAsync(string recipeName,JsonDocument recipeObj, CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/Brizco.Core/EntityServices/BrewService.cs b/Brizco.Core/EntityServices/BrewService.cs new file mode 100644 index 0000000..865b373 --- /dev/null +++ b/Brizco.Core/EntityServices/BrewService.cs @@ -0,0 +1,116 @@ +using Newtonsoft.Json; +using System.Reflection; +using Brizco.Domain; + +namespace Brizco.Core.EntityServices; + +public class BrewService : IBrewService +{ + private readonly IMartenRepositoryWrapper _martenRepositoryWrapper; + private readonly ICurrentUserService _currentUserService; + + public BrewService(IMartenRepositoryWrapper martenRepositoryWrapper,ICurrentUserService currentUserService) + { + _martenRepositoryWrapper = martenRepositoryWrapper; + _currentUserService = currentUserService; + } + public async Task GetLastBrewAsync(string recipeName, CancellationToken cancellationToken = default) + { + var type = Assembly.GetAssembly(typeof(DomainConfig))?.GetType($"Brizco.Domain.MartenEntities.Recipes.{recipeName}"); + if (type == null) + throw new AppException("Recipe not found", ApiResultStatusCode.NotFound); + if (_currentUserService.ComplexId == null) + throw new BaseApiException(ApiResultStatusCode.BadRequest,"Complex id is null"); + if (!Guid.TryParse(_currentUserService.ComplexId, out Guid complexId)) + throw new BaseApiException(ApiResultStatusCode.BadRequest, "Complex id is wrong"); + + var baseRecipe = await _martenRepositoryWrapper.SetRepository() + .GetEntityAsync(s => s.ComplexId == complexId && s.Name == recipeName, cancellationToken); + object? recipe; + if (baseRecipe == null) + recipe = Activator.CreateInstance(type); + else + recipe = JsonConvert.DeserializeObject(baseRecipe.CurrentBrewJson, type) ?? Activator.CreateInstance(type); + + if (recipe == null) + throw new AppException("Recipe type or base is wrong"); + + return recipe; + } + + public async Task GetBrewAsync(string recipeName, CancellationToken cancellationToken = default) + { + var type = Assembly.GetAssembly(typeof(DomainConfig))?.GetType($"Brizco.Domain.MartenEntities.Recipes.{recipeName}"); + if (type == null) + throw new AppException("Recipe not found", ApiResultStatusCode.NotFound); + if (_currentUserService.ComplexId == null) + throw new BaseApiException(ApiResultStatusCode.BadRequest, "Complex id is null"); + if (!Guid.TryParse(_currentUserService.ComplexId, out Guid complexId)) + throw new BaseApiException(ApiResultStatusCode.BadRequest, "Complex id is wrong"); + + var baseRecipe = await _martenRepositoryWrapper.SetRepository() + .GetEntityAsync(s =>s.ComplexId==complexId && s.Name == recipeName, cancellationToken); + object? recipe; + if (baseRecipe == null) + { + recipe = Activator.CreateInstance(type); + baseRecipe = new BaseBrew(); + } + else + recipe = JsonConvert.DeserializeObject(baseRecipe.CurrentBrewJson, type) ?? Activator.CreateInstance(type); + + if (recipe == null) + throw new AppException("Recipe type or base is wrong"); + + var pastRecipes = new List(); + foreach (var json in baseRecipe.PastBrewsJson) + { + var pastRecipe = JsonConvert.DeserializeObject(json, type) ?? Activator.CreateInstance(type); + if (pastRecipe != null) + pastRecipes.Add(pastRecipe); + } + + var dto = new BaseRecipeLDto + { + CurrentRecipe = recipe, + Name = recipeName, + PastRecipes = pastRecipes + }; + + return dto; + } + + public async Task AddBrewAsync(string recipeName, JsonDocument recipeObj, CancellationToken cancellationToken = default) + { + var type = Assembly.GetAssembly(typeof(DomainConfig))?.GetType($"Brizco.Domain.MartenEntities.Recipes.{recipeName}"); + if (type == null) + throw new AppException("Recipe not found", ApiResultStatusCode.NotFound); + + if (_currentUserService.ComplexId == null) + throw new BaseApiException(ApiResultStatusCode.BadRequest, "Complex id is null"); + if (!Guid.TryParse(_currentUserService.ComplexId, out Guid complexId)) + throw new BaseApiException(ApiResultStatusCode.BadRequest, "Complex id is wrong"); + + var baseRecipe = await _martenRepositoryWrapper.SetRepository() + .GetEntityAsync(s =>s.ComplexId == complexId && s.Name == recipeName, cancellationToken); + + if (baseRecipe == null) + { + baseRecipe = new BaseBrew() + { + CurrentBrewJson = JsonConvert.SerializeObject(recipeObj.Deserialize(type)), + Name = recipeName, + DotnetType = type.FullName ?? $"Brizco.Domain.MartenEntities.Recipes.{recipeName}", + ComplexId = complexId + }; + } + else + { + baseRecipe.PastBrewsJson.Add(baseRecipe.CurrentBrewJson); + baseRecipe.CurrentBrewJson = JsonConvert.SerializeObject(recipeObj.Deserialize(type)); + } + + await _martenRepositoryWrapper.SetRepository() + .AddOrUpdateEntityAsync(baseRecipe, cancellationToken); + } +} \ No newline at end of file diff --git a/Brizco.Core/EntityServices/ShiftPlanService.cs b/Brizco.Core/EntityServices/ShiftPlanService.cs index 4006135..ee54551 100644 --- a/Brizco.Core/EntityServices/ShiftPlanService.cs +++ b/Brizco.Core/EntityServices/ShiftPlanService.cs @@ -1,6 +1,4 @@ -using Brizco.Domain.CommandQueries.Commands; -using Brizco.Domain.CommandQueries.Queries; -using Brizco.Domain.Entities.Shift; +using Brizco.Domain.Entities.Shift; namespace Brizco.Core.EntityServices; diff --git a/Brizco.Core/Models/Api/ApiResult.cs b/Brizco.Core/Models/Api/ApiResult.cs index 0daf409..ff7babc 100644 --- a/Brizco.Core/Models/Api/ApiResult.cs +++ b/Brizco.Core/Models/Api/ApiResult.cs @@ -1,9 +1,5 @@ -using Brizco.Common.Extensions; -using Brizco.Common.Models.Api; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace Brizco.Core.Models.Api; diff --git a/Brizco.Domain/Brizco.Domain.csproj b/Brizco.Domain/Brizco.Domain.csproj index 679e3c4..464a6bc 100644 --- a/Brizco.Domain/Brizco.Domain.csproj +++ b/Brizco.Domain/Brizco.Domain.csproj @@ -1,6 +1,6 @@  - + net8.0 enable enable diff --git a/Brizco.Domain/MartenEntities/Brews/BaseBrew.cs b/Brizco.Domain/MartenEntities/Brews/BaseBrew.cs new file mode 100644 index 0000000..d30f3c7 --- /dev/null +++ b/Brizco.Domain/MartenEntities/Brews/BaseBrew.cs @@ -0,0 +1,10 @@ +namespace Brizco.Domain.MartenEntities.Brews; + +public class BaseBrew : MartenEntity +{ + public string Name { get; set; } = string.Empty; + public string CurrentBrewJson { get; set; } = string.Empty; + public string DotnetType { get; set; } = string.Empty; + public List PastBrewsJson { get; set; } = new(); + public Guid ComplexId { get; set; } +} \ No newline at end of file diff --git a/Brizco.Domain/MartenEntities/Brews/BaseRecipeLDto.cs b/Brizco.Domain/MartenEntities/Brews/BaseRecipeLDto.cs new file mode 100644 index 0000000..92a1f13 --- /dev/null +++ b/Brizco.Domain/MartenEntities/Brews/BaseRecipeLDto.cs @@ -0,0 +1,8 @@ +namespace Brizco.Domain.MartenEntities.Brews; + +public class BaseRecipeLDto +{ + public string Name { get; set; } = string.Empty; + public object CurrentRecipe { get; set; } = string.Empty; + public List PastRecipes { get; set; } = new(); +} \ No newline at end of file diff --git a/Brizco.Domain/MartenEntities/Brews/CoffeeBrew.cs b/Brizco.Domain/MartenEntities/Brews/CoffeeBrew.cs new file mode 100644 index 0000000..12ab56d --- /dev/null +++ b/Brizco.Domain/MartenEntities/Brews/CoffeeBrew.cs @@ -0,0 +1,11 @@ +namespace Brizco.Domain.MartenEntities.Brews; + +public class CoffeeBrew +{ + public DateTime LogAt { get; set; } + public string LogBy { get; set; } = string.Empty; + + public float Ratio { get; set; } + public int ExtractionTime { get; set; } + public float FinalYield { get; set; } +} \ No newline at end of file diff --git a/Brizco.Infrastructure/Brizco.Infrastructure.csproj b/Brizco.Infrastructure/Brizco.Infrastructure.csproj index 808ebd3..c7c4d49 100644 --- a/Brizco.Infrastructure/Brizco.Infrastructure.csproj +++ b/Brizco.Infrastructure/Brizco.Infrastructure.csproj @@ -8,6 +8,7 @@ + @@ -23,14 +24,17 @@ + + + diff --git a/Brizco.Infrastructure/Marten/MartenRepository.cs b/Brizco.Infrastructure/Marten/MartenRepository.cs new file mode 100644 index 0000000..7d0a1c7 --- /dev/null +++ b/Brizco.Infrastructure/Marten/MartenRepository.cs @@ -0,0 +1,62 @@ +using Marten; + +namespace Brizco.Infrastructure.Marten; + +public class MartenRepository : IMartenRepository where TMartenEntity : IMartenEntity +{ + private readonly IDocumentStore _documentStore; + + public MartenRepository(IDocumentStore documentStore) + { + _documentStore = documentStore; + } + + public async Task> GetEntitiesAsync(CancellationToken cancellation) + { + await using var session = _documentStore.QuerySession(); + var entities = await session.Query().ToListAsync(cancellation); + return entities.ToList(); + } + + public async Task> GetEntitiesAsync(Expression> expression, CancellationToken cancellation) + { + await using var session = _documentStore.QuerySession(); + var entities = await session.Query().Where(expression).ToListAsync(cancellation); + return entities.ToList(); + } + + public async Task GetEntityAsync(Guid id, CancellationToken cancellation) + { + await using var session = _documentStore.QuerySession(); + var setting = await session.LoadAsync(id, cancellation); + if (setting == null) + throw new AppException($"{nameof(setting)} not found", ApiResultStatusCode.NotFound); + return setting; + } + + public async Task GetEntityAsync(Expression> expression, CancellationToken cancellation) + { + await using var session = _documentStore.QuerySession(); + var entity = await session.Query().FirstOrDefaultAsync(expression, cancellation); + return entity; + } + + public async Task AddOrUpdateEntityAsync(TMartenEntity entity, CancellationToken cancellation) + { + if (entity == null) + throw new AppException($"{nameof(entity)} is null", ApiResultStatusCode.BadRequest); + + await using var session = _documentStore.LightweightSession(); + session.Store(entity); + await session.SaveChangesAsync(cancellation); + } + + public async Task RemoveEntityAsync(TMartenEntity entity, CancellationToken cancellation) + { + if (entity == null) + throw new AppException($"{nameof(entity)} is null", ApiResultStatusCode.BadRequest); + await using var session = _documentStore.LightweightSession(); + session.Delete(entity); + await session.SaveChangesAsync(cancellation); + } +} \ No newline at end of file diff --git a/Brizco.Infrastructure/Marten/MartenRepositoryWrapper.cs b/Brizco.Infrastructure/Marten/MartenRepositoryWrapper.cs new file mode 100644 index 0000000..54472a6 --- /dev/null +++ b/Brizco.Infrastructure/Marten/MartenRepositoryWrapper.cs @@ -0,0 +1,16 @@ +using Marten; + +namespace Brizco.Infrastructure.Marten; + +public class MartenRepositoryWrapper : IMartenRepositoryWrapper +{ + private readonly IDocumentStore _documentStore; + + public MartenRepositoryWrapper(IDocumentStore documentStore) + { + _documentStore = documentStore; + } + + public IMartenRepository SetRepository() where TMartenEntity : IMartenEntity + => new MartenRepository(_documentStore); +} \ No newline at end of file diff --git a/Brizco.Repository/Repositories/Marten/IMartenRepository.cs b/Brizco.Repository/Repositories/Marten/IMartenRepository.cs new file mode 100644 index 0000000..6f57bac --- /dev/null +++ b/Brizco.Repository/Repositories/Marten/IMartenRepository.cs @@ -0,0 +1,15 @@ +using System.Linq.Expressions; + +namespace Brizco.Repository.Repositories.Marten; + +public interface IMartenRepository : IScopedDependency where TMartenEntity : IMartenEntity +{ + Task> GetEntitiesAsync(CancellationToken cancellation = default); + Task> GetEntitiesAsync(Expression> expression, CancellationToken cancellation = default); + + Task GetEntityAsync(Guid id, CancellationToken cancellation = default); + Task GetEntityAsync(Expression> expression, CancellationToken cancellation = default); + + Task AddOrUpdateEntityAsync(TMartenEntity entity, CancellationToken cancellation = default); + Task RemoveEntityAsync(TMartenEntity entity, CancellationToken cancellation = default); +} \ No newline at end of file diff --git a/Brizco.Repository/Repositories/Marten/IMartenRepositoryWrapper.cs b/Brizco.Repository/Repositories/Marten/IMartenRepositoryWrapper.cs new file mode 100644 index 0000000..0258930 --- /dev/null +++ b/Brizco.Repository/Repositories/Marten/IMartenRepositoryWrapper.cs @@ -0,0 +1,6 @@ +namespace Brizco.Repository.Repositories.Marten; + +public interface IMartenRepositoryWrapper : IScopedDependency +{ + IMartenRepository SetRepository() where TMartenEntity : IMartenEntity; +} \ No newline at end of file