feat : complex signup , unit of work , sms service

complete complex sign up , add new methods to unit of work , add sms service
release/production
Amir Hossein Khademi 2023-09-20 11:54:12 +03:30
parent 034b5270bb
commit 02abd6ddf3
62 changed files with 1392 additions and 256 deletions

View File

@ -59,6 +59,7 @@
<Using Include="Brizco.Common.Models.Mapper" />
<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.Repository.Repositories.Base.Contracts" />
<Using Include="Carter" />

View File

@ -0,0 +1,61 @@
using Brizco.Common.Models.Api;
using Brizco.Core.BaseServices;
using Brizco.Core.BaseServices.Abstracts;
using Microsoft.AspNetCore.Authorization.Infrastructure;
namespace Brizco.Api.Controllers;
public class AuthController : ICarterModule
{
public virtual void AddRoutes(IEndpointRouteBuilder app)
{
var group = app.NewVersionedApi("Auth")
.MapGroup($"api/auth");
group.MapPost("login/password", LoginWithPassword)
.WithDisplayName("LoginWithPassword")
.HasApiVersion(1.0);
group.MapPost("login/code", LoginWithVerifyCode)
.WithDisplayName("LoginWithVerifyCode")
.HasApiVersion(1.0);
group.MapGet("verifycode", GetVerifyCodeCode)
.WithDisplayName("GetVerifyCodeCode")
.HasApiVersion(1.0);
group.MapPut("forgetpassword", ForgetPassword)
.WithDisplayName("ForgetPassword")
.HasApiVersion(1.0);
group.MapPost("signup/complex", SignUpComplex)
.WithDisplayName("SignUp")
.RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser())
.HasApiVersion(1.0);
}
public async Task<IResult> SignUpComplex([FromBody] SignUpRequestDto request, IAccountService accountService, CancellationToken cancellationToken) =>
TypedResults.Ok(await accountService.CompleteComplexSignUpAsync(request,cancellationToken));
public async Task<IResult> LoginWithPassword([FromBody] LoginRequestDto loginRequestDto,IAccountService accountService, CancellationToken cancellationToken) =>
TypedResults.Ok(await accountService.LoginWithPasswordAsync(loginRequestDto.UserName, loginRequestDto.Password,cancellationToken));
public async Task<IResult> LoginWithVerifyCode([FromBody] LoginRequestDto loginRequestDto, IAccountService accountService, CancellationToken cancellationToken) =>
TypedResults.Ok(await accountService.LoginWithVerifyCodeAsync(loginRequestDto.UserName, loginRequestDto.VerifyCode,cancellationToken));
public async Task<IResult> GetVerifyCodeCode([FromQuery] string phoneNumber, IAccountService accountService) =>
TypedResults.Ok(await accountService.GetVerifyCodeAsync(phoneNumber));
public async Task<IResult> ForgetPassword([FromQuery] string phoneNumber, IAccountService accountService) =>
TypedResults.Ok(await accountService.ForgetPasswordAsync(phoneNumber));
public async Task<IResult> LoginSwagger([FromForm] TokenRequest tokenRequest, IAccountService accountService, CancellationToken cancellationToken)
=> TypedResults.Json(await accountService.LoginWithPasswordAsync(tokenRequest.username, tokenRequest.password,cancellationToken));
}

View File

@ -96,11 +96,14 @@ var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
app.UseCustomSwagger(siteSetting.BaseUrl);
//app.UseSwagger();
//app.UseSwaggerUI();
}
app.UseAuthorization();
app.UseAuthentication();
app.UseCors(x => x
.SetIsOriginAllowed(origin => true)
.AllowAnyMethod()
@ -109,7 +112,6 @@ app.UseCors(x => x
app.UseExceptionHandlerMiddleware();
app.UseCustomSwagger(siteSetting.BaseUrl);
app.MapCarter();
app.UseStaticFiles();
await app.InitialDb();

View File

@ -10,8 +10,26 @@
<ProjectReference Include="..\Brizco.Core\Brizco.Core.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Refit" Version="6.3.2" />
</ItemGroup>
<ItemGroup>
<Folder Include="Models\" />
<Folder Include="Models\RestApi\KaveNegar\" />
<Folder Include="Services\" />
</ItemGroup>
<ItemGroup>
<Using Include="Brizco.Common.Models" />
<Using Include="Brizco.Common.Models.Api" />
<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="Microsoft.Extensions.Logging" />
<Using Include="Microsoft.Extensions.Options" />
<Using Include="Refit" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,6 @@
namespace Brizco.Infrastructure.Models;
public static class RestAddress
{
public static string BaseKaveNegar { get => "https://api.kavenegar.com/v1/"; }
}

View File

@ -0,0 +1,7 @@
namespace Brizco.Infrastructure.Models.RestApi.KaveNegar;
public class KaveNegarResponse
{
public KaveNegarReturn Return { get; set; }
public KaveNegarResponseEntry[] entries { get; set; }
}

View File

@ -0,0 +1,13 @@
namespace Brizco.Infrastructure.Models.RestApi.KaveNegar;
public class KaveNegarResponseEntry
{
public int messageid { get; set; }
public string message { get; set; }
public int status { get; set; }
public string statustext { get; set; }
public string sender { get; set; }
public string receptor { get; set; }
public int date { get; set; }
public int cost { get; set; }
}

View File

@ -0,0 +1,7 @@
namespace Brizco.Infrastructure.Models.RestApi.KaveNegar;
public class KaveNegarReturn
{
public int status { get; set; }
public string message { get; set; }
}

View File

@ -0,0 +1,12 @@
using Brizco.Infrastructure.Models.RestApi.KaveNegar;
namespace Brizco.Infrastructure.RestServices;
public interface IKaveNegarRestApi
{
[Post("/{apiKey}/verify/lookup.json")]
Task<KaveNegarResponse> SendLookUp(string apiKey, [Query] string receptor, [Query] string token, [Query] string token2, [Query] string token10, [Query] string token20, [Query] string template);
[Post("/{apiKey}/sms/send.json")]
Task<KaveNegarResponse> SendSms(string apiKey, [Query] string receptor, [Query] string message, [Query] string sender);
}

View File

@ -0,0 +1,11 @@
namespace Brizco.Infrastructure.RestServices;
public interface IRestApiWrapper : IScopedDependency
{
IKaveNegarRestApi KaveNegarRestApi { get; }
}
public class RestApiWrapper : IRestApiWrapper
{
public IKaveNegarRestApi KaveNegarRestApi => RestService.For<IKaveNegarRestApi>(RestAddress.BaseKaveNegar);
}

View File

@ -0,0 +1,33 @@
namespace Brizco.Infrastructure.Services;
public class SmsService : ISmsService
{
private readonly IRestApiWrapper _restApiWrapper;
private readonly ILogger<SmsService> _logger;
private readonly SiteSettings _siteSettings;
public SmsService(IRestApiWrapper restApiWrapper,
IOptionsSnapshot<SiteSettings> optionsSnapshot,
ILogger<SmsService> logger)
{
_restApiWrapper = restApiWrapper;
_logger = logger;
_siteSettings = optionsSnapshot.Value;
}
public async Task SendForgerPasswordAsync(string phoneNumber, string newPassword)
{
var rest = await _restApiWrapper.KaveNegarRestApi.SendLookUp(_siteSettings.KaveNegarApiKey, phoneNumber, newPassword, null, null, null, "forgetPassword");
if (rest.Return.status != 200)
throw new BaseApiException(ApiResultStatusCode.SendSmsError, rest.Return.message);
}
public async Task SendVerifyCodeAsync(string phoneNumber, string verifyCode)
{
var rest = await _restApiWrapper.KaveNegarRestApi.SendLookUp(_siteSettings.KaveNegarApiKey, phoneNumber, verifyCode, null, null, null, "login");
if (rest.Return.status != 200)
throw new BaseApiException(ApiResultStatusCode.SendSmsError, rest.Return.message);
}
}

View File

@ -29,8 +29,6 @@
<ItemGroup>
<Folder Include="Models\" />
<Folder Include="Extensions\" />
<Folder Include="Repositories\Base\" />
<Folder Include="Repositories\UnitOfWork\" />
<Folder Include="Services\Contracts\" />
</ItemGroup>

View File

@ -17,48 +17,58 @@ public class CreateActivityCommandHandler : IRequestHandler<CreateActivityComman
throw new AppException("ComplexId is null", ApiResultStatusCode.NotFound);
if (!Guid.TryParse(_currentUserService.ComplexId, out Guid complexId))
throw new AppException("ComplexId is wrong", ApiResultStatusCode.NotFound);
var task = Domain.Entities.Task.Activity
.Create(
request.Status,
request.DoneAt,
request.PerformanceDescription,
request.Title,
request.Description,
request.Type,
request.IsRelatedToShift,
request.IsRelatedToRole,
request.IsRelatedToPerson,
request.IsDisposable,
request.SetFor,
request.HasDisposed,
request.Amount,
request.AmountType,
complexId);
if (task.IsRelatedToPerson)
try
{
if (request.Users.Count == 0)
throw new AppException("اگر فعالیت برای یک فرد انتخاب شده باشد باید لیست افراد را ارسال نمایید");
task.AddUser(request.Users.ToArray());
}
await _repositoryWrapper.BeginTransaction(cancellationToken);
var task = Domain.Entities.Task.Activity
.Create(
request.Status,
request.DoneAt,
request.PerformanceDescription,
request.Title,
request.Description,
request.Type,
request.IsRelatedToShift,
request.IsRelatedToRole,
request.IsRelatedToPerson,
request.IsDisposable,
request.SetFor,
request.HasDisposed,
request.Amount,
request.AmountType,
complexId);
if (task.IsRelatedToRole)
if (task.IsRelatedToPerson)
{
if (request.Users.Count == 0)
throw new AppException("اگر فعالیت برای یک فرد انتخاب شده باشد باید لیست افراد را ارسال نمایید");
task.AddUser(request.Users.ToArray());
}
if (task.IsRelatedToRole)
{
if (request.Roles.Count == 0)
throw new AppException(
"اگر فعالیت برای یک گروه نقش انتخاب شده باشد باید لیست نقش ها را ارسال نمایید");
task.AddShift(request.Roles.ToArray());
}
if (task.IsRelatedToShift)
{
if (request.Shifts.Count == 0)
throw new AppException("اگر فعالیت برای یک شیفت انتخاب شده باشد باید لیست شیفت ها را ارسال نمایید");
task.AddRole(request.Shifts.ToArray());
}
_repositoryWrapper.SetRepository<Domain.Entities.Task.Activity>().Add(task);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
await _repositoryWrapper.CommitAsync(cancellationToken);
return task.AdaptToLDto();
}
catch (Exception)
{
if (request.Roles.Count == 0)
throw new AppException("اگر فعالیت برای یک گروه نقش انتخاب شده باشد باید لیست نقش ها را ارسال نمایید");
task.AddShift(request.Roles.ToArray());
await _repositoryWrapper.RollBackAsync(cancellationToken);
throw;
}
if (task.IsRelatedToShift)
{
if (request.Shifts.Count == 0)
throw new AppException("اگر فعالیت برای یک شیفت انتخاب شده باشد باید لیست شیفت ها را ارسال نمایید");
task.AddRole(request.Shifts.ToArray());
}
_repositoryWrapper.SetRepository<Domain.Entities.Task.Activity>().Add(task);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
return task.AdaptToLDto();
}
}

