diff --git a/Berizco.Api/Brizco.Api.csproj b/Berizco.Api/Brizco.Api.csproj
index 5e1f5ca..656e5ec 100644
--- a/Berizco.Api/Brizco.Api.csproj
+++ b/Berizco.Api/Brizco.Api.csproj
@@ -59,6 +59,7 @@
+
diff --git a/Berizco.Api/Controllers/AuthController.cs b/Berizco.Api/Controllers/AuthController.cs
new file mode 100644
index 0000000..cfd2380
--- /dev/null
+++ b/Berizco.Api/Controllers/AuthController.cs
@@ -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 SignUpComplex([FromBody] SignUpRequestDto request, IAccountService accountService, CancellationToken cancellationToken) =>
+ TypedResults.Ok(await accountService.CompleteComplexSignUpAsync(request,cancellationToken));
+
+ public async Task LoginWithPassword([FromBody] LoginRequestDto loginRequestDto,IAccountService accountService, CancellationToken cancellationToken) =>
+ TypedResults.Ok(await accountService.LoginWithPasswordAsync(loginRequestDto.UserName, loginRequestDto.Password,cancellationToken));
+
+
+ public async Task LoginWithVerifyCode([FromBody] LoginRequestDto loginRequestDto, IAccountService accountService, CancellationToken cancellationToken) =>
+ TypedResults.Ok(await accountService.LoginWithVerifyCodeAsync(loginRequestDto.UserName, loginRequestDto.VerifyCode,cancellationToken));
+
+
+ public async Task GetVerifyCodeCode([FromQuery] string phoneNumber, IAccountService accountService) =>
+ TypedResults.Ok(await accountService.GetVerifyCodeAsync(phoneNumber));
+
+
+ public async Task ForgetPassword([FromQuery] string phoneNumber, IAccountService accountService) =>
+ TypedResults.Ok(await accountService.ForgetPasswordAsync(phoneNumber));
+
+
+ public async Task LoginSwagger([FromForm] TokenRequest tokenRequest, IAccountService accountService, CancellationToken cancellationToken)
+ => TypedResults.Json(await accountService.LoginWithPasswordAsync(tokenRequest.username, tokenRequest.password,cancellationToken));
+
+
+}
\ No newline at end of file
diff --git a/Berizco.Api/Program.cs b/Berizco.Api/Program.cs
index b93ec89..d03a0c6 100644
--- a/Berizco.Api/Program.cs
+++ b/Berizco.Api/Program.cs
@@ -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();
diff --git a/Berizco.Infrastructure/Brizco.Infrastructure.csproj b/Berizco.Infrastructure/Brizco.Infrastructure.csproj
index 744594c..b3dba0d 100644
--- a/Berizco.Infrastructure/Brizco.Infrastructure.csproj
+++ b/Berizco.Infrastructure/Brizco.Infrastructure.csproj
@@ -10,8 +10,26 @@
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Berizco.Infrastructure/Models/RestAddress.cs b/Berizco.Infrastructure/Models/RestAddress.cs
new file mode 100644
index 0000000..2b76dc6
--- /dev/null
+++ b/Berizco.Infrastructure/Models/RestAddress.cs
@@ -0,0 +1,6 @@
+namespace Brizco.Infrastructure.Models;
+
+public static class RestAddress
+{
+ public static string BaseKaveNegar { get => "https://api.kavenegar.com/v1/"; }
+}
\ No newline at end of file
diff --git a/Berizco.Infrastructure/Models/RestApi/KaveNegar/KaveNegarResponse.cs b/Berizco.Infrastructure/Models/RestApi/KaveNegar/KaveNegarResponse.cs
new file mode 100644
index 0000000..a259136
--- /dev/null
+++ b/Berizco.Infrastructure/Models/RestApi/KaveNegar/KaveNegarResponse.cs
@@ -0,0 +1,7 @@
+namespace Brizco.Infrastructure.Models.RestApi.KaveNegar;
+
+public class KaveNegarResponse
+{
+ public KaveNegarReturn Return { get; set; }
+ public KaveNegarResponseEntry[] entries { get; set; }
+}
\ No newline at end of file
diff --git a/Berizco.Infrastructure/Models/RestApi/KaveNegar/KaveNegarResponseEntry.cs b/Berizco.Infrastructure/Models/RestApi/KaveNegar/KaveNegarResponseEntry.cs
new file mode 100644
index 0000000..c6c8245
--- /dev/null
+++ b/Berizco.Infrastructure/Models/RestApi/KaveNegar/KaveNegarResponseEntry.cs
@@ -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; }
+}
\ No newline at end of file
diff --git a/Berizco.Infrastructure/Models/RestApi/KaveNegar/KaveNegarReturn.cs b/Berizco.Infrastructure/Models/RestApi/KaveNegar/KaveNegarReturn.cs
new file mode 100644
index 0000000..34a3c24
--- /dev/null
+++ b/Berizco.Infrastructure/Models/RestApi/KaveNegar/KaveNegarReturn.cs
@@ -0,0 +1,7 @@
+namespace Brizco.Infrastructure.Models.RestApi.KaveNegar;
+
+public class KaveNegarReturn
+{
+ public int status { get; set; }
+ public string message { get; set; }
+}
\ No newline at end of file
diff --git a/Berizco.Infrastructure/RestServices/IKaveNegarRestApi.cs b/Berizco.Infrastructure/RestServices/IKaveNegarRestApi.cs
new file mode 100644
index 0000000..ba260ed
--- /dev/null
+++ b/Berizco.Infrastructure/RestServices/IKaveNegarRestApi.cs
@@ -0,0 +1,12 @@
+using Brizco.Infrastructure.Models.RestApi.KaveNegar;
+
+namespace Brizco.Infrastructure.RestServices;
+
+public interface IKaveNegarRestApi
+{
+
+ [Post("/{apiKey}/verify/lookup.json")]
+ Task 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 SendSms(string apiKey, [Query] string receptor, [Query] string message, [Query] string sender);
+}
\ No newline at end of file
diff --git a/Berizco.Infrastructure/RestServices/IRestApiWrapper.cs b/Berizco.Infrastructure/RestServices/IRestApiWrapper.cs
new file mode 100644
index 0000000..d30099b
--- /dev/null
+++ b/Berizco.Infrastructure/RestServices/IRestApiWrapper.cs
@@ -0,0 +1,11 @@
+namespace Brizco.Infrastructure.RestServices;
+
+public interface IRestApiWrapper : IScopedDependency
+{
+ IKaveNegarRestApi KaveNegarRestApi { get; }
+}
+
+public class RestApiWrapper : IRestApiWrapper
+{
+ public IKaveNegarRestApi KaveNegarRestApi => RestService.For(RestAddress.BaseKaveNegar);
+}
\ No newline at end of file
diff --git a/Berizco.Infrastructure/Services/SmsService.cs b/Berizco.Infrastructure/Services/SmsService.cs
new file mode 100644
index 0000000..5d43579
--- /dev/null
+++ b/Berizco.Infrastructure/Services/SmsService.cs
@@ -0,0 +1,33 @@
+namespace Brizco.Infrastructure.Services;
+
+public class SmsService : ISmsService
+{
+ private readonly IRestApiWrapper _restApiWrapper;
+ private readonly ILogger _logger;
+ private readonly SiteSettings _siteSettings;
+ public SmsService(IRestApiWrapper restApiWrapper,
+ IOptionsSnapshot optionsSnapshot,
+ ILogger 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);
+ }
+
+}
\ No newline at end of file
diff --git a/Berizco.Repository/Brizco.Repository.csproj b/Berizco.Repository/Brizco.Repository.csproj
index 7f2feeb..d728e30 100644
--- a/Berizco.Repository/Brizco.Repository.csproj
+++ b/Berizco.Repository/Brizco.Repository.csproj
@@ -29,8 +29,6 @@
-
-
diff --git a/Berizco.Repository/Handlers/Activity/CreateActivityCommandHandler.cs b/Berizco.Repository/Handlers/Activity/CreateActivityCommandHandler.cs
index 41bb5b8..ee68e7f 100644
--- a/Berizco.Repository/Handlers/Activity/CreateActivityCommandHandler.cs
+++ b/Berizco.Repository/Handlers/Activity/CreateActivityCommandHandler.cs
@@ -17,48 +17,58 @@ public class CreateActivityCommandHandler : IRequestHandler().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().Add(task);
- await _repositoryWrapper.SaveChangesAsync(cancellationToken);
- return task.AdaptToLDto();
}
}
\ No newline at end of file
diff --git a/Berizco.Repository/Handlers/Activity/DeleteActivityCommandHandler.cs b/Berizco.Repository/Handlers/Activity/DeleteActivityCommandHandler.cs
index 42684d4..0551448 100644
--- a/Berizco.Repository/Handlers/Activity/DeleteActivityCommandHandler.cs
+++ b/Berizco.Repository/Handlers/Activity/DeleteActivityCommandHandler.cs
@@ -10,15 +10,25 @@ public class DeleteActivityCommandHandler : IRequestHandler Handle(DeleteActivityCommand request, CancellationToken cancellationToken)
{
- var task = await _repositoryWrapper.SetRepository()
- .TableNoTracking
- .FirstOrDefaultAsync(s => s.Id == request.Id, cancellationToken);
- if (task == null)
- throw new AppException("Task not found", ApiResultStatusCode.NotFound);
- _repositoryWrapper.SetRepository()
- .Delete(task);
+ try
+ {
+ await _repositoryWrapper.BeginTransaction(cancellationToken);
+ var task = await _repositoryWrapper.SetRepository()
+ .TableNoTracking
+ .FirstOrDefaultAsync(s => s.Id == request.Id, cancellationToken);
+ if (task == null)
+ throw new AppException("Task not found", ApiResultStatusCode.NotFound);
+ _repositoryWrapper.SetRepository()
+ .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;
+ }
}
}
\ No newline at end of file
diff --git a/Berizco.Repository/Handlers/Activity/GetActivitiesQueryHandler.cs b/Berizco.Repository/Handlers/Activity/GetActivitiesQueryHandler.cs
index 284384f..0d6742a 100644
--- a/Berizco.Repository/Handlers/Activity/GetActivitiesQueryHandler.cs
+++ b/Berizco.Repository/Handlers/Activity/GetActivitiesQueryHandler.cs
@@ -12,7 +12,7 @@ public class GetActivitiesQueryHandler : IRequestHandler().TableNoTracking
.OrderByDescending(s => s.CreatedAt)
- .Skip(request.page * 15).Take(15)
+ .Skip(request.Page * 15).Take(15)
.Select(ActivityMapper.ProjectToSDto)
.ToListAsync(cancellationToken);
diff --git a/Berizco.Repository/Handlers/Activity/GetActivityQueryHandler.cs b/Berizco.Repository/Handlers/Activity/GetActivityQueryHandler.cs
index 9293b98..292d286 100644
--- a/Berizco.Repository/Handlers/Activity/GetActivityQueryHandler.cs
+++ b/Berizco.Repository/Handlers/Activity/GetActivityQueryHandler.cs
@@ -15,7 +15,7 @@ public class GetActivityQueryHandler : IRequestHandler()
.TableNoTracking
- .Where(s => s.Id == request.id)
+ .Where(s => s.Id == request.Id)
.Select(ActivityMapper.ProjectToLDto)
.FirstOrDefaultAsync(cancellationToken);
if (task == null)
diff --git a/Berizco.Repository/Handlers/Activity/UpdateActivityCommandHandler.cs b/Berizco.Repository/Handlers/Activity/UpdateActivityCommandHandler.cs
index 9871f4f..e488d64 100644
--- a/Berizco.Repository/Handlers/Activity/UpdateActivityCommandHandler.cs
+++ b/Berizco.Repository/Handlers/Activity/UpdateActivityCommandHandler.cs
@@ -22,29 +22,39 @@ public class UpdateActivityCommandHandler : IRequestHandler()
- .Update(newTask);
- await _repositoryWrapper.SaveChangesAsync(cancellationToken);
+ _repositoryWrapper.SetRepository()
+ .Update(newTask);
+ await _repositoryWrapper.SaveChangesAsync(cancellationToken);
+ await _repositoryWrapper.CommitAsync(cancellationToken);
- return true;
+ return true;
+ }
+ catch (Exception )
+ {
+ await _repositoryWrapper.RollBackAsync(cancellationToken);
+ throw;
+ }
}
}
\ No newline at end of file
diff --git a/Berizco.Repository/Handlers/Complex/CreateComplexCommandHandler.cs b/Berizco.Repository/Handlers/Complex/CreateComplexCommandHandler.cs
index 1d5072f..7158448 100644
--- a/Berizco.Repository/Handlers/Complex/CreateComplexCommandHandler.cs
+++ b/Berizco.Repository/Handlers/Complex/CreateComplexCommandHandler.cs
@@ -13,9 +13,19 @@ public class CreateComplexCommandHandler : IRequestHandler Handle(CreateComplexCommand request, CancellationToken cancellationToken)
{
- var complex = Domain.Entities.Complex.Complex.Create(request.Name, request.Address, request.SupportPhone);
- _repositoryWrapper.SetRepository().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().Add(complex);
+ await _repositoryWrapper.SaveChangesAsync(cancellationToken);
+ await _repositoryWrapper.CommitAsync(cancellationToken);
+ return complex.AdaptToSDto();
+ }
+ catch (Exception)
+ {
+ await _repositoryWrapper.RollBackAsync(cancellationToken);
+ throw;
+ }
}
}
\ No newline at end of file
diff --git a/Berizco.Repository/Handlers/Complex/CreateComplexUserCommandHandler.cs b/Berizco.Repository/Handlers/Complex/CreateComplexUserCommandHandler.cs
new file mode 100644
index 0000000..2612a36
--- /dev/null
+++ b/Berizco.Repository/Handlers/Complex/CreateComplexUserCommandHandler.cs
@@ -0,0 +1,51 @@
+using Brizco.Domain.Entities.User;
+using Microsoft.AspNetCore.Identity;
+
+namespace Brizco.Repository.Handlers.Complex;
+
+public class CreateComplexUserCommandHandler : IRequestHandler
+{
+ private readonly IRepositoryWrapper _repositoryWrapper;
+ private readonly UserManager _userManager;
+ private readonly RoleManager _roleManager;
+ private readonly ILogger _logger;
+
+ public CreateComplexUserCommandHandler(IRepositoryWrapper repositoryWrapper,
+ UserManager userManager,
+ RoleManager roleManager,
+ ILogger logger)
+ {
+ _repositoryWrapper = repositoryWrapper;
+ _userManager = userManager;
+ _roleManager = roleManager;
+ _logger = logger;
+ }
+
+ public async Task Handle(CreateComplexUserCommand request, CancellationToken cancellationToken)
+ {
+ try
+ {
+ await _repositoryWrapper.BeginTransaction(cancellationToken);
+ var complex = await _repositoryWrapper.SetRepository().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().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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Berizco.Repository/Handlers/Complex/DeleteComplexCommandHandler.cs b/Berizco.Repository/Handlers/Complex/DeleteComplexCommandHandler.cs
index 2dec095..7ec7f06 100644
--- a/Berizco.Repository/Handlers/Complex/DeleteComplexCommandHandler.cs
+++ b/Berizco.Repository/Handlers/Complex/DeleteComplexCommandHandler.cs
@@ -10,15 +10,25 @@ public class DeleteComplexCommandHandler : IRequestHandler Handle(DeleteComplexCommand request, CancellationToken cancellationToken)
{
- var task = await _repositoryWrapper.SetRepository()
- .TableNoTracking
- .FirstOrDefaultAsync(s => s.Id == request.Id, cancellationToken);
- if (task == null)
- throw new AppException("Task not found", ApiResultStatusCode.NotFound);
- _repositoryWrapper.SetRepository()
- .Delete(task);
+ try
+ {
+ await _repositoryWrapper.BeginTransaction(cancellationToken);
+ var task = await _repositoryWrapper.SetRepository()
+ .TableNoTracking
+ .FirstOrDefaultAsync(s => s.Id == request.Id, cancellationToken);
+ if (task == null)
+ throw new AppException("Task not found", ApiResultStatusCode.NotFound);
+ _repositoryWrapper.SetRepository()
+ .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;
+ }
}
}
\ No newline at end of file
diff --git a/Berizco.Repository/Handlers/Complex/DeleteComplexUserCommandHandler.cs b/Berizco.Repository/Handlers/Complex/DeleteComplexUserCommandHandler.cs
new file mode 100644
index 0000000..78d0d33
--- /dev/null
+++ b/Berizco.Repository/Handlers/Complex/DeleteComplexUserCommandHandler.cs
@@ -0,0 +1,36 @@
+using Brizco.Domain.Entities.Complex;
+
+namespace Brizco.Repository.Handlers.Complex;
+
+public class DeleteComplexUserCommandHandler : IRequestHandler
+{
+ private readonly IRepositoryWrapper _repositoryWrapper;
+
+ public DeleteComplexUserCommandHandler(IRepositoryWrapper repositoryWrapper)
+ {
+ _repositoryWrapper = repositoryWrapper;
+ }
+
+ public async Task Handle(DeleteComplexUserCommand request, CancellationToken cancellationToken)
+ {
+ try
+ {
+ await _repositoryWrapper.BeginTransaction(cancellationToken);
+ var complexUser = await _repositoryWrapper.SetRepository()
+ .TableNoTracking
+ .FirstOrDefaultAsync(c => c.Id == request.ComplexUserId, cancellationToken);
+ if (complexUser == null)
+ throw new AppException("ComplexUser not found", ApiResultStatusCode.NotFound);
+
+ _repositoryWrapper.SetRepository().Delete(complexUser);
+ await _repositoryWrapper.SaveChangesAsync(cancellationToken);
+ await _repositoryWrapper.CommitAsync(cancellationToken);
+ return true;
+ }
+ catch (Exception)
+ {
+ await _repositoryWrapper.RollBackAsync(cancellationToken);
+ throw;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Berizco.Repository/Handlers/Complex/GetComplexQueryHandler.cs b/Berizco.Repository/Handlers/Complex/GetComplexQueryHandler.cs
index cd5b59b..fe8376a 100644
--- a/Berizco.Repository/Handlers/Complex/GetComplexQueryHandler.cs
+++ b/Berizco.Repository/Handlers/Complex/GetComplexQueryHandler.cs
@@ -14,7 +14,7 @@ public class GetComplexQueryHandler : IRequestHandler()
.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);
diff --git a/Berizco.Repository/Handlers/Complex/GetComplexesQueryHandler.cs b/Berizco.Repository/Handlers/Complex/GetComplexesQueryHandler.cs
index 8958889..5ad15e5 100644
--- a/Berizco.Repository/Handlers/Complex/GetComplexesQueryHandler.cs
+++ b/Berizco.Repository/Handlers/Complex/GetComplexesQueryHandler.cs
@@ -8,7 +8,7 @@ public class GetComplexesQueryHandler : IRequestHandler> Handle(GetComplexesQuery request, CancellationToken cancellationToken)
+ public async Task> Handle(GetComplexesQuery request, CancellationToken cancellationToken)
{
var tasks = await _repositoryWrapper.SetRepository().TableNoTracking
.OrderByDescending(s => s.CreatedAt)
diff --git a/Berizco.Repository/Handlers/Complex/UpdateActivityCommandHandler.cs b/Berizco.Repository/Handlers/Complex/UpdateActivityCommandHandler.cs
deleted file mode 100644
index a17e9cb..0000000
--- a/Berizco.Repository/Handlers/Complex/UpdateActivityCommandHandler.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-namespace Brizco.Repository.Handlers.Complex;
-
-public class UpdateActivityCommandHandler : IRequestHandler
-{
- private readonly IRepositoryWrapper _repositoryWrapper;
- private readonly ICurrentUserService _currentUserService;
-
- public UpdateActivityCommandHandler(IRepositoryWrapper repositoryWrapper,ICurrentUserService currentUserService)
- {
- _repositoryWrapper = repositoryWrapper;
- _currentUserService = currentUserService;
- }
-
- public async Task Handle(UpdateActivityCommand request, CancellationToken cancellationToken)
- {
- var task = await _repositoryWrapper.SetRepository()
- .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()
- .Update(newTask);
- await _repositoryWrapper.SaveChangesAsync(cancellationToken);
-
- return true;
- }
-}
\ No newline at end of file
diff --git a/Berizco.Repository/Handlers/Shift/CreateShiftCommandHandler.cs b/Berizco.Repository/Handlers/Shift/CreateShiftCommandHandler.cs
index f56b0c0..44f5a4a 100644
--- a/Berizco.Repository/Handlers/Shift/CreateShiftCommandHandler.cs
+++ b/Berizco.Repository/Handlers/Shift/CreateShiftCommandHandler.cs
@@ -18,17 +18,27 @@ public class CreateShiftCommandHandler : IRequestHandler shift.SetDay(d));
+ request.DayOfWeeks.ForEach(d => shift.SetDay(d));
- _repositoryWrapper.SetRepository().Add(shift);
- await _repositoryWrapper.SaveChangesAsync(cancellationToken);
- return shift;
+ _repositoryWrapper.SetRepository().Add(shift);
+ await _repositoryWrapper.SaveChangesAsync(cancellationToken);
+ await _repositoryWrapper.CommitAsync(cancellationToken);
+ return shift;
+ }
+ catch (Exception )
+ {
+ await _repositoryWrapper.RollBackAsync(cancellationToken);
+ throw;
+ }
}
}
\ No newline at end of file
diff --git a/Berizco.Repository/Handlers/Shift/DeleteShiftCommandHandler.cs b/Berizco.Repository/Handlers/Shift/DeleteShiftCommandHandler.cs
index e4622cd..77fbc36 100644
--- a/Berizco.Repository/Handlers/Shift/DeleteShiftCommandHandler.cs
+++ b/Berizco.Repository/Handlers/Shift/DeleteShiftCommandHandler.cs
@@ -12,7 +12,7 @@ public class DeleteShiftCommandHandler : IRequestHandler()
.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()
diff --git a/Berizco.Repository/Handlers/Shift/UpdateShiftCommandHandler.cs b/Berizco.Repository/Handlers/Shift/UpdateShiftCommandHandler.cs
index 5d8c6cd..43ff0b5 100644
--- a/Berizco.Repository/Handlers/Shift/UpdateShiftCommandHandler.cs
+++ b/Berizco.Repository/Handlers/Shift/UpdateShiftCommandHandler.cs
@@ -14,7 +14,7 @@ public class UpdateShiftCommandHandler : IRequestHandler Handle(UpdateShiftCommand request, CancellationToken cancellationToken)
{
var shift = await _repositoryWrapper.SetRepository()
- .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()
.Update(newShift);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
diff --git a/Berizco.Repository/Handlers/ShiftPlan/CreateShiftPlanCommandHandler.cs b/Berizco.Repository/Handlers/ShiftPlan/CreateShiftPlanCommandHandler.cs
index 23b80dc..a3fe947 100644
--- a/Berizco.Repository/Handlers/ShiftPlan/CreateShiftPlanCommandHandler.cs
+++ b/Berizco.Repository/Handlers/ShiftPlan/CreateShiftPlanCommandHandler.cs
@@ -16,15 +16,26 @@ public class CreateShiftPlanCommandHandler : IRequestHandlershiftPlan.AddUser(i));
+ request.UserIds.ForEach(i => shiftPlan.AddUser(i));
- _repositoryWrapper.SetRepository().Add(shiftPlan);
- await _repositoryWrapper.SaveChangesAsync(cancellationToken);
- return shiftPlan.AdaptToLDto();
+ _repositoryWrapper.SetRepository().Add(shiftPlan);
+ await _repositoryWrapper.SaveChangesAsync(cancellationToken);
+ await _repositoryWrapper.CommitAsync(cancellationToken);
+ return shiftPlan.AdaptToLDto();
+ }
+ catch (Exception )
+ {
+ await _repositoryWrapper.RollBackAsync(cancellationToken);
+ throw;
+ }
}
}
\ No newline at end of file
diff --git a/Berizco.Repository/Handlers/Task/DeleteTaskCommandHandler.cs b/Berizco.Repository/Handlers/Task/DeleteTaskCommandHandler.cs
index fcaaa3e..2911a30 100644
--- a/Berizco.Repository/Handlers/Task/DeleteTaskCommandHandler.cs
+++ b/Berizco.Repository/Handlers/Task/DeleteTaskCommandHandler.cs
@@ -12,7 +12,7 @@ public class DeleteActivityCommandHandler : IRequestHandler()
.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()
diff --git a/Berizco.Repository/Handlers/Task/GetTaskQueryHandler.cs b/Berizco.Repository/Handlers/Task/GetTaskQueryHandler.cs
index cd7e3af..75e87b6 100644
--- a/Berizco.Repository/Handlers/Task/GetTaskQueryHandler.cs
+++ b/Berizco.Repository/Handlers/Task/GetTaskQueryHandler.cs
@@ -15,7 +15,7 @@ public class GetActivityQueryHandler : IRequestHandler
{
var task = await _repositoryWrapper.SetRepository()
.TableNoTracking
- .Where(s => s.Id == request.id)
+ .Where(s => s.Id == request.Id)
.Select(TaskMapper.ProjectToLDto)
.FirstOrDefaultAsync(cancellationToken);
if (task == null)
diff --git a/Berizco.Repository/Handlers/Task/GetTasksQueryHandler.cs b/Berizco.Repository/Handlers/Task/GetTasksQueryHandler.cs
index 9c59add..180d5ec 100644
--- a/Berizco.Repository/Handlers/Task/GetTasksQueryHandler.cs
+++ b/Berizco.Repository/Handlers/Task/GetTasksQueryHandler.cs
@@ -12,7 +12,7 @@ public class GetActivitiesQueryHandler : IRequestHandler().TableNoTracking
.OrderByDescending(s => s.CreatedAt)
- .Skip(request.page * 15).Take(15)
+ .Skip(request.Page * 15).Take(15)
.Select(TaskMapper.ProjectToSDto)
.ToListAsync(cancellationToken);
diff --git a/Berizco.Repository/Handlers/Task/UpdateTaskCommandHandler.cs b/Berizco.Repository/Handlers/Task/UpdateTaskCommandHandler.cs
index f16e55a..fc08f8d 100644
--- a/Berizco.Repository/Handlers/Task/UpdateTaskCommandHandler.cs
+++ b/Berizco.Repository/Handlers/Task/UpdateTaskCommandHandler.cs
@@ -14,7 +14,7 @@ public class UpdateActivityCommandHandler : IRequestHandler Handle(UpdateTaskCommand request, CancellationToken cancellationToken)
{
var task = await _repositoryWrapper.SetRepository()
- .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()
.Update(newTask);
diff --git a/Berizco.Repository/Migrations/20230918112118_Init.Designer.cs b/Berizco.Repository/Migrations/20230919130824_Init.Designer.cs
similarity index 97%
rename from Berizco.Repository/Migrations/20230918112118_Init.Designer.cs
rename to Berizco.Repository/Migrations/20230919130824_Init.Designer.cs
index 6ba96a8..539b19e 100644
--- a/Berizco.Repository/Migrations/20230918112118_Init.Designer.cs
+++ b/Berizco.Repository/Migrations/20230919130824_Init.Designer.cs
@@ -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
{
///
@@ -106,6 +106,9 @@ namespace Brizco.Repository.Migrations
.IsRequired()
.HasColumnType("text");
+ b.Property("RoleId")
+ .HasColumnType("uuid");
+
b.Property("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("EnglishName")
+ .IsRequired()
+ .HasColumnType("text");
+
b.Property("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
@@ -549,6 +558,10 @@ namespace Brizco.Repository.Migrations
.HasMaxLength(256)
.HasColumnType("character varying(256)");
+ b.Property("PersianName")
+ .IsRequired()
+ .HasColumnType("text");
+
b.HasKey("Id");
b.HasIndex("ComplexId");
@@ -620,6 +633,9 @@ namespace Brizco.Repository.Migrations
b.Property("SecurityStamp")
.HasColumnType("text");
+ b.Property("SignUpStatus")
+ .HasColumnType("integer");
+
b.Property("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");
});
diff --git a/Berizco.Repository/Migrations/20230918112118_Init.cs b/Berizco.Repository/Migrations/20230919130824_Init.cs
similarity index 97%
rename from Berizco.Repository/Migrations/20230918112118_Init.cs
rename to Berizco.Repository/Migrations/20230919130824_Init.cs
index b702314..b4abe47 100644
--- a/Berizco.Repository/Migrations/20230918112118_Init.cs
+++ b/Berizco.Repository/Migrations/20230919130824_Init.cs
@@ -47,6 +47,7 @@ namespace Brizco.Repository.Migrations
LastName = table.Column(type: "text", nullable: false),
BirthDate = table.Column(type: "timestamp without time zone", nullable: false),
Gender = table.Column(type: "integer", nullable: false),
+ SignUpStatus = table.Column(type: "integer", nullable: false),
UserName = table.Column(type: "character varying(256)", maxLength: 256, nullable: true),
NormalizedUserName = table.Column(type: "character varying(256)", maxLength: 256, nullable: true),
Email = table.Column(type: "character varying(256)", maxLength: 256, nullable: true),
@@ -74,6 +75,8 @@ namespace Brizco.Repository.Migrations
{
Id = table.Column(type: "uuid", nullable: false),
Description = table.Column(type: "text", nullable: false),
+ EnglishName = table.Column(type: "text", nullable: false),
+ PersianName = table.Column(type: "text", nullable: false),
ComplexId = table.Column(type: "uuid", nullable: true),
Name = table.Column(type: "character varying(256)", maxLength: 256, nullable: true),
NormalizedName = table.Column(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(type: "uuid", nullable: false),
- UserId = table.Column(type: "uuid", nullable: false),
- ComplexId = table.Column(type: "uuid", nullable: false),
- RemovedAt = table.Column(type: "timestamp without time zone", nullable: false),
- CreatedAt = table.Column(type: "timestamp without time zone", nullable: false),
- CreatedBy = table.Column(type: "text", nullable: false),
- IsRemoved = table.Column(type: "boolean", nullable: false),
- RemovedBy = table.Column(type: "text", nullable: false),
- ModifiedAt = table.Column(type: "timestamp without time zone", nullable: false),
- ModifiedBy = table.Column(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(type: "uuid", nullable: false),
+ UserId = table.Column(type: "uuid", nullable: false),
+ ComplexId = table.Column(type: "uuid", nullable: false),
+ RoleId = table.Column(type: "uuid", nullable: false),
+ RemovedAt = table.Column(type: "timestamp without time zone", nullable: false),
+ CreatedAt = table.Column(type: "timestamp without time zone", nullable: false),
+ CreatedBy = table.Column(type: "text", nullable: false),
+ IsRemoved = table.Column(type: "boolean", nullable: false),
+ RemovedBy = table.Column(type: "text", nullable: false),
+ ModifiedAt = table.Column(type: "timestamp without time zone", nullable: false),
+ ModifiedBy = table.Column(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",
diff --git a/Berizco.Repository/Migrations/ApplicationContextModelSnapshot.cs b/Berizco.Repository/Migrations/ApplicationContextModelSnapshot.cs
index c6f4de3..3482684 100644
--- a/Berizco.Repository/Migrations/ApplicationContextModelSnapshot.cs
+++ b/Berizco.Repository/Migrations/ApplicationContextModelSnapshot.cs
@@ -103,6 +103,9 @@ namespace Brizco.Repository.Migrations
.IsRequired()
.HasColumnType("text");
+ b.Property("RoleId")
+ .HasColumnType("uuid");
+
b.Property("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("EnglishName")
+ .IsRequired()
+ .HasColumnType("text");
+
b.Property("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
@@ -546,6 +555,10 @@ namespace Brizco.Repository.Migrations
.HasMaxLength(256)
.HasColumnType("character varying(256)");
+ b.Property("PersianName")
+ .IsRequired()
+ .HasColumnType("text");
+
b.HasKey("Id");
b.HasIndex("ComplexId");
@@ -617,6 +630,9 @@ namespace Brizco.Repository.Migrations
b.Property("SecurityStamp")
.HasColumnType("text");
+ b.Property("SignUpStatus")
+ .HasColumnType("integer");
+
b.Property("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");
});
diff --git a/Berizco.Repository/Repositories/Base/Contracts/IRepositoryWrapper.cs b/Berizco.Repository/Repositories/Base/Contracts/IRepositoryWrapper.cs
index 56f2154..c5a0586 100644
--- a/Berizco.Repository/Repositories/Base/Contracts/IRepositoryWrapper.cs
+++ b/Berizco.Repository/Repositories/Base/Contracts/IRepositoryWrapper.cs
@@ -3,6 +3,9 @@
public interface IRepositoryWrapper : IDisposable , IScopedDependency
{
IBaseRepository SetRepository() 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);
}
}
\ No newline at end of file
diff --git a/Berizco.Repository/Repositories/Base/RepositoryWrapper.cs b/Berizco.Repository/Repositories/Base/RepositoryWrapper.cs
index 1c52bd4..b61134f 100644
--- a/Berizco.Repository/Repositories/Base/RepositoryWrapper.cs
+++ b/Berizco.Repository/Repositories/Base/RepositoryWrapper.cs
@@ -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 SetRepository() where T : ApiEntity => new BaseRepository(_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> entries = _context.ChangeTracker.Entries();
+ foreach (EntityEntry 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();
}
}
diff --git a/Berizco.Repository/Repositories/UnitOfWork/IUnitOfWork.cs b/Berizco.Repository/Repositories/UnitOfWork/IUnitOfWork.cs
index 7e7e191..23d737f 100644
--- a/Berizco.Repository/Repositories/UnitOfWork/IUnitOfWork.cs
+++ b/Berizco.Repository/Repositories/UnitOfWork/IUnitOfWork.cs
@@ -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);
}
\ No newline at end of file
diff --git a/Berizco.Repository/Repositories/UnitOfWork/UnitOfWork.cs b/Berizco.Repository/Repositories/UnitOfWork/UnitOfWork.cs
index 30d754a..2425d23 100644
--- a/Berizco.Repository/Repositories/UnitOfWork/UnitOfWork.cs
+++ b/Berizco.Repository/Repositories/UnitOfWork/UnitOfWork.cs
@@ -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();
diff --git a/Berizco.Repository/Services/DbInitializerService.cs b/Berizco.Repository/Services/DbInitializerService.cs
index bc6b4ce..5573c1b 100644
--- a/Berizco.Repository/Services/DbInitializerService.cs
+++ b/Berizco.Repository/Services/DbInitializerService.cs
@@ -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);
diff --git a/Brizco.Common/Models/Claims/ApplicationClaims.cs b/Brizco.Common/Models/Claims/ApplicationClaims.cs
index 1959d3f..d275794 100644
--- a/Brizco.Common/Models/Claims/ApplicationClaims.cs
+++ b/Brizco.Common/Models/Claims/ApplicationClaims.cs
@@ -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 AllClaims = new List
{
- ManageProducts.GetClaim
+ ManageActivities.GetClaim,
+ ViewTasks.GetClaim,
+ ManageTasks.GetClaim,
+
+ ManageShiftPlans.GetClaim,
+ ViewShifts.GetClaim,
+ ManageShifts.GetClaim,
+
+ ViewComplexes.GetClaim,
+ ManageComplexes.GetClaim,
+ };
+
+ public static List ManagerClaims = new List
+ {
+ ManageActivities.GetClaim,
+ ViewTasks.GetClaim,
+ ManageTasks.GetClaim,
+
+ ManageShiftPlans.GetClaim,
+ ViewShifts.GetClaim,
+ ManageShifts.GetClaim,
};
}
diff --git a/Brizco.Common/Models/Claims/ApplicationPermission.cs b/Brizco.Common/Models/Claims/ApplicationPermission.cs
index 9ea5d0b..5c140ba 100644
--- a/Brizco.Common/Models/Claims/ApplicationPermission.cs
+++ b/Brizco.Common/Models/Claims/ApplicationPermission.cs
@@ -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);
}
diff --git a/Brizco.Core/Abstracts/ISmsService.cs b/Brizco.Core/Abstracts/ISmsService.cs
new file mode 100644
index 0000000..dd15d1b
--- /dev/null
+++ b/Brizco.Core/Abstracts/ISmsService.cs
@@ -0,0 +1,7 @@
+namespace Brizco.Core.Abstracts;
+
+public interface ISmsService : IScopedDependency
+{
+ Task SendVerifyCodeAsync(string phoneNumber, string verifyCode);
+ Task SendForgerPasswordAsync(string phoneNumber, string newPassword);
+}
\ No newline at end of file
diff --git a/Brizco.Core/BaseServices/Abstracts/IAccountService.cs b/Brizco.Core/BaseServices/Abstracts/IAccountService.cs
new file mode 100644
index 0000000..bf24bc4
--- /dev/null
+++ b/Brizco.Core/BaseServices/Abstracts/IAccountService.cs
@@ -0,0 +1,11 @@
+namespace Brizco.Core.BaseServices.Abstracts;
+
+public interface IAccountService : IScopedDependency
+{
+ public Task> LoginWithPasswordAsync(string userName, string password, CancellationToken cancellationToken);
+ public Task> LoginWithVerifyCodeAsync(string userName, string verifyCode, CancellationToken cancellationToken);
+ public Task GetVerifyCodeAsync(string phoneNumber);
+ public Task ForgetPasswordAsync(string phoneNumber);
+ public Task CheckMemberShipAsync(string phoneNumber);
+ public Task> CompleteComplexSignUpAsync(SignUpRequestDto requestDto, CancellationToken cancellationToken);
+}
\ No newline at end of file
diff --git a/Brizco.Core/BaseServices/Abstracts/IJwtService.cs b/Brizco.Core/BaseServices/Abstracts/IJwtService.cs
new file mode 100644
index 0000000..3354d8d
--- /dev/null
+++ b/Brizco.Core/BaseServices/Abstracts/IJwtService.cs
@@ -0,0 +1,12 @@
+namespace Brizco.Core.BaseServices.Abstracts;
+
+public interface IJwtService : IScopedDependency
+{
+ Task> Generate(TUser user, Guid complexId,Guid roleId) where TUser : ApplicationUser;
+ Task> Generate(TUser user, Guid complexId) where TUser : ApplicationUser;
+ Task> Generate(TUser user) where TUser : ApplicationUser;
+
+ Task> Generate(TUser user, Guid complexId, Guid roleId) where TUser : ApplicationUser;
+ Task> Generate(TUser user, Guid complexId) where TUser : ApplicationUser;
+ Task> Generate(TUser user) where TUser : ApplicationUser;
+}
\ No newline at end of file
diff --git a/Brizco.Core/BaseServices/AccountService.cs b/Brizco.Core/BaseServices/AccountService.cs
new file mode 100644
index 0000000..a0cc9ae
--- /dev/null
+++ b/Brizco.Core/BaseServices/AccountService.cs
@@ -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 _userManager;
+ private readonly SignInManager _userSignInManager;
+ private readonly IJwtService _jwtService;
+ private readonly ICurrentUserService _currentUserService;
+ private readonly IRepositoryWrapper _repositoryWrapper;
+ private readonly ISmsService _smsService;
+ private readonly IComplexService _complexService;
+
+ public AccountService(
+ UserManager userManager,
+ SignInManager 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 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 CheckMemberShipAsync(string phoneNumber)
+ {
+ var user = await _userManager.FindByNameAsync(phoneNumber);
+ if (user == null)
+ return false;
+ return true;
+ }
+
+ public async Task 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> 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> 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> 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> CompleteLogin(ApplicationUser user, CancellationToken cancellationToken)
+ {
+
+ var complexUsers = await _repositoryWrapper.SetRepository()
+ .TableNoTracking
+ .Where(mcu => mcu.UserId == user.Id)
+ .OrderByDescending(o => o.CreatedAt)
+ .ToListAsync(cancellationToken);
+ var lastComplex = complexUsers.FirstOrDefault();
+ AccessToken jwt;
+ if (lastComplex != null)
+ jwt = await _jwtService.Generate(user, lastComplex.ComplexId, lastComplex.RoleId);
+ else
+ jwt = await _jwtService.Generate(user);
+
+ return jwt;
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/Brizco.Core/BaseServices/JwtService.cs b/Brizco.Core/BaseServices/JwtService.cs
new file mode 100644
index 0000000..b8a5339
--- /dev/null
+++ b/Brizco.Core/BaseServices/JwtService.cs
@@ -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 _signInManager;
+ private readonly RoleManager _roleManager;
+ private readonly SiteSettings _siteSettings;
+
+ public JwtService(
+ IOptionsSnapshot siteSettings,
+ SignInManager userSignInManager,
+ RoleManager roleManager)
+ {
+ _signInManager = userSignInManager;
+ _roleManager = roleManager;
+ _siteSettings = siteSettings.Value;
+ }
+ public async Task> Generate(TUser user, Guid complexId, Guid roleId) where TUser : ApplicationUser
+ {
+ var tokenId = StringExtensions.GetId(8);
+ var claims = await GetClaims(user, tokenId, roleId.ToString());
+ claims.Add(new Claim("ComplexId", complexId.ToString()));
+
+ var token = BaseGenerate(user, claims);
+ token.Permissions = claims.Where(c => c.Type == "Permission").Select(c => c.Value).ToList();
+ return token;
+ }
+ public async Task> Generate(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> Generate(TUser user) where TUser : ApplicationUser
+ {
+ var tokenId = StringExtensions.GetId(8);
+ var claims = await GetClaims(user, tokenId);
+ return BaseGenerate(user, claims);
+
+ }
+
+ public async Task> Generate(TUser user, Guid complexId, Guid roleId) where TUser : ApplicationUser
+ {
+ var tokenId = StringExtensions.GetId(8);
+ var claims = await GetClaims(user, tokenId, roleId.ToString());
+ claims.Add(new Claim("ComplexId", complexId.ToString()));
+
+ var token = BaseGenerate(user, claims);
+ token.Permissions = claims.Where(c => c.Type == "Permission").Select(c => c.Value).ToList();
+ return token;
+ }
+ public async Task> Generate(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> Generate(TUser user) where TUser : ApplicationUser
+ {
+ var tokenId = StringExtensions.GetId(8);
+ var claims = await GetClaims(user, tokenId);
+ return BaseGenerate(user, claims);
+ }
+
+
+
+
+ private AccessToken BaseGenerate(TUser user, List claims) where TUser : ApplicationUser
+ {
+ var secretKey = Encoding.UTF8.GetBytes(_siteSettings.JwtSettings.SecretKey);
+ var signingCredintial = new SigningCredentials(new SymmetricSecurityKey(secretKey), SecurityAlgorithms.HmacSha512Signature);
+
+ 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(handler.CreateJwtSecurityToken(desctiptor));
+ token.User = user;
+ return token;
+ }
+ private AccessToken BaseGenerate(TUser user, List claims) where TUser : ApplicationUser
+ {
+ var secretKey = Encoding.UTF8.GetBytes(_siteSettings.JwtSettings.SecretKey);
+ var signingCredintial = new SigningCredentials(new SymmetricSecurityKey(secretKey), SecurityAlgorithms.HmacSha512Signature);
+
+ 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(handler.CreateJwtSecurityToken(desctiptor));
+ token.User = user.Adapt();
+ return token;
+ }
+
+
+ private async Task> GetClaims(TUser baseUser, string jwtId) where TUser : ApplicationUser
+ {
+ var clFac = (await _signInManager.ClaimsFactory.CreateAsync(baseUser));
+ var claims = new List();
+ claims.Add(new Claim("JwtID", jwtId));
+ claims.Add(new Claim(ClaimTypes.Name, baseUser.UserName));
+ 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> GetClaims(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();
+ 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;
+
+ }
+
+}
\ No newline at end of file
diff --git a/Brizco.Core/Brizco.Core.csproj b/Brizco.Core/Brizco.Core.csproj
index 97c9b95..81ebdf8 100644
--- a/Brizco.Core/Brizco.Core.csproj
+++ b/Brizco.Core/Brizco.Core.csproj
@@ -16,6 +16,7 @@
+
@@ -23,4 +24,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Brizco.Core/EntityServices/Abstracts/IComplexService.cs b/Brizco.Core/EntityServices/Abstracts/IComplexService.cs
new file mode 100644
index 0000000..3ff2393
--- /dev/null
+++ b/Brizco.Core/EntityServices/Abstracts/IComplexService.cs
@@ -0,0 +1,10 @@
+namespace Brizco.Core.EntityServices.Abstracts;
+
+public interface IComplexService : IScopedDependency
+{
+ Task CreateComplexAsync(string complexName,
+ string complexAddress,
+ string complexSuppPhone,
+ Guid managerUserId,
+ CancellationToken cancellationToken);
+}
\ No newline at end of file
diff --git a/Brizco.Core/EntityServices/ComplexService.cs b/Brizco.Core/EntityServices/ComplexService.cs
new file mode 100644
index 0000000..1579870
--- /dev/null
+++ b/Brizco.Core/EntityServices/ComplexService.cs
@@ -0,0 +1,43 @@
+namespace Brizco.Core.EntityServices;
+
+public class ComplexService : IComplexService
+{
+ private readonly ISender _sender;
+ private readonly RoleManager _roleManager;
+
+ public ComplexService(ISender sender,RoleManager roleManager)
+ {
+ _sender = sender;
+ _roleManager = roleManager;
+ }
+ public async Task 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;
+ }
+}
\ No newline at end of file
diff --git a/Brizco.Domain/Brizco.Domain.csproj b/Brizco.Domain/Brizco.Domain.csproj
index 559318b..e31a5b5 100644
--- a/Brizco.Domain/Brizco.Domain.csproj
+++ b/Brizco.Domain/Brizco.Domain.csproj
@@ -66,6 +66,7 @@
+
diff --git a/Brizco.Domain/CommandQueries/Commands/ComplexCommands.cs b/Brizco.Domain/CommandQueries/Commands/ComplexCommands.cs
index 7f77bba..e6e2c1c 100644
--- a/Brizco.Domain/CommandQueries/Commands/ComplexCommands.cs
+++ b/Brizco.Domain/CommandQueries/Commands/ComplexCommands.cs
@@ -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;
+public sealed record CreateComplexUserCommand(Guid ComplexId,Guid UserId,Guid RoleId)
+ : IRequest;
+
+public sealed record DeleteComplexUserCommand(Guid ComplexUserId)
+ : IRequest;
+
public sealed record UpdateComplexCommand(Guid Id, string Name, string Address, string SupportPhone)
: IRequest;
-
public sealed record DeleteComplexCommand(Guid Id)
: IRequest;
\ No newline at end of file
diff --git a/Brizco.Domain/Dtos/RequestDtos/LoginRequestDto.cs b/Brizco.Domain/Dtos/RequestDtos/LoginRequestDto.cs
new file mode 100644
index 0000000..c0fe72f
--- /dev/null
+++ b/Brizco.Domain/Dtos/RequestDtos/LoginRequestDto.cs
@@ -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;
+}
\ No newline at end of file
diff --git a/Brizco.Domain/Dtos/RequestDtos/SignUpRequestDto.cs b/Brizco.Domain/Dtos/RequestDtos/SignUpRequestDto.cs
new file mode 100644
index 0000000..042439c
--- /dev/null
+++ b/Brizco.Domain/Dtos/RequestDtos/SignUpRequestDto.cs
@@ -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;
+}
\ No newline at end of file
diff --git a/Brizco.Domain/Dtos/SmallDtos/ApplicationUserSDto.cs b/Brizco.Domain/Dtos/SmallDtos/ApplicationUserSDto.cs
new file mode 100644
index 0000000..2620341
--- /dev/null
+++ b/Brizco.Domain/Dtos/SmallDtos/ApplicationUserSDto.cs
@@ -0,0 +1,15 @@
+using Brizco.Domain.Entities.User;
+
+namespace Brizco.Domain.Dtos.SmallDtos;
+
+public class ApplicationUserSDto : BaseDto
+{
+ 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;
+}
\ No newline at end of file
diff --git a/Brizco.Domain/Entities/Complex/Aggregate.Complex.cs b/Brizco.Domain/Entities/Complex/Aggregate.Complex.cs
index 14c9116..53613ee 100644
--- a/Brizco.Domain/Entities/Complex/Aggregate.Complex.cs
+++ b/Brizco.Domain/Entities/Complex/Aggregate.Complex.cs
@@ -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;
+ }
}
\ No newline at end of file
diff --git a/Brizco.Domain/Entities/Complex/ComplexUser.cs b/Brizco.Domain/Entities/Complex/ComplexUser.cs
index b8d2355..8f4a865 100644
--- a/Brizco.Domain/Entities/Complex/ComplexUser.cs
+++ b/Brizco.Domain/Entities/Complex/ComplexUser.cs
@@ -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; }
}
\ No newline at end of file
diff --git a/Brizco.Domain/Entities/User/ApplicationRole.cs b/Brizco.Domain/Entities/User/ApplicationRole.cs
index 8f6deb6..d794e9a 100644
--- a/Brizco.Domain/Entities/User/ApplicationRole.cs
+++ b/Brizco.Domain/Entities/User/ApplicationRole.cs
@@ -3,6 +3,8 @@
public class ApplicationRole : IdentityRole
{
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; }
diff --git a/Brizco.Domain/Entities/User/ApplicationUser.cs b/Brizco.Domain/Entities/User/ApplicationUser.cs
index d77f935..2d60db9 100644
--- a/Brizco.Domain/Entities/User/ApplicationUser.cs
+++ b/Brizco.Domain/Entities/User/ApplicationUser.cs
@@ -6,5 +6,6 @@ public class ApplicationUser : IdentityUser
public string LastName { get; set; } = string.Empty;
public DateTime BirthDate { get; set; }
public Gender Gender { get; set; }
+ public SignUpStatus SignUpStatus { get; set; }
}
diff --git a/Brizco.Domain/Enums/SignUpStatus.cs b/Brizco.Domain/Enums/SignUpStatus.cs
new file mode 100644
index 0000000..ca60767
--- /dev/null
+++ b/Brizco.Domain/Enums/SignUpStatus.cs
@@ -0,0 +1,9 @@
+namespace Brizco.Domain.Enums;
+
+public enum SignUpStatus
+{
+ StartSignUp = 0,
+ PhoneNumberVerified = 1,
+ ComplexCreated = 2,
+ SignUpCompleted = 3,
+}
\ No newline at end of file
diff --git a/Brizco.Domain/Mappers/ComplexMapper.g.cs b/Brizco.Domain/Mappers/ComplexMapper.g.cs
index 53665e1..1bfcb2e 100644
--- a/Brizco.Domain/Mappers/ComplexMapper.g.cs
+++ b/Brizco.Domain/Mappers/ComplexMapper.g.cs
@@ -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> ProjectLDtoToComplex => p15 => new Complex()
+ {
+ Name = p15.Name,
+ Address = p15.Address,
+ SupportPhone = p15.SupportPhone,
+ Users = p15.Users.Select(p16 => new ComplexUser()
+ {
+ UserId = p16.UserId,
+ ComplexId = p16.ComplexId,
+ Id = p16.Id
+ }).ToList(),
+ 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> ProjectToLDto => p23 => new ComplexLDto()
+ {
+ Name = p23.Name,
+ Address = p23.Address,
+ SupportPhone = p23.SupportPhone,
+ Users = p23.Users.Select(p24 => new ComplexUserSDto()
+ {
+ UserId = p24.UserId,
+ ComplexId = p24.ComplexId,
+ Id = p24.Id
+ }).ToList(),
+ Id = p23.Id
+ };
+
+ private static List funcMain1(List p10)
{
if (p10 == null)
{
return null;
}
- Complex result = p11 ?? new Complex();
+ List result = new List(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> ProjectLDtoToComplex => p12 => new Complex()
+
+ private static List funcMain2(List p13, List 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 result = new List(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> ProjectToLDto => p16 => new ComplexLDto()
+
+ private static List funcMain3(List p18)
{
- Name = p16.Name,
- Address = p16.Address,
- SupportPhone = p16.SupportPhone,
- Id = p16.Id
- };
+ if (p18 == null)
+ {
+ return null;
+ }
+ List result = new List(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 funcMain4(List p21, List p22)
+ {
+ if (p21 == null)
+ {
+ return null;
+ }
+ List result = new List(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;
+
+ }
}
}
\ No newline at end of file
diff --git a/Brizco.Domain/Models/Settings/SiteSettings.cs b/Brizco.Domain/Models/Settings/SiteSettings.cs
index 5189414..b7b6154 100644
--- a/Brizco.Domain/Models/Settings/SiteSettings.cs
+++ b/Brizco.Domain/Models/Settings/SiteSettings.cs
@@ -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
{