feat(MartenDB) , feat(Brew) , feat(BrewService)

-Add MartentDB and MartenEntity
-Add MartenRepository
-Add BaseBrew entity and CoffeBrew
-Add BrewService for manage brews entity
master
Amir Hossein Khademi 2024-05-28 18:50:02 +03:30
parent 91a73cbcef
commit 8bb2713069
28 changed files with 449 additions and 80 deletions

View File

@ -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": {

View File

@ -56,20 +56,36 @@
<ItemGroup>
<Using Include="Autofac" />
<Using Include="Autofac.Extensions.DependencyInjection" />
<Using Include="Brizco.Api.WebFramework.ScalarUi" />
<Using Include="Brizco.Api.WebFramework.Swagger" />
<Using Include="Brizco.Common.Models" />
<Using Include="Brizco.Common.Models.Api" />
<Using Include="Brizco.Common.Models.Claims" />
<Using Include="Brizco.Common.Models.Entity" />
<Using Include="Brizco.Common.Models.Exception" />
<Using Include="Brizco.Common.Models.Mapper" />
<Using Include="Brizco.Core" />
<Using Include="Brizco.Core.CoreServices.Abstracts" />
<Using Include="Brizco.Core.EntityServices.Abstracts" />
<Using Include="Brizco.Core.Models.Api" />
<Using Include="Brizco.Domain" />
<Using Include="Brizco.Domain.CommandQueries.Commands" />
<Using Include="Brizco.Domain.CommandQueries.Queries" />
<Using Include="Brizco.Domain.Dtos.RequestDtos" />
<Using Include="Brizco.Domain.Entities" />
<Using Include="Brizco.Domain.Entities.User" />
<Using Include="Brizco.Domain.Models.Settings" />
<Using Include="Brizco.Infrastructure" />
<Using Include="Brizco.Repository" />
<Using Include="Brizco.Repository.Extensions" />
<Using Include="Brizco.Repository.Models" />
<Using Include="Brizco.Repository.Repositories.Base.Contracts" />
<Using Include="Carter" />
<Using Include="FluentValidation" />
<Using Include="Mapster" />
<Using Include="MediatR" />
<Using Include="MediatR.Extensions.Autofac.DependencyInjection" />
<Using Include="MediatR.Extensions.Autofac.DependencyInjection.Builder" />
<Using Include="Microsoft.AspNetCore.Authentication.JwtBearer" />
<Using Include="Microsoft.AspNetCore.Authorization" />
<Using Include="Microsoft.AspNetCore.Identity" />

View File

@ -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<IResult> GetLatestBrewAsync([FromRoute] string recipeName,
[FromServices] IBrewService brewService, CancellationToken cancellationToken)
=> TypedResults.Ok(await brewService.GetLastBrewAsync(recipeName, cancellationToken));
private async Task<IResult> AddBrewAsync([FromRoute] string recipeName,
[FromBody] JsonDocument recipeObj, [FromServices] IBrewService brewService,
CancellationToken cancellationToken)
{
await brewService.AddBrewAsync(recipeName, recipeObj, cancellationToken);
return TypedResults.Ok();
}
}

View File

@ -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

View File

@ -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<ContainerBuilder>(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();

View File

@ -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()); })

View File

@ -1,20 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<!--<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<LangVersion>10</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<LangVersion>10</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MD.PersianDateTime.Standard" Version="2.5.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.5.1" />
</ItemGroup>-->
</ItemGroup>
<PropertyGroup>
<!--<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>10</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
@ -25,11 +25,11 @@
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.0.3" />
</ItemGroup>
</ItemGroup>-->
<ItemGroup>
<Using Include="MD.PersianDateTime.Standard" />
<Using Include="System.ComponentModel.DataAnnotations" />
<Using Include="System.ComponentModel.DataAnnotations.Schema" />
<Using Include="MD.PersianDateTime.Standard" />
<Using Include="System.ComponentModel.DataAnnotations" />
<Using Include="System.ComponentModel.DataAnnotations.Schema" />
</ItemGroup>
</Project>

View File