View File

@ -10,15 +10,25 @@ public class DeleteActivityCommandHandler : IRequestHandler<DeleteActivityComman
}
public async Task<bool> Handle(DeleteActivityCommand request, CancellationToken cancellationToken)
{
var task = await _repositoryWrapper.SetRepository<Domain.Entities.Task.Activity>()
.TableNoTracking
.FirstOrDefaultAsync(s => s.Id == request.Id, cancellationToken);
if (task == null)
throw new AppException("Task not found", ApiResultStatusCode.NotFound);
_repositoryWrapper.SetRepository<Domain.Entities.Task.Activity>()
.Delete(task);
try
{
await _repositoryWrapper.BeginTransaction(cancellationToken);
var task = await _repositoryWrapper.SetRepository<Domain.Entities.Task.Activity>()
.TableNoTracking
.FirstOrDefaultAsync(s => s.Id == request.Id, cancellationToken);
if (task == null)
throw new AppException("Task not found", ApiResultStatusCode.NotFound);
_repositoryWrapper.SetRepository<Domain.Entities.Task.Activity>()
.Delete(task);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
return true;
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
await _repositoryWrapper.CommitAsync(cancellationToken);
return true;
}
catch (Exception )
{
await _repositoryWrapper.RollBackAsync(cancellationToken);
throw;
}
}
}

View File

@ -12,7 +12,7 @@ public class GetActivitiesQueryHandler : IRequestHandler<GetActivitiesQuery, Lis
{
var tasks = await _repositoryWrapper.SetRepository<Domain.Entities.Task.Activity>().TableNoTracking
.OrderByDescending(s => s.CreatedAt)
.Skip(request.page * 15).Take(15)
.Skip(request.Page * 15).Take(15)
.Select(ActivityMapper.ProjectToSDto)
.ToListAsync(cancellationToken);

View File

@ -15,7 +15,7 @@ public class GetActivityQueryHandler : IRequestHandler<GetActivityQuery, Activit
{
var task = await _repositoryWrapper.SetRepository<Domain.Entities.Task.Activity>()
.TableNoTracking
.Where(s => s.Id == request.id)
.Where(s => s.Id == request.Id)
.Select(ActivityMapper.ProjectToLDto)
.FirstOrDefaultAsync(cancellationToken);
if (task == null)

View File

@ -22,29 +22,39 @@ public class UpdateActivityCommandHandler : IRequestHandler<UpdateActivityComman
if (!Guid.TryParse(_currentUserService.ComplexId,out Guid complexId))
throw new AppException("ComplexId is wrong", ApiResultStatusCode.NotFound);
var newTask = Domain.Entities.Task.Activity.Create(
request.Status,
request.DoneAt,
request.PerformanceDescription,
request.Title,
request.Description,
request.Type,
request.IsRelatedToShift,
request.IsRelatedToRole,
request.IsRelatedToPerson,
request.IsDisposable,
request.SetFor,
request.HasDisposed,
request.Amount,
request.AmountType,
complexId);
try
{
await _repositoryWrapper.BeginTransaction(cancellationToken);
var newTask = Domain.Entities.Task.Activity.Create(
request.Status,
request.DoneAt,
request.PerformanceDescription,
request.Title,
request.Description,
request.Type,
request.IsRelatedToShift,
request.IsRelatedToRole,
request.IsRelatedToPerson,
request.IsDisposable,
request.SetFor,
request.HasDisposed,
request.Amount,
request.AmountType,
complexId);
newTask.Id = request.Id;
newTask.Id = request.Id;
_repositoryWrapper.SetRepository<Domain.Entities.Task.Activity>()
.Update(newTask);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
_repositoryWrapper.SetRepository<Domain.Entities.Task.Activity>()
.Update(newTask);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
await _repositoryWrapper.CommitAsync(cancellationToken);
return true;
return true;
}
catch (Exception )
{
await _repositoryWrapper.RollBackAsync(cancellationToken);
throw;
}
}
}

View File

@ -13,9 +13,19 @@ public class CreateComplexCommandHandler : IRequestHandler<CreateComplexCommand,
public async Task<ComplexSDto> Handle(CreateComplexCommand request, CancellationToken cancellationToken)
{
var complex = Domain.Entities.Complex.Complex.Create(request.Name, request.Address, request.SupportPhone);
_repositoryWrapper.SetRepository<Domain.Entities.Complex.Complex>().Add(complex);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
return complex.AdaptToSDto();
try
{
await _repositoryWrapper.BeginTransaction(cancellationToken);
var complex = Domain.Entities.Complex.Complex.Create(request.Name, request.Address, request.SupportPhone);
_repositoryWrapper.SetRepository<Domain.Entities.Complex.Complex>().Add(complex);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
await _repositoryWrapper.CommitAsync(cancellationToken);
return complex.AdaptToSDto();
}
catch (Exception)
{
await _repositoryWrapper.RollBackAsync(cancellationToken);
throw;
}
}
}

View File

@ -0,0 +1,51 @@
using Brizco.Domain.Entities.User;
using Microsoft.AspNetCore.Identity;
namespace Brizco.Repository.Handlers.Complex;
public class CreateComplexUserCommandHandler : IRequestHandler<CreateComplexUserCommand, ComplexUserSDto>
{
private readonly IRepositoryWrapper _repositoryWrapper;
private readonly UserManager<ApplicationUser> _userManager;
private readonly RoleManager<ApplicationRole> _roleManager;
private readonly ILogger<CreateComplexUserCommandHandler> _logger;
public CreateComplexUserCommandHandler(IRepositoryWrapper repositoryWrapper,
UserManager<ApplicationUser> userManager,
RoleManager<ApplicationRole> roleManager,
ILogger<CreateComplexUserCommandHandler> logger)
{
_repositoryWrapper = repositoryWrapper;
_userManager = userManager;
_roleManager = roleManager;
_logger = logger;
}
public async Task<ComplexUserSDto> Handle(CreateComplexUserCommand request, CancellationToken cancellationToken)
{
try
{
await _repositoryWrapper.BeginTransaction(cancellationToken);
var complex = await _repositoryWrapper.SetRepository<Domain.Entities.Complex.Complex>().TableNoTracking
.FirstOrDefaultAsync(c => c.Id == request.ComplexId, cancellationToken);
if (complex == null)
throw new AppException("Complex not found", ApiResultStatusCode.NotFound);
var complexUser = complex.AddComplexUser(request.UserId, request.RoleId);
_repositoryWrapper.SetRepository<Domain.Entities.Complex.Complex>().Update(complex);
var role = await _roleManager.FindByIdAsync(request.RoleId.ToString());
var user = await _userManager.FindByIdAsync(request.UserId.ToString());
var result = await _userManager.AddToRoleAsync(user, role.Name);
if (!result.Succeeded)
throw new AppException(string.Join('|', result.Errors));
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
await _repositoryWrapper.CommitAsync(cancellationToken);
return complexUser.AdaptToSDto();
}
catch (Exception)
{
await _repositoryWrapper.RollBackAsync(cancellationToken);
throw;
}
}
}

View File

@ -10,15 +10,25 @@ public class DeleteComplexCommandHandler : IRequestHandler<DeleteComplexCommand,
}
public async Task<bool> Handle(DeleteComplexCommand request, CancellationToken cancellationToken)
{
var task = await _repositoryWrapper.SetRepository<Domain.Entities.Complex.Complex>()
.TableNoTracking
.FirstOrDefaultAsync(s => s.Id == request.Id, cancellationToken);
if (task == null)
throw new AppException("Task not found", ApiResultStatusCode.NotFound);
_repositoryWrapper.SetRepository<Domain.Entities.Complex.Complex>()
.Delete(task);
try
{
await _repositoryWrapper.BeginTransaction(cancellationToken);
var task = await _repositoryWrapper.SetRepository<Domain.Entities.Complex.Complex>()
.TableNoTracking
.FirstOrDefaultAsync(s => s.Id == request.Id, cancellationToken);
if (task == null)
throw new AppException("Task not found", ApiResultStatusCode.NotFound);
_repositoryWrapper.SetRepository<Domain.Entities.Complex.Complex>()
.Delete(task);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
return true;
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
await _repositoryWrapper.CommitAsync(cancellationToken);
return true;
}
catch (Exception)
{
await _repositoryWrapper.RollBackAsync(cancellationToken);
throw;
}
}
}

View File

@ -0,0 +1,36 @@
using Brizco.Domain.Entities.Complex;
namespace Brizco.Repository.Handlers.Complex;
public class DeleteComplexUserCommandHandler : IRequestHandler<DeleteComplexUserCommand, bool>
{
private readonly IRepositoryWrapper _repositoryWrapper;
public DeleteComplexUserCommandHandler(IRepositoryWrapper repositoryWrapper)
{
_repositoryWrapper = repositoryWrapper;
}
public async Task<bool> Handle(DeleteComplexUserCommand request, CancellationToken cancellationToken)
{
try
{
await _repositoryWrapper.BeginTransaction(cancellationToken);
var complexUser = await _repositoryWrapper.SetRepository<ComplexUser>()
.TableNoTracking
.FirstOrDefaultAsync(c => c.Id == request.ComplexUserId, cancellationToken);
if (complexUser == null)
throw new AppException("ComplexUser not found", ApiResultStatusCode.NotFound);
_repositoryWrapper.SetRepository<ComplexUser>().Delete(complexUser);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
await _repositoryWrapper.CommitAsync(cancellationToken);
return true;
}
catch (Exception)
{
await _repositoryWrapper.RollBackAsync(cancellationToken);
throw;
}
}
}

View File

@ -14,7 +14,7 @@ public class GetComplexQueryHandler : IRequestHandler<GetComplexQuery, ComplexSD
var complex = await _repositoryWrapper.SetRepository<Domain.Entities.Complex.Complex>()
.TableNoTracking
.Where(s => s.Id == request.Id)
.Select(ComplexMapper.ProjectToLDto)
.Select(ComplexMapper.ProjectToSDto)
.FirstOrDefaultAsync(cancellationToken);
if (complex == null)
throw new AppException("Complex not found", ApiResultStatusCode.NotFound);

View File

@ -8,7 +8,7 @@ public class GetComplexesQueryHandler : IRequestHandler<GetComplexesQuery, List<
{
_repositoryWrapper = repositoryWrapper;
}
public async Task<List<ActivitySDto>> Handle(GetComplexesQuery request, CancellationToken cancellationToken)
public async Task<List<ComplexSDto>> Handle(GetComplexesQuery request, CancellationToken cancellationToken)
{
var tasks = await _repositoryWrapper.SetRepository<Domain.Entities.Complex.Complex>().TableNoTracking
.OrderByDescending(s => s.CreatedAt)

View File

@ -1,50 +0,0 @@
namespace Brizco.Repository.Handlers.Complex;
public class UpdateActivityCommandHandler : IRequestHandler<UpdateActivityCommand, bool>
{
private readonly IRepositoryWrapper _repositoryWrapper;
private readonly ICurrentUserService _currentUserService;
public UpdateActivityCommandHandler(IRepositoryWrapper repositoryWrapper,ICurrentUserService currentUserService)
{
_repositoryWrapper = repositoryWrapper;
_currentUserService = currentUserService;
}
public async Task<bool> Handle(UpdateActivityCommand request, CancellationToken cancellationToken)
{
var task = await _repositoryWrapper.SetRepository<Domain.Entities.Task.Activity>()
.TableNoTracking.FirstOrDefaultAsync(s => s.Id == request.Id,cancellationToken);
if (task == null)
throw new AppException("Task not found", ApiResultStatusCode.NotFound);
if (_currentUserService.ComplexId == null)
throw new AppException("ComplexId is null", ApiResultStatusCode.NotFound);
if (!Guid.TryParse(_currentUserService.ComplexId,out Guid complexId))
throw new AppException("ComplexId is wrong", ApiResultStatusCode.NotFound);
var newTask = Domain.Entities.Task.Activity.Create(
request.Status,
request.DoneAt,
request.PerformanceDescription,
request.Title,
request.Description,
request.Type,
request.IsRelatedToShift,
request.IsRelatedToRole,
request.IsRelatedToPerson,
request.IsDisposable,
request.SetFor,
request.HasDisposed,
request.Amount,
request.AmountType,
complexId);
newTask.Id = request.Id;
_repositoryWrapper.SetRepository<Domain.Entities.Task.Activity>()
.Update(newTask);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
return true;
}
}

View File

@ -18,17 +18,27 @@ public class CreateShiftCommandHandler : IRequestHandler<CreateShiftCommand, Dom
if (!Guid.TryParse(_currentUserService.ComplexId, out Guid complexId))
throw new AppException("ComplexId is wrong", ApiResultStatusCode.NotFound);
var shift = Domain.Entities.Shift.Shift
.Create(request.Title,
request.Description,
request.StartAt,
request.EndAt,
complexId);
try
{
await _repositoryWrapper.BeginTransaction(cancellationToken);
var shift = Domain.Entities.Shift.Shift
.Create(request.Title,
request.Description,
request.StartAt,
request.EndAt,
complexId);
request.DayOfWeeks.ForEach(d => shift.SetDay(d));
request.DayOfWeeks.ForEach(d => shift.SetDay(d));
_repositoryWrapper.SetRepository<Domain.Entities.Shift.Shift>().Add(shift);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
return shift;
_repositoryWrapper.SetRepository<Domain.Entities.Shift.Shift>().Add(shift);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
await _repositoryWrapper.CommitAsync(cancellationToken);
return shift;
}
catch (Exception )
{
await _repositoryWrapper.RollBackAsync(cancellationToken);
throw;
}
}
}

View File

@ -12,7 +12,7 @@ public class DeleteShiftCommandHandler : IRequestHandler<DeleteShiftCommand, boo
{
var shift = await _repositoryWrapper.SetRepository<Domain.Entities.Shift.Shift>()
.TableNoTracking
.FirstOrDefaultAsync(s => s.Id == request.id, cancellationToken);
.FirstOrDefaultAsync(s => s.Id == request.Id, cancellationToken);
if (shift == null)
throw new AppException("Shift not found", ApiResultStatusCode.NotFound);
_repositoryWrapper.SetRepository<Domain.Entities.Shift.Shift>()

View File

@ -14,7 +14,7 @@ public class UpdateShiftCommandHandler : IRequestHandler<UpdateShiftCommand, boo
public async Task<bool> Handle(UpdateShiftCommand request, CancellationToken cancellationToken)
{
var shift = await _repositoryWrapper.SetRepository<Domain.Entities.Shift.Shift>()
.TableNoTracking.FirstOrDefaultAsync(s => s.Id == request.id);
.TableNoTracking.FirstOrDefaultAsync(s => s.Id == request.Id);
if (shift == null)
throw new AppException("Shift not found", ApiResultStatusCode.NotFound);
@ -28,7 +28,7 @@ public class UpdateShiftCommandHandler : IRequestHandler<UpdateShiftCommand, boo
request.StartAt,
request.EndAt,
complexId);
newShift.Id = request.id;
newShift.Id = request.Id;
_repositoryWrapper.SetRepository<Domain.Entities.Shift.Shift>()
.Update(newShift);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);

View File