@ -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<ClaimDto> AllClaimDtos = new List<ClaimDto>
{
ManageRecipes,
ViewRecipes,
ManageActivities,
ViewTasks,
ManageTasks,
@ -241,6 +260,9 @@ public static class ApplicationClaims
public static List<Claim> AllClaims = new List<Claim>
{
ManageRecipes.GetClaim,
ViewRecipes.GetClaim,
ManageStaffs.GetClaim,
ViewStaffs.GetClaim,
ManageReports.GetClaim,
@ -282,6 +304,9 @@ public static class ApplicationClaims
public static List<Claim> ManagerClaims = new List<Claim>
{
ManageRecipes.GetClaim,
ViewRecipes.GetClaim,
ManageStaffs.GetClaim,
ViewStaffs.GetClaim,
ManageReports.GetClaim,
@ -319,6 +344,8 @@ public static class ApplicationClaims
public static List<Claim> ViewerOwnerClaims = new List<Claim>
{
ViewRecipes.GetClaim,
ManageReports.GetClaim,
ViewStaffs.GetClaim,
@ -346,6 +373,9 @@ public static class ApplicationClaims
public static List<Claim> SuperVisorClaims = new List<Claim>
{
ManageRecipes.GetClaim,
ViewRecipes.GetClaim,
ManageActivities.GetClaim,
ChangeActivityStatus.GetClaim,
ViewMineActivities.GetClaim,
@ -369,6 +399,8 @@ public static class ApplicationClaims
public static List<Claim> StaffClaims = new List<Claim>
{
ViewRecipes.GetClaim,
ChangeActivityStatus.GetClaim,
ViewMineActivities.GetClaim,

View File

@ -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);

View File

@ -0,0 +1,9 @@
namespace Brizco.Common.Models.Entity;
public interface IMartenEntity
{
string CreatedBy { get; }
string ModifiedBy { get; }
DateTime CreatedAt { get; }
DateTime ModifiedAt { get; }
}

View File

@ -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();
}
}

View File

@ -31,7 +31,6 @@
<Using Include="Brizco.Common.Models.Claims" />
<Using Include="Brizco.Common.Models.Exception" />
<Using Include="Brizco.Core.Abstracts" />
<Using Include="Brizco.Core.BaseServices.Abstracts" />
<Using Include="Brizco.Core.CoreServices.Abstracts" />
<Using Include="Brizco.Core.CoreServices.ReportServices.Commands" />
<Using Include="Brizco.Core.EntityServices.Abstracts" />
@ -46,8 +45,11 @@
<Using Include="Brizco.Domain.Entities.User" />
<Using Include="Brizco.Domain.Enums" />
<Using Include="Brizco.Domain.Mappers" />
<Using Include="Brizco.Domain.MartenEntities.Brews" />
<Using Include="Brizco.Domain.Models.Settings" />
<Using Include="Brizco.Repository.Abstracts" />
<Using Include="Brizco.Repository.Repositories.Base.Contracts" />
<Using Include="Brizco.Repository.Repositories.Marten" />
<Using Include="Mapster" />
<Using Include="MediatR" />
<Using Include="Microsoft.AspNetCore.Identity" />
@ -57,6 +59,7 @@
<Using Include="NPOI.SS.Util" />
<Using Include="NPOI.XSSF.UserModel" />
<Using Include="System.Security.Claims" />
<Using Include="System.Text.Json" />
</ItemGroup>
</Project>

View File

@ -1,8 +1,8 @@
namespace Brizco.Core.BaseServices.Abstracts;
namespace Brizco.Core.CoreServices.Abstracts;
public interface IJwtService : IScopedDependency
{
Task<AccessToken<TUser>> Generate<TUser>(TUser user, Guid complexId,Guid roleId) where TUser : ApplicationUser;
Task<AccessToken<TUser>> Generate<TUser>(TUser user, Guid complexId, Guid roleId) where TUser : ApplicationUser;
Task<AccessToken<TUser>> Generate<TUser>(TUser user, Guid complexId) where TUser : ApplicationUser;
Task<AccessToken<TUser>> Generate<TUser>(TUser user) where TUser : ApplicationUser;

View File

@ -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<TUser>(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<AccessToken<TUserDto,TRole>> Generate<TUserDto, TUser, TRole>(TUser user, Guid complexId, Guid roleId) where TUser : ApplicationUser
public async Task<AccessToken<TUserDto, TRole>> Generate<TUserDto, TUser, TRole>(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<TUserDto, TUser, TRole>(user, claims);
@ -132,7 +124,7 @@ public class JwtService : IJwtService
return token;
}
private AccessToken<TUserDto,TRole> BaseGenerate<TUserDto, TUser, TRole>(TUser user, List<Claim> claims) where TUser : ApplicationUser
private AccessToken<TUserDto, TRole> BaseGenerate<TUserDto, TUser, TRole>(TUser user, List<Claim> 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<List<Claim>> GetClaims<TUser>(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<Claim>();
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<Claim>();
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));

View File

@ -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;

View File

@ -0,0 +1,8 @@
namespace Brizco.Core.EntityServices.Abstracts;
public interface IBrewService : IScopedDependency
{
public Task<object> GetLastBrewAsync(string recipeName, CancellationToken cancellationToken = default);
public Task<BaseRecipeLDto> GetBrewAsync(string recipeName , CancellationToken cancellationToken = default);
public Task AddBrewAsync(string recipeName,JsonDocument recipeObj, CancellationToken cancellationToken = default);
}

View File

@ -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<object> 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<BaseBrew>()
.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<BaseRecipeLDto> 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<BaseBrew>()
.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<object>();
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<BaseBrew>()
.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<BaseBrew>()
.AddOrUpdateEntityAsync(baseRecipe, cancellationToken);
}
}

View File

@ -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;

View File

@ -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;

View File

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

View File

@ -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<string> PastBrewsJson { get; set; } = new();
public Guid ComplexId { get; set; }
}

View File

@ -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<object> PastRecipes { get; set; } = new();
}

View File

@ -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; }
}