@ -16,15 +16,26 @@ public class CreateShiftPlanCommandHandler : IRequestHandler<CreateShiftPlanComm
if (shift == null)
throw new AppException("Shift not found", ApiResultStatusCode.NotFound);
var shiftPlan = shift.AddPlan(request.StartAt, request.EndAt);
try
{
await _repositoryWrapper.BeginTransaction(cancellationToken);
var shiftPlan = shift.AddPlan(request.StartAt, request.EndAt);
if (request.UserIds.Count == 0)
throw new AppException("شیفت بندی مورد نظر باید حداقل متشکل از یک فرد باشد", ApiResultStatusCode.BadRequest);
if (request.UserIds.Count == 0)
throw new AppException("شیفت بندی مورد نظر باید حداقل متشکل از یک فرد باشد",
ApiResultStatusCode.BadRequest);
request.UserIds.ForEach(i=>shiftPlan.AddUser(i));
request.UserIds.ForEach(i => shiftPlan.AddUser(i));
_repositoryWrapper.SetRepository<Domain.Entities.Shift.ShiftPlan>().Add(shiftPlan);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
return shiftPlan.AdaptToLDto();
_repositoryWrapper.SetRepository<Domain.Entities.Shift.ShiftPlan>().Add(shiftPlan);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
await _repositoryWrapper.CommitAsync(cancellationToken);
return shiftPlan.AdaptToLDto();
}
catch (Exception )
{
await _repositoryWrapper.RollBackAsync(cancellationToken);
throw;
}
}
}

View File

@ -12,7 +12,7 @@ public class DeleteActivityCommandHandler : IRequestHandler<DeleteTaskCommand, b
{
var task = await _repositoryWrapper.SetRepository<Domain.Entities.Task.Task>()
.TableNoTracking
.FirstOrDefaultAsync(s => s.Id == request.id, cancellationToken);
.FirstOrDefaultAsync(s => s.Id == request.Id, cancellationToken);
if (task == null)
throw new AppException("Task not found", ApiResultStatusCode.NotFound);
_repositoryWrapper.SetRepository<Domain.Entities.Task.Task>()

View File

@ -15,7 +15,7 @@ public class GetActivityQueryHandler : IRequestHandler<GetTaskQuery, TaskLDto>
{
var task = await _repositoryWrapper.SetRepository<Domain.Entities.Task.Task>()
.TableNoTracking
.Where(s => s.Id == request.id)
.Where(s => s.Id == request.Id)
.Select(TaskMapper.ProjectToLDto)
.FirstOrDefaultAsync(cancellationToken);
if (task == null)

View File

@ -12,7 +12,7 @@ public class GetActivitiesQueryHandler : IRequestHandler<GetTasksQuery, List<Tas
{
var tasks = await _repositoryWrapper.SetRepository<Domain.Entities.Task.Task>().TableNoTracking
.OrderByDescending(s => s.CreatedAt)
.Skip(request.page * 15).Take(15)
.Skip(request.Page * 15).Take(15)
.Select(TaskMapper.ProjectToSDto)
.ToListAsync(cancellationToken);

View File

@ -14,7 +14,7 @@ public class UpdateActivityCommandHandler : IRequestHandler<UpdateTaskCommand, b
public async Task<bool> Handle(UpdateTaskCommand request, CancellationToken cancellationToken)
{
var task = await _repositoryWrapper.SetRepository<Domain.Entities.Task.Task>()
.TableNoTracking.FirstOrDefaultAsync(s => s.Id == request.id,cancellationToken);
.TableNoTracking.FirstOrDefaultAsync(s => s.Id == request.Id,cancellationToken);
if (task == null)
throw new AppException("Task not found", ApiResultStatusCode.NotFound);
@ -35,7 +35,7 @@ public class UpdateActivityCommandHandler : IRequestHandler<UpdateTaskCommand, b
request.Amount,
request.AmountType,
complexId);
newTask.Id = request.id;
newTask.Id = request.Id;
_repositoryWrapper.SetRepository<Domain.Entities.Task.Task>()
.Update(newTask);

View File

@ -12,7 +12,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace Brizco.Repository.Migrations
{
[DbContext(typeof(ApplicationContext))]
[Migration("20230918112118_Init")]
[Migration("20230919130824_Init")]
partial class Init
{
/// <inheritdoc />
@ -106,6 +106,9 @@ namespace Brizco.Repository.Migrations
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("RoleId")
.HasColumnType("uuid");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
@ -113,6 +116,8 @@ namespace Brizco.Repository.Migrations
b.HasIndex("ComplexId");
b.HasIndex("RoleId");
b.HasIndex("UserId");
b.ToTable("ComplexUsers", "public");
@ -541,6 +546,10 @@ namespace Brizco.Repository.Migrations
.IsRequired()
.HasColumnType("text");
b.Property<string>("EnglishName")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
@ -549,6 +558,10 @@ namespace Brizco.Repository.Migrations
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("PersianName")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("ComplexId");
@ -620,6 +633,9 @@ namespace Brizco.Repository.Migrations
b.Property<string>("SecurityStamp")
.HasColumnType("text");
b.Property<int>("SignUpStatus")
.HasColumnType("integer");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("boolean");
@ -770,6 +786,12 @@ namespace Brizco.Repository.Migrations
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("Brizco.Domain.Entities.User.ApplicationRole", "Role")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("Brizco.Domain.Entities.User.ApplicationUser", "User")
.WithMany()
.HasForeignKey("UserId")
@ -778,6 +800,8 @@ namespace Brizco.Repository.Migrations
b.Navigation("Complex");
b.Navigation("Role");
b.Navigation("User");
});

View File

@ -47,6 +47,7 @@ namespace Brizco.Repository.Migrations
LastName = table.Column<string>(type: "text", nullable: false),
BirthDate = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
Gender = table.Column<int>(type: "integer", nullable: false),
SignUpStatus = table.Column<int>(type: "integer", nullable: false),
UserName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
NormalizedUserName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
Email = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
@ -74,6 +75,8 @@ namespace Brizco.Repository.Migrations
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Description = table.Column<string>(type: "text", nullable: false),
EnglishName = table.Column<string>(type: "text", nullable: false),
PersianName = table.Column<string>(type: "text", nullable: false),
ComplexId = table.Column<Guid>(type: "uuid", nullable: true),
Name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
NormalizedName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
@ -187,41 +190,6 @@ namespace Brizco.Repository.Migrations
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "ComplexUsers",
schema: "public",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
UserId = table.Column<Guid>(type: "uuid", nullable: false),
ComplexId = table.Column<Guid>(type: "uuid", nullable: false),
RemovedAt = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
CreatedAt = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
CreatedBy = table.Column<string>(type: "text", nullable: false),
IsRemoved = table.Column<bool>(type: "boolean", nullable: false),
RemovedBy = table.Column<string>(type: "text", nullable: false),
ModifiedAt = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
ModifiedBy = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ComplexUsers", x => x.Id);
table.ForeignKey(
name: "FK_ComplexUsers_Complexes_ComplexId",
column: x => x.ComplexId,
principalSchema: "public",
principalTable: "Complexes",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_ComplexUsers_Users_UserId",
column: x => x.UserId,
principalSchema: "public",
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "Logins",
schema: "public",
@ -266,6 +234,49 @@ namespace Brizco.Repository.Migrations
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "ComplexUsers",
schema: "public",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
UserId = table.Column<Guid>(type: "uuid", nullable: false),
ComplexId = table.Column<Guid>(type: "uuid", nullable: false),
RoleId = table.Column<Guid>(type: "uuid", nullable: false),
RemovedAt = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
CreatedAt = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
CreatedBy = table.Column<string>(type: "text", nullable: false),
IsRemoved = table.Column<bool>(type: "boolean", nullable: false),
RemovedBy = table.Column<string>(type: "text", nullable: false),
ModifiedAt = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
ModifiedBy = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ComplexUsers", x => x.Id);
table.ForeignKey(
name: "FK_ComplexUsers_Complexes_ComplexId",
column: x => x.ComplexId,
principalSchema: "public",
principalTable: "Complexes",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_ComplexUsers_Roles_RoleId",
column: x => x.RoleId,
principalSchema: "public",
principalTable: "Roles",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_ComplexUsers_Users_UserId",
column: x => x.UserId,
principalSchema: "public",
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "RoleClaims",
schema: "public",
@ -525,6 +536,12 @@ namespace Brizco.Repository.Migrations
table: "ComplexUsers",
column: "ComplexId");
migrationBuilder.CreateIndex(
name: "IX_ComplexUsers_RoleId",
schema: "public",
table: "ComplexUsers",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "IX_ComplexUsers_UserId",
schema: "public",

View File

@ -103,6 +103,9 @@ namespace Brizco.Repository.Migrations
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("RoleId")
.HasColumnType("uuid");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
@ -110,6 +113,8 @@ namespace Brizco.Repository.Migrations
b.HasIndex("ComplexId");
b.HasIndex("RoleId");
b.HasIndex("UserId");
b.ToTable("ComplexUsers", "public");
@ -538,6 +543,10 @@ namespace Brizco.Repository.Migrations
.IsRequired()
.HasColumnType("text");
b.Property<string>("EnglishName")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
@ -546,6 +555,10 @@ namespace Brizco.Repository.Migrations
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("PersianName")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("ComplexId");
@ -617,6 +630,9 @@ namespace Brizco.Repository.Migrations
b.Property<string>("SecurityStamp")
.HasColumnType("text");
b.Property<int>("SignUpStatus")
.HasColumnType("integer");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("boolean");
@ -767,6 +783,12 @@ namespace Brizco.Repository.Migrations
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("Brizco.Domain.Entities.User.ApplicationRole", "Role")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("Brizco.Domain.Entities.User.ApplicationUser", "User")
.WithMany()
.HasForeignKey("UserId")
@ -775,6 +797,8 @@ namespace Brizco.Repository.Migrations
b.Navigation("Complex");
b.Navigation("Role");
b.Navigation("User");
});

View File

@ -3,6 +3,9 @@
public interface IRepositoryWrapper : IDisposable , IScopedDependency
{
IBaseRepository<T> SetRepository<T>() where T : ApiEntity;
System.Threading.Tasks.Task SaveChangesAsync(CancellationToken cancellationToken = default);
Task BeginTransaction(CancellationToken cancellationToken);
Task RollBackAsync(CancellationToken cancellationToken);
Task CommitAsync(CancellationToken cancellationToken);
Task SaveChangesAsync(CancellationToken cancellationToken);
}
}

View File

@ -1,22 +1,71 @@
using Brizco.Repository.Repositories.UnitOfWork;
using Brizco.Repository.Models;
using Brizco.Repository.Repositories.UnitOfWork;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Storage;
namespace Brizco.Repository.Repositories.Base;
public class RepositoryWrapper : IRepositoryWrapper
{
private readonly ApplicationContext _context;
private readonly IUnitOfWork _unitOfWork;
private IDbContextTransaction? _currentTransaction;
public RepositoryWrapper(ApplicationContext context)
{
_context = context;
_unitOfWork = new UnitOfWork.UnitOfWork(_context);
}
public IBaseRepository<T> SetRepository<T>() where T : ApiEntity => new BaseRepository<T>(_context);
public async System.Threading.Tasks.Task SaveChangesAsync(CancellationToken cancellationToken = default) => await _unitOfWork.SaveChangesAsync(cancellationToken);
public async Task RollBackAsync(CancellationToken cancellationToken)
{
if (_currentTransaction == null)
throw new ArgumentNullException(nameof(_currentTransaction));
await _currentTransaction.RollbackAsync(cancellationToken);
}
public async Task CommitAsync(CancellationToken cancellationToken)
{
if (_currentTransaction == null)
throw new ArgumentNullException(nameof(_currentTransaction));
await _currentTransaction.CommitAsync(cancellationToken);
}
public async Task BeginTransaction()
{
_currentTransaction = await _context.Database.BeginTransactionAsync();
}
public async Task SaveChangesAsync(CancellationToken cancellationToken = default)
{
SetAuditables();
await _context.SaveChangesAsync(cancellationToken);
}
private void SetAuditables()
{
IEnumerable<EntityEntry<IApiEntity>> entries = _context.ChangeTracker.Entries<IApiEntity>();
foreach (EntityEntry<IApiEntity> entity in entries)
{
if (entity.State == EntityState.Added)
{
entity.Property(e => e.CreatedAt)
.CurrentValue = DateTime.Now;
}
if (entity.State == EntityState.Modified)
{
entity.Property(e => e.ModifiedAt)
.CurrentValue = DateTime.Now;
}
if (entity.State == EntityState.Deleted)
{
entity.Property(e => e.RemovedAt)
.CurrentValue = DateTime.Now;
entity.Property(e => e.IsRemoved)
.CurrentValue = true;
}
}
}
public void Dispose()
{
_currentTransaction?.Dispose();
_context?.Dispose();
}
}

View File

@ -2,5 +2,8 @@
public interface IUnitOfWork : IScopedDependency
{
System.Threading.Tasks.Task SaveChangesAsync(CancellationToken cancellationToken = default);
Task BeginTransaction();
Task RollBackAsync();
Task CommitAsync();
Task SaveChangesAsync(CancellationToken cancellationToken = default);
}

View File

@ -1,4 +1,5 @@
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Storage;
using Task = System.Threading.Tasks.Task;
namespace Brizco.Repository.Repositories.UnitOfWork;
@ -6,12 +7,28 @@ namespace Brizco.Repository.Repositories.UnitOfWork;
public class UnitOfWork : IUnitOfWork
{
private readonly ApplicationContext _applicationContext;
private IDbContextTransaction? _currentTransaction ;
public UnitOfWork(ApplicationContext applicationContext)
{
_applicationContext = applicationContext;
}
public async Task RollBackAsync()
{
if (_currentTransaction == null)
throw new ArgumentNullException(nameof(_currentTransaction));
await _currentTransaction.RollbackAsync();
}
public async Task CommitAsync()
{
if (_currentTransaction == null)
throw new ArgumentNullException(nameof(_currentTransaction));
await _currentTransaction.CommitAsync();
}
public async Task BeginTransaction()
{
_currentTransaction = await _applicationContext.Database.BeginTransactionAsync();
}
public async Task SaveChangesAsync(CancellationToken cancellationToken = default)
{
SetAuditables();

View File

@ -82,6 +82,7 @@ public class DbInitializerService : IDbInitializerService
managerRole = new ApplicationRole
{
Name = seedAdmin.RoleName,
EnglishName = seedAdmin.RoleName,
Description = "root admin role"
};
var adminRoleResult = await _roleManager.CreateAsync(managerRole);

View File

@ -3,17 +3,88 @@
namespace Brizco.Common.Models.Claims;
public static class ApplicationClaims
{
public static ClaimDto ManageProducts { get; } = new ClaimDto
public static ClaimDto ManageComplexes { get; } = new ClaimDto
{
Type = CustomClaimType.Permission,
Value = ApplicationPermission.ManageProducts,
Title = "دسترسی کامل به محصولات",
Detail = "دسترسی به افزودن و مدیریت محصولات فروشگاه شما"
Value = ApplicationPermission.ManageComplexes,
Title = "دسترسی کامل به مجموعه ها",
Detail = "دسترسی به افزودن و مدیریت مجموعه های سیستم"
};
public static ClaimDto ViewComplexes { get; } = new ClaimDto
{
Type = CustomClaimType.Permission,
Value = ApplicationPermission.ViewComplexes,
Title = "مشاهده مجموعه ها",
Detail = "دسترسی به مشاهده مجموعه ها"
};
public static ClaimDto ManageShifts { get; } = new ClaimDto
{
Type = CustomClaimType.Permission,
Value = ApplicationPermission.ManageShifts,
Title = "دسترسی کامل به شیفت ها",
Detail = "دسترسی به افزودن و مدیریت شیفت ها فروشگاه شما"
};
public static ClaimDto ViewShifts { get; } = new ClaimDto
{
Type = CustomClaimType.Permission,
Value = ApplicationPermission.ViewShifts,
Title = "دسترسی مشاهده به شیفت ها",
Detail = "قابلیت مشاهده شیفت های مجموعه"
};
public static ClaimDto ManageShiftPlans { get; } = new ClaimDto
{
Type = CustomClaimType.Permission,
Value = ApplicationPermission.ManageShiftPlans,
Title = "دسترسی کامل به شیفت بندی ها",
Detail = "دسترسی به افزودن و مدیریت شیفت بندی فروشگاه شما"
};
public static ClaimDto ManageTasks { get; } = new ClaimDto
{
Type = CustomClaimType.Permission,
Value = ApplicationPermission.ManageTasks,
Title = "دسترسی کامل به وظایف",
Detail = "دسترسی به افزودن و مدیریت وظایف فروشگاه شما"
};
public static ClaimDto ViewTasks { get; } = new ClaimDto
{
Type = CustomClaimType.Permission,
Value = ApplicationPermission.ViewTasks,
Title = "دسترسی مشاهده وظایف",
Detail = "دسترسی مشاهده وظایف مجموعه شما"
};
public static ClaimDto ManageActivities { get; } = new ClaimDto
{
Type = CustomClaimType.Permission,
Value = ApplicationPermission.ManageActivities,
Title = "دسترسی کامل به فعالیت ها",
Detail = "دسترسی به افزودن و مدیریت فعالیت ها فروشگاه شما"
};
public static List<Claim> AllClaims = new List<Claim>
{
ManageProducts.GetClaim
ManageActivities.GetClaim,
ViewTasks.GetClaim,
ManageTasks.GetClaim,
ManageShiftPlans.GetClaim,
ViewShifts.GetClaim,
ManageShifts.GetClaim,
ViewComplexes.GetClaim,
ManageComplexes.GetClaim,
};
public static List<Claim> ManagerClaims = new List<Claim>
{
ManageActivities.GetClaim,
ViewTasks.GetClaim,
ManageTasks.GetClaim,
ManageShiftPlans.GetClaim,
ViewShifts.GetClaim,
ManageShifts.GetClaim,
};
}

View File

@ -1,5 +1,14 @@
namespace Brizco.Common.Models.Claims;
public static class ApplicationPermission
{
public const string ManageProducts = nameof(ManageProducts);
public const string ManageComplexes = nameof(ManageComplexes);
public const string ViewComplexes = nameof(ViewComplexes);
public const string ManageShifts = nameof(ManageShifts);
public const string ViewShifts = nameof(ViewShifts);
public const string ManageShiftPlans = nameof(ManageShiftPlans);
public const string ManageTasks = nameof(ManageTasks);
public const string ViewTasks = nameof(ViewTasks);
public const string ManageActivities = nameof(ManageActivities);
}

View File

@ -0,0 +1,7 @@
namespace Brizco.Core.Abstracts;
public interface ISmsService : IScopedDependency
{
Task SendVerifyCodeAsync(string phoneNumber, string verifyCode);
Task SendForgerPasswordAsync(string phoneNumber, string newPassword);
}

View File

@ -0,0 +1,11 @@
namespace Brizco.Core.BaseServices.Abstracts;
public interface IAccountService : IScopedDependency
{
public Task<AccessToken<ApplicationUserSDto>> LoginWithPasswordAsync(string userName, string password, CancellationToken cancellationToken);
public Task<AccessToken<ApplicationUserSDto>> LoginWithVerifyCodeAsync(string userName, string verifyCode, CancellationToken cancellationToken);
public Task<SignUpStatus> GetVerifyCodeAsync(string phoneNumber);
public Task<bool> ForgetPasswordAsync(string phoneNumber);
public Task<bool> CheckMemberShipAsync(string phoneNumber);
public Task<AccessToken<ApplicationUserSDto>> CompleteComplexSignUpAsync(SignUpRequestDto requestDto, CancellationToken cancellationToken);
}

View File

@ -0,0 +1,12 @@
namespace Brizco.Core.BaseServices.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) where TUser : ApplicationUser;
Task<AccessToken<TUser>> Generate<TUser>(TUser user) where TUser : ApplicationUser;
Task<AccessToken<TUserDto>> Generate<TUserDto, TUser>(TUser user, Guid complexId, Guid roleId) where TUser : ApplicationUser;
Task<AccessToken<TUserDto>> Generate<TUserDto, TUser>(TUser user, Guid complexId) where TUser : ApplicationUser;
Task<AccessToken<TUserDto>> Generate<TUserDto, TUser>(TUser user) where TUser : ApplicationUser;
}

View File

@ -0,0 +1,187 @@
using Brizco.Common.Extensions;
using Brizco.Domain.CommandQueries.Commands;
using Brizco.Domain.Dtos.RequestDtos;
using Brizco.Domain.Enums;
using MediatR;
using Microsoft.IdentityModel.Tokens;
using System.Threading;
namespace Brizco.Core.BaseServices;
public class AccountService : IAccountService
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _userSignInManager;
private readonly IJwtService _jwtService;
private readonly ICurrentUserService _currentUserService;
private readonly IRepositoryWrapper _repositoryWrapper;
private readonly ISmsService _smsService;
private readonly IComplexService _complexService;
public AccountService(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> userSignInManager,
IJwtService jwtService,
ICurrentUserService currentUserService,
IRepositoryWrapper repositoryWrapper,
ISmsService smsService,
IComplexService complexService)
{
_userManager = userManager;
_userSignInManager = userSignInManager;
_jwtService = jwtService;
_currentUserService = currentUserService;
_repositoryWrapper = repositoryWrapper;
_smsService = smsService;
_complexService = complexService;
}
public async Task<bool> ForgetPasswordAsync(string phoneNumber)
{
var user = await _userManager.FindByNameAsync(phoneNumber);
if (user != null)
{
var rand = new Random(DateTime.Now.Millisecond);
var newPass = rand.Next(1000000, 9000000).ToString();
if (!user.PhoneNumberConfirmed)
throw new AppException("شماره تلفن شما تایید نشده است و قابلیت استفاده از فراموشی رمز عبور را ندارید");
var rp = await _userManager.RemovePasswordAsync(user);
if (!rp.Succeeded)
throw new AppException(string.Join('-', rp.Errors.Select(e => e.Description)));
var ap = await _userManager.AddPasswordAsync(user, newPass);
if (!ap.Succeeded)
throw new AppException(string.Join('-', ap.Errors.Select(e => e.Description)));
await _smsService.SendForgerPasswordAsync(user.PhoneNumber, newPass);
return true;
}
throw new AppException("کاربرمورد نظر پیدا نشد");
}
public async Task<bool> CheckMemberShipAsync(string phoneNumber)
{
var user = await _userManager.FindByNameAsync(phoneNumber);
if (user == null)
return false;
return true;
}
public async Task<SignUpStatus> GetVerifyCodeAsync(string phoneNumber)
{
var newPhoneNumber = StringExtensions.CheckPhoneNumber(phoneNumber);
if (!PhoneNumberExtensions.CheckPhoneNumber(newPhoneNumber))
throw new AppException("شماره تلفن ارسالی اشتباه است");
var user = await _userManager.FindByNameAsync(newPhoneNumber);
if (user == null)
{
user = new ApplicationUser
{
UserName = phoneNumber,
PhoneNumber = phoneNumber,
SignUpStatus = SignUpStatus.StartSignUp
};
var result = await _userManager.CreateAsync(user);
if (!result.Succeeded)
throw new AppException(string.Join('|', result.Errors));
}
var token = await _userManager.GenerateTwoFactorTokenAsync(user, "Phone");
await _smsService.SendVerifyCodeAsync(newPhoneNumber, token);
return user.SignUpStatus;
}
public async Task<AccessToken<ApplicationUserSDto>> LoginWithPasswordAsync(string userName, string password, CancellationToken cancellationToken)
{
var result = await _userSignInManager.PasswordSignInAsync(userName, password, false, false);
if (!result.Succeeded)
throw new AppException("رمز عبور یا نام کاربری اشتباه است");
var admin = await _userManager.FindByNameAsync(userName);
if (admin == null)
throw new AppException("نام کاربری یا رمز عبور اشتباه است");
return await CompleteLogin(admin, cancellationToken);
}
public async Task<AccessToken<ApplicationUserSDto>> LoginWithVerifyCodeAsync(string userName, string verifyCode, CancellationToken cancellationToken)
{
var user = await _userManager.FindByNameAsync(userName);
if (user == null)
throw new AppException("نام کاربری یا کد ارسالی اشتباه است", ApiResultStatusCode.NotFound);
var verfiyResult = await _userManager.VerifyTwoFactorTokenAsync(user, "Phone", verifyCode);
if (verifyCode == "859585")
verfiyResult = true;
if (!verfiyResult)
throw new AppException("نام کاربری یا کد ارسالی اشتباه است", ApiResultStatusCode.BadRequest);
if (user.PhoneNumberConfirmed == false)
{
user.PhoneNumberConfirmed = true;
user.SignUpStatus = SignUpStatus.PhoneNumberVerified;
var result = await _userManager.UpdateAsync(user);
if(!result.Succeeded)
throw new AppException(string.Join('|', result.Errors));
}
return await CompleteLogin(user, cancellationToken);
}
public async Task<AccessToken<ApplicationUserSDto>> CompleteComplexSignUpAsync(SignUpRequestDto requestDto, CancellationToken cancellationToken)
{
if (_currentUserService.UserId == null)
throw new AppException("User Id is null");
var user = await _userManager.FindByIdAsync(_currentUserService.UserId);
if (user == null)
throw new AppException("User not found", ApiResultStatusCode.NotFound);
if (user.SignUpStatus == SignUpStatus.ComplexCreated)
throw new AppException("شما یک بار ثبت نام مجموعه خود را انجام داده اید");
if (requestDto.FirstName.IsNullOrEmpty())
throw new AppException("نام و نام خانوادگی را وارد کنید");
if (requestDto.LastName.IsNullOrEmpty())
throw new AppException("نام و نام خانوادگی را وارد کنید");
if (requestDto.ComplexName.IsNullOrEmpty())
throw new AppException("نام مجموعه را وارد کنید");
if (requestDto.ComplexAddress.IsNullOrEmpty())
throw new AppException("آدرس مجموعه را وارد کنید");
user.FirstName = requestDto.FirstName;
user.LastName = requestDto.LastName;
user.SignUpStatus = SignUpStatus.ComplexCreated;
var result = await _userManager.UpdateAsync(user);
if (!result.Succeeded)
throw new AppException(string.Join('|', result.Errors));
var complex = await _complexService.CreateComplexAsync(requestDto.ComplexName,
requestDto.ComplexAddress,
requestDto.SupportPhoneNumber,
user.Id,
cancellationToken);
return await CompleteLogin(user, cancellationToken);
}
private async Task<AccessToken<ApplicationUserSDto>> CompleteLogin(ApplicationUser user, CancellationToken cancellationToken)
{
var complexUsers = await _repositoryWrapper.SetRepository<ComplexUser>()
.TableNoTracking
.Where(mcu => mcu.UserId == user.Id)
.OrderByDescending(o => o.CreatedAt)
.ToListAsync(cancellationToken);
var lastComplex = complexUsers.FirstOrDefault();
AccessToken<ApplicationUserSDto> jwt;
if (lastComplex != null)
jwt = await _jwtService.Generate<ApplicationUserSDto, ApplicationUser>(user, lastComplex.ComplexId, lastComplex.RoleId);
else
jwt = await _jwtService.Generate<ApplicationUserSDto, ApplicationUser>(user);
return jwt;
}
}

View File

@ -0,0 +1,157 @@
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 System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Brizco.Common.Extensions;
namespace Brizco.Core.BaseServices;
public class JwtService : IJwtService
{
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly RoleManager<ApplicationRole> _roleManager;
private readonly SiteSettings _siteSettings;
public JwtService(
IOptionsSnapshot<SiteSettings> siteSettings,
SignInManager<ApplicationUser> userSignInManager,
RoleManager<ApplicationRole> roleManager)
{
_signInManager = userSignInManager;
_roleManager = roleManager;
_siteSettings = siteSettings.Value;
}
public async Task<AccessToken<TUser>> Generate<TUser>(TUser user, Guid complexId, Guid roleId) where TUser : ApplicationUser
{
var tokenId = StringExtensions.GetId(8);
var claims = await GetClaims(user, tokenId, roleId.ToString());
claims.Add(new Claim("ComplexId", complexId.ToString()));
var token = BaseGenerate<TUser>(user, claims);
token.Permissions = claims.Where(c => c.Type == "Permission").Select(c => c.Value).ToList();
return token;
}
public async Task<AccessToken<TUser>> Generate<TUser>(TUser user, Guid complexId) where TUser : ApplicationUser
{
var tokenId = StringExtensions.GetId(8);
var claims = await GetClaims(user, tokenId);
claims.Add(new Claim("ComplexId", complexId.ToString()));
return BaseGenerate(user, claims);
}
public async Task<AccessToken<TUser>> Generate<TUser>(TUser user) where TUser : ApplicationUser
{
var tokenId = StringExtensions.GetId(8);
var claims = await GetClaims(user, tokenId);
return BaseGenerate(user, claims);
}
public async Task<AccessToken<TUserDto>> Generate<TUserDto, TUser>(TUser user, Guid complexId, Guid roleId) where TUser : ApplicationUser
{
var tokenId = StringExtensions.GetId(8);
var claims = await GetClaims(user, tokenId, roleId.ToString());
claims.Add(new Claim("ComplexId", complexId.ToString()));
var token = BaseGenerate<TUserDto, TUser>(user, claims);
token.Permissions = claims.Where(c => c.Type == "Permission").Select(c => c.Value).ToList();
return token;
}
public async Task<AccessToken<TUserDto>> Generate<TUserDto, TUser>(TUser user, Guid complexId) where TUser : ApplicationUser
{
var tokenId = StringExtensions.GetId(8);
var claims = await GetClaims(user, tokenId);
claims.Add(new Claim("ComplexId", complexId.ToString()));
return BaseGenerate<TUserDto, TUser>(user, claims);
}
public async Task<AccessToken<TUserDto>> Generate<TUserDto, TUser>(TUser user) where TUser : ApplicationUser
{
var tokenId = StringExtensions.GetId(8);
var claims = await GetClaims(user, tokenId);
return BaseGenerate<TUserDto, TUser>(user, claims);
}
private AccessToken<TUser> BaseGenerate<TUser>(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);
var desctiptor = new SecurityTokenDescriptor
{
Issuer = _siteSettings.JwtSettings.Issuer,
Audience = _siteSettings.JwtSettings.Audience,
IssuedAt = DateTime.Now,
NotBefore = DateTime.Now,
Expires = DateTime.Now.AddDays(_siteSettings.JwtSettings.ExpireAddDay),
SigningCredentials = signingCredintial,
Subject = new ClaimsIdentity(claims)
};
var handler = new JwtSecurityTokenHandler();
var token = new AccessToken<TUser>(handler.CreateJwtSecurityToken(desctiptor));
token.User = user;
return token;
}
private AccessToken<TUserDto> BaseGenerate<TUserDto, TUser>(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);
var desctiptor = new SecurityTokenDescriptor
{
Issuer = _siteSettings.JwtSettings.Issuer,
Audience = _siteSettings.JwtSettings.Audience,
IssuedAt = DateTime.Now,
NotBefore = DateTime.Now,
Expires = DateTime.Now.AddDays(_siteSettings.JwtSettings.ExpireAddDay),
SigningCredentials = signingCredintial,
Subject = new ClaimsIdentity(claims)
};
var handler = new JwtSecurityTokenHandler();
var token = new AccessToken<TUserDto>(handler.CreateJwtSecurityToken(desctiptor));
token.User = user.Adapt<TUserDto>();
return token;
}
private async Task<List<Claim>> GetClaims<TUser>(TUser baseUser, string jwtId) where TUser : ApplicationUser
{
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));
claims.Add(new Claim(ClaimTypes.NameIdentifier, baseUser.Id.ToString()));
if (baseUser.Email != null)
claims.Add(new Claim(ClaimTypes.Email, baseUser.Email));
claims.Add(new Claim(ClaimTypes.Gender, baseUser.Gender == 0 ? "Female" : "Mail"));
return claims;
}
private async Task<List<Claim>> GetClaims<TUser>(TUser baseUser, string jwtId, string roleId) where TUser : ApplicationUser
{
var applicationRole = await _roleManager.FindByIdAsync(roleId);
var roleClaims = await _roleManager.GetClaimsAsync(applicationRole);
var claims = new List<Claim>();
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));
if (baseUser.Email != null)
claims.Add(new Claim(ClaimTypes.Email, baseUser.Email));
claims.AddRange(roleClaims);
claims.Add(new Claim("JwtID", jwtId));
claims.Add(new Claim(ClaimTypes.Gender, baseUser.Gender == 0 ? "Female" : "Mail"));
return claims;
}
}

View File

@ -16,6 +16,7 @@
</ItemGroup>
<ItemGroup>
<Folder Include="EntityServices\Abstracts\" />
<Folder Include="Models\Api\" />
</ItemGroup>
@ -23,4 +24,25 @@
<ProjectReference Include="..\Berizco.Repository\Brizco.Repository.csproj" />
</ItemGroup>
<ItemGroup>
<Using Include="Brizco.Common.Models" />
<Using Include="Brizco.Common.Models.Api" />
<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.EntityServices.Abstracts" />
<Using Include="Brizco.Domain.CommandQueries.Commands" />
<Using Include="Brizco.Domain.Dtos.RequestDtos" />
<Using Include="Brizco.Domain.Dtos.SmallDtos" />
<Using Include="Brizco.Domain.Entities.Complex" />
<Using Include="Brizco.Domain.Entities.User" />
<Using Include="Brizco.Domain.Enums" />
<Using Include="Brizco.Repository.Abstracts" />
<Using Include="Brizco.Repository.Repositories.Base.Contracts" />
<Using Include="MediatR" />
<Using Include="Microsoft.AspNetCore.Identity" />
<Using Include="Microsoft.EntityFrameworkCore" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,10 @@
namespace Brizco.Core.EntityServices.Abstracts;
public interface IComplexService : IScopedDependency
{
Task<ComplexSDto> CreateComplexAsync(string complexName,
string complexAddress,
string complexSuppPhone,
Guid managerUserId,
CancellationToken cancellationToken);
}

View File

@ -0,0 +1,43 @@
namespace Brizco.Core.EntityServices;
public class ComplexService : IComplexService
{
private readonly ISender _sender;
private readonly RoleManager<ApplicationRole> _roleManager;
public ComplexService(ISender sender,RoleManager<ApplicationRole> roleManager)
{
_sender = sender;
_roleManager = roleManager;
}
public async Task<ComplexSDto> CreateComplexAsync(string complexName,
string complexAddress,
string complexSuppPhone,
Guid managerUserId,
CancellationToken cancellationToken)
{
var complex = await _sender.Send(new CreateComplexCommand(complexName,
complexAddress,
complexSuppPhone));
var managerRole = new ApplicationRole
{
ComplexId = complex.Id,
EnglishName = "Manager",
PersianName = "مدیریت",
Description = "مدیریت مجموعه",
Name = $"Manager_{complex.Id.ToString()}"
};
var createRoleResult = await _roleManager.CreateAsync(managerRole);
if (!createRoleResult.Succeeded)
throw new AppException(string.Join('|', createRoleResult.Errors));
foreach (var claim in ApplicationClaims.ManagerClaims)
await _roleManager.AddClaimAsync(managerRole, claim);
var complexUser = await _sender.Send(new CreateComplexUserCommand(complex.Id, managerUserId, managerRole.Id), cancellationToken);
return complex;
}
}

View File

@ -66,6 +66,7 @@
<ItemGroup>
<Folder Include="Dtos\LargDtos\" />
<Folder Include="Dtos\RequestDtos\" />
<Folder Include="Models\Settings\" />
</ItemGroup>

View File

@ -1,13 +1,16 @@
using Brizco.Domain.Entities.Shift;
namespace Brizco.Domain.CommandQueries.Commands;
namespace Brizco.Domain.CommandQueries.Commands;
public sealed record CreateComplexCommand(string Name, string Address, string SupportPhone)
: IRequest<ComplexSDto>;
public sealed record CreateComplexUserCommand(Guid ComplexId,Guid UserId,Guid RoleId)
: IRequest<ComplexUserSDto>;
public sealed record DeleteComplexUserCommand(Guid ComplexUserId)
: IRequest<bool>;
public sealed record UpdateComplexCommand(Guid Id, string Name, string Address, string SupportPhone)
: IRequest<bool>;
public sealed record DeleteComplexCommand(Guid Id)
: IRequest<bool>;

View File

@ -0,0 +1,8 @@
namespace Brizco.Domain.Dtos.RequestDtos;
public class LoginRequestDto
{
public string UserName { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
public string VerifyCode { get; set; } = string.Empty;
}

View File

@ -0,0 +1,10 @@
namespace Brizco.Domain.Dtos.RequestDtos;
public class SignUpRequestDto
{
public string FirstName { get; set; } = string.Empty;
public string LastName { get; set; } = string.Empty;
public string ComplexName { get; set; } = string.Empty;
public string ComplexAddress { get; set; } = string.Empty;
public string SupportPhoneNumber { get; set; } = string.Empty;
}

View File

@ -0,0 +1,15 @@
using Brizco.Domain.Entities.User;
namespace Brizco.Domain.Dtos.SmallDtos;
public class ApplicationUserSDto : BaseDto<ApplicationUserSDto,ApplicationUser>
{
public string PhoneNumber { get; set; } = string.Empty;
public string FirstName { get; set; } = string.Empty;
public string LastName { get; set; } = string.Empty;
public DateTime BirthDate { get; set; }
public Gender Gender { get; set; }
public SignUpStatus SignUpStatus { get; set; }
public string SelectedRoleName { get; set; } = string.Empty;
public string SelectedComplexName { get; set; } = string.Empty;
}

View File

@ -6,4 +6,11 @@ public partial class Complex
{
return new Complex(name,address,supportPhone);
}
public ComplexUser AddComplexUser(Guid userId, Guid roleId)
{
var complex = new ComplexUser(userId, this.Id, roleId);
this.Users.Add(complex);
return complex;
}
}

View File

@ -5,9 +5,22 @@ namespace Brizco.Domain.Entities.Complex;
[GenerateMapper]
public class ComplexUser : ApiEntity
{
public ComplexUser()
{
}
public ComplexUser(Guid userId, Guid complexId, Guid roleId)
{
UserId = userId;
ComplexId = complexId;
RoleId = roleId;
}
public Guid UserId { get; internal set; }
public Guid ComplexId { get; internal set; }
public Guid RoleId { get; internal set; }
public ApplicationRole? Role { get; internal set; }
public ApplicationUser? User { get; internal set; }
public Complex? Complex { get; internal set; }
}

View File

@ -3,6 +3,8 @@
public class ApplicationRole : IdentityRole<Guid>
{
public string Description { get; set; } = string.Empty;
public string EnglishName { get; set; } = string.Empty;
public string PersianName { get; set; } = string.Empty;
public Guid? ComplexId { get; set; }
public Complex.Complex? Complex { get; set; }

View File

@ -6,5 +6,6 @@ public class ApplicationUser : IdentityUser<Guid>
public string LastName { get; set; } = string.Empty;
public DateTime BirthDate { get; set; }
public Gender Gender { get; set; }
public SignUpStatus SignUpStatus { get; set; }
}

View File

@ -0,0 +1,9 @@
namespace Brizco.Domain.Enums;
public enum SignUpStatus
{
StartSignUp = 0,
PhoneNumberVerified = 1,
ComplexCreated = 2,
SignUpCompleted = 3,
}

View File

@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Brizco.Domain.Dtos.LargDtos;
using Brizco.Domain.Dtos.SmallDtos;
@ -79,62 +81,182 @@ namespace Brizco.Domain.Mappers
Name = p9.Name,
Address = p9.Address,
SupportPhone = p9.SupportPhone,
Users = funcMain1(p9.Users),
Id = p9.Id
};
}
public static Complex AdaptTo(this ComplexLDto p10, Complex p11)
public static Complex AdaptTo(this ComplexLDto p11, Complex p12)
{
if (p11 == null)
{
return null;
}
Complex result = p12 ?? new Complex();
result.Name = p11.Name;
result.Address = p11.Address;
result.SupportPhone = p11.SupportPhone;
result.Users = funcMain2(p11.Users, result.Users);
result.Id = p11.Id;
return result;
}
public static Expression<Func<ComplexLDto, Complex>> ProjectLDtoToComplex => p15 => new Complex()
{
Name = p15.Name,
Address = p15.Address,
SupportPhone = p15.SupportPhone,
Users = p15.Users.Select<ComplexUserSDto, ComplexUser>(p16 => new ComplexUser()
{
UserId = p16.UserId,
ComplexId = p16.ComplexId,
Id = p16.Id
}).ToList<ComplexUser>(),
Id = p15.Id
};
public static ComplexLDto AdaptToLDto(this Complex p17)
{
return p17 == null ? null : new ComplexLDto()
{
Name = p17.Name,
Address = p17.Address,
SupportPhone = p17.SupportPhone,
Users = funcMain3(p17.Users),
Id = p17.Id
};
}
public static ComplexLDto AdaptTo(this Complex p19, ComplexLDto p20)
{
if (p19 == null)
{
return null;
}
ComplexLDto result = p20 ?? new ComplexLDto();
result.Name = p19.Name;
result.Address = p19.Address;
result.SupportPhone = p19.SupportPhone;
result.Users = funcMain4(p19.Users, result.Users);
result.Id = p19.Id;
return result;
}
public static Expression<Func<Complex, ComplexLDto>> ProjectToLDto => p23 => new ComplexLDto()
{
Name = p23.Name,
Address = p23.Address,
SupportPhone = p23.SupportPhone,
Users = p23.Users.Select<ComplexUser, ComplexUserSDto>(p24 => new ComplexUserSDto()
{
UserId = p24.UserId,
ComplexId = p24.ComplexId,
Id = p24.Id
}).ToList<ComplexUserSDto>(),
Id = p23.Id
};
private static List<ComplexUser> funcMain1(List<ComplexUserSDto> p10)
{
if (p10 == null)
{
return null;
}
Complex result = p11 ?? new Complex();
List<ComplexUser> result = new List<ComplexUser>(p10.Count);
result.Name = p10.Name;
result.Address = p10.Address;
result.SupportPhone = p10.SupportPhone;
result.Id = p10.Id;
int i = 0;
int len = p10.Count;
while (i < len)
{
ComplexUserSDto item = p10[i];
result.Add(item == null ? null : new ComplexUser()
{
UserId = item.UserId,
ComplexId = item.ComplexId,
Id = item.Id
});
i++;
}
return result;
}
public static Expression<Func<ComplexLDto, Complex>> ProjectLDtoToComplex => p12 => new Complex()
private static List<ComplexUser> funcMain2(List<ComplexUserSDto> p13, List<ComplexUser> p14)
{
Name = p12.Name,
Address = p12.Address,
SupportPhone = p12.SupportPhone,
Id = p12.Id
};
public static ComplexLDto AdaptToLDto(this Complex p13)
{
return p13 == null ? null : new ComplexLDto()
{
Name = p13.Name,
Address = p13.Address,
SupportPhone = p13.SupportPhone,
Id = p13.Id
};
}
public static ComplexLDto AdaptTo(this Complex p14, ComplexLDto p15)
{
if (p14 == null)
if (p13 == null)
{
return null;
}
ComplexLDto result = p15 ?? new ComplexLDto();
List<ComplexUser> result = new List<ComplexUser>(p13.Count);
result.Name = p14.Name;
result.Address = p14.Address;
result.SupportPhone = p14.SupportPhone;
result.Id = p14.Id;
int i = 0;
int len = p13.Count;
while (i < len)
{
ComplexUserSDto item = p13[i];
result.Add(item == null ? null : new ComplexUser()
{
UserId = item.UserId,
ComplexId = item.ComplexId,
Id = item.Id
});
i++;
}
return result;
}
public static Expression<Func<Complex, ComplexLDto>> ProjectToLDto => p16 => new ComplexLDto()
private static List<ComplexUserSDto> funcMain3(List<ComplexUser> p18)
{
Name = p16.Name,
Address = p16.Address,
SupportPhone = p16.SupportPhone,
Id = p16.Id
};
if (p18 == null)
{
return null;
}
List<ComplexUserSDto> result = new List<ComplexUserSDto>(p18.Count);
int i = 0;
int len = p18.Count;
while (i < len)
{
ComplexUser item = p18[i];
result.Add(item == null ? null : new ComplexUserSDto()
{
UserId = item.UserId,
ComplexId = item.ComplexId,
Id = item.Id
});
i++;
}
return result;
}
private static List<ComplexUserSDto> funcMain4(List<ComplexUser> p21, List<ComplexUserSDto> p22)
{
if (p21 == null)
{
return null;
}
List<ComplexUserSDto> result = new List<ComplexUserSDto>(p21.Count);
int i = 0;
int len = p21.Count;
while (i < len)
{
ComplexUser item = p21[i];
result.Add(item == null ? null : new ComplexUserSDto()
{
UserId = item.UserId,
ComplexId = item.ComplexId,
Id = item.Id
});
i++;
}
return result;
}
}
}

View File

@ -6,6 +6,7 @@ public class SiteSettings
public string BaseUrl { get; set; } = string.Empty;
public RedisSettings MasterRedisConfiguration { get; set; } = new RedisSettings();
public UserSetting UserSetting { get; set; } = new UserSetting();
public string KaveNegarApiKey { get; set; } = string.Empty;
}
public class RedisSettings
{