View File

@ -8,6 +8,7 @@
<ItemGroup>
<PackageReference Include="Refit" Version="7.0.0" />
<PackageReference Include="Marten" Version="7.8.0" />
</ItemGroup>
<ItemGroup>
@ -23,14 +24,17 @@
<ItemGroup>
<Using Include="Brizco.Common.Models" />
<Using Include="Brizco.Common.Models.Api" />
<Using Include="Brizco.Common.Models.Entity" />
<Using Include="Brizco.Common.Models.Exception" />
<Using Include="Brizco.Core.Abstracts" />
<Using Include="Brizco.Domain.Models.Settings" />
<Using Include="Brizco.Infrastructure.Models" />
<Using Include="Brizco.Infrastructure.RestServices" />
<Using Include="Brizco.Repository.Repositories.Marten" />
<Using Include="Microsoft.Extensions.Logging" />
<Using Include="Microsoft.Extensions.Options" />
<Using Include="Refit" />
<Using Include="System.Linq.Expressions" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,62 @@
using Marten;
namespace Brizco.Infrastructure.Marten;
public class MartenRepository<TMartenEntity> : IMartenRepository<TMartenEntity> where TMartenEntity : IMartenEntity
{
private readonly IDocumentStore _documentStore;
public MartenRepository(IDocumentStore documentStore)
{
_documentStore = documentStore;
}
public async Task<List<TMartenEntity>> GetEntitiesAsync(CancellationToken cancellation)
{
await using var session = _documentStore.QuerySession();
var entities = await session.Query<TMartenEntity>().ToListAsync(cancellation);
return entities.ToList();
}
public async Task<List<TMartenEntity>> GetEntitiesAsync(Expression<Func<TMartenEntity, bool>> expression, CancellationToken cancellation)
{
await using var session = _documentStore.QuerySession();
var entities = await session.Query<TMartenEntity>().Where(expression).ToListAsync(cancellation);
return entities.ToList();
}
public async Task<TMartenEntity> GetEntityAsync(Guid id, CancellationToken cancellation)
{
await using var session = _documentStore.QuerySession();
var setting = await session.LoadAsync<TMartenEntity>(id, cancellation);
if (setting == null)
throw new AppException($"{nameof(setting)} not found", ApiResultStatusCode.NotFound);
return setting;
}
public async Task<TMartenEntity?> GetEntityAsync(Expression<Func<TMartenEntity, bool>> expression, CancellationToken cancellation)
{
await using var session = _documentStore.QuerySession();
var entity = await session.Query<TMartenEntity>().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);
}
}

View File

@ -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<TMartenEntity> SetRepository<TMartenEntity>() where TMartenEntity : IMartenEntity
=> new MartenRepository<TMartenEntity>(_documentStore);
}

View File

@ -0,0 +1,15 @@
using System.Linq.Expressions;
namespace Brizco.Repository.Repositories.Marten;
public interface IMartenRepository<TMartenEntity> : IScopedDependency where TMartenEntity : IMartenEntity
{
Task<List<TMartenEntity>> GetEntitiesAsync(CancellationToken cancellation = default);
Task<List<TMartenEntity>> GetEntitiesAsync(Expression<Func<TMartenEntity, bool>> expression, CancellationToken cancellation = default);
Task<TMartenEntity> GetEntityAsync(Guid id, CancellationToken cancellation = default);
Task<TMartenEntity?> GetEntityAsync(Expression<Func<TMartenEntity, bool>> expression, CancellationToken cancellation = default);
Task AddOrUpdateEntityAsync(TMartenEntity entity, CancellationToken cancellation = default);
Task RemoveEntityAsync(TMartenEntity entity, CancellationToken cancellation = default);
}

View File

@ -0,0 +1,6 @@
namespace Brizco.Repository.Repositories.Marten;
public interface IMartenRepositoryWrapper : IScopedDependency
{
IMartenRepository<TMartenEntity> SetRepository<TMartenEntity>() where TMartenEntity : IMartenEntity;
}