diff --git a/Brizco.Api/Controllers/ActivityController.cs b/Brizco.Api/Controllers/ActivityController.cs index bc5bd51..e116c04 100644 --- a/Brizco.Api/Controllers/ActivityController.cs +++ b/Brizco.Api/Controllers/ActivityController.cs @@ -17,6 +17,10 @@ public class ActivityController : ICarterModule .WithDisplayName("GetActivity") .HasApiVersion(1.0); + group.MapGet("done/{id:guid}", DoneActivityAsync) + .WithDisplayName("DoneActivity") + .HasApiVersion(1.0); + //group.MapPost("", Post) // .AllowAnonymous() // .HasApiVersion(1.0); @@ -35,7 +39,10 @@ public class ActivityController : ICarterModule => TypedResults.Ok(await sender.Send(new GetActivitiesQuery(page), cancellationToken)); // GET:Get An Entity By Id - public async Task GetAsync(Guid id, ISender sender, CancellationToken cancellationToken) + public async Task GetAsync(Guid id, IActivityService activityService, CancellationToken cancellationToken) + => TypedResults.Ok(await activityService.DoneActivityAsync(id,cancellationToken)); + + public async Task DoneActivityAsync(Guid id, ISender sender, CancellationToken cancellationToken) => TypedResults.Ok(await sender.Send(new GetActivityQuery(id), cancellationToken)); //// POST:Create Entity diff --git a/Brizco.Api/Controllers/HomeController.cs b/Brizco.Api/Controllers/HomeController.cs index 4d6a9be..ccceff7 100644 --- a/Brizco.Api/Controllers/HomeController.cs +++ b/Brizco.Api/Controllers/HomeController.cs @@ -9,6 +9,6 @@ public class HomeController : Controller [HttpGet] public IActionResult Index() { - return View("Index", new IndexModel()); + return View("Index", new IndexModel()); } } diff --git a/Brizco.Common/Models/Api/AccessToken.cs b/Brizco.Common/Models/Api/AccessToken.cs index 413759d..8979867 100644 --- a/Brizco.Common/Models/Api/AccessToken.cs +++ b/Brizco.Common/Models/Api/AccessToken.cs @@ -48,4 +48,30 @@ namespace Brizco.Common.Models.Api public string BearerToken => $"Bearer {access_token}"; public List Permissions { get; set; } } + + + public class AccessToken + { + public AccessToken() + { + } + + public AccessToken(JwtSecurityToken securityToken) + { + access_token = new JwtSecurityTokenHandler().WriteToken(securityToken); + token_type = "Bearer"; + expires_in = (int)(securityToken.ValidTo - DateTime.UtcNow).TotalSeconds; + } + + public string access_token { get; set; } = string.Empty; + public string ig_access_token { get; set; } = string.Empty; + public string refresh_token { get; set; } = string.Empty; + public string token_type { get; set; } = string.Empty; + public int expires_in { get; set; } + + public TUser User { get; set; } + public string BearerToken => $"Bearer {access_token}"; + public List Permissions { get; set; } + public List Roles { get; set; } = new(); + } } \ No newline at end of file diff --git a/Brizco.Core/BaseServices/Abstracts/IJwtService.cs b/Brizco.Core/BaseServices/Abstracts/IJwtService.cs index 3354d8d..4a8840f 100644 --- a/Brizco.Core/BaseServices/Abstracts/IJwtService.cs +++ b/Brizco.Core/BaseServices/Abstracts/IJwtService.cs @@ -7,6 +7,7 @@ public interface IJwtService : IScopedDependency Task> Generate(TUser user) where TUser : ApplicationUser; Task> Generate(TUser user, Guid complexId, Guid roleId) where TUser : ApplicationUser; + Task> Generate(TUser user, Guid complexId, Guid roleId) where TUser : ApplicationUser; Task> Generate(TUser user, Guid complexId) where TUser : ApplicationUser; Task> Generate(TUser user) where TUser : ApplicationUser; } \ No newline at end of file diff --git a/Brizco.Core/BaseServices/JwtService.cs b/Brizco.Core/BaseServices/JwtService.cs index 8608a37..da44f99 100644 --- a/Brizco.Core/BaseServices/JwtService.cs +++ b/Brizco.Core/BaseServices/JwtService.cs @@ -63,6 +63,16 @@ public class JwtService : IJwtService token.Permissions = claims.Where(c => c.Type == "Permission").Select(c => c.Value).ToList(); return token; } + + public async Task> Generate(TUser user, Guid complexId, Guid roleId) 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, Guid complexId) where TUser : ApplicationUser { var tokenId = StringExtensions.GetId(8); @@ -122,6 +132,27 @@ public class JwtService : IJwtService 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 { diff --git a/Brizco.Core/CoreServices/Abstracts/IAccountService.cs b/Brizco.Core/CoreServices/Abstracts/IAccountService.cs index e9164f1..76faf9e 100644 --- a/Brizco.Core/CoreServices/Abstracts/IAccountService.cs +++ b/Brizco.Core/CoreServices/Abstracts/IAccountService.cs @@ -2,10 +2,10 @@ public interface IAccountService : IScopedDependency { - public Task> LoginWithPasswordAsync(string userName, string password, CancellationToken cancellationToken); - public Task> LoginWithVerifyCodeAsync(string userName, string verifyCode, CancellationToken cancellationToken); + 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); + public Task> CompleteComplexSignUpAsync(SignUpRequestDto requestDto, CancellationToken cancellationToken); } \ No newline at end of file diff --git a/Brizco.Core/CoreServices/AccountService.cs b/Brizco.Core/CoreServices/AccountService.cs index 611e808..f3b564c 100644 --- a/Brizco.Core/CoreServices/AccountService.cs +++ b/Brizco.Core/CoreServices/AccountService.cs @@ -1,5 +1,7 @@ using Brizco.Domain.Entities.Complex; using Brizco.Domain.Mappers; +using System.Linq; +using Mapster; namespace Brizco.Core.CoreServices; @@ -77,11 +79,11 @@ public class AccountService : IAccountService user = await _userService.CreateUserAsync(phoneNumber); var token = await _userManager.GenerateTwoFactorTokenAsync(user, "Phone"); - //await _smsService.SendVerifyCodeAsync(newPhoneNumber, token); + await _smsService.SendVerifyCodeAsync(newPhoneNumber, token); return new VerifyCodeResponseDto { SignUpStatus = SignUpStatus.StartSignOn }; } - public async Task> LoginWithPasswordAsync(string userName, string password, CancellationToken cancellationToken) + public async Task> LoginWithPasswordAsync(string userName, string password, CancellationToken cancellationToken) { var result = await _userSignInManager.PasswordSignInAsync(userName, password, false, false); if (!result.Succeeded) @@ -94,7 +96,7 @@ public class AccountService : IAccountService return await CompleteLogin(admin, cancellationToken); } - public async Task> LoginWithVerifyCodeAsync(string userName, string verifyCode, CancellationToken cancellationToken) + public async Task> LoginWithVerifyCodeAsync(string userName, string verifyCode, CancellationToken cancellationToken) { var user = await _userManager.FindByNameAsync(userName); if (user == null) @@ -116,7 +118,7 @@ public class AccountService : IAccountService return await CompleteLogin(user, cancellationToken); } - public async Task> CompleteComplexSignUpAsync(SignUpRequestDto requestDto, CancellationToken cancellationToken) + public async Task> CompleteComplexSignUpAsync(SignUpRequestDto requestDto, CancellationToken cancellationToken) { if (_currentUserService.UserId == null) throw new AppException("User Id is null"); @@ -155,16 +157,13 @@ public class AccountService : IAccountService } - private async Task> CompleteLogin(ApplicationUser user, CancellationToken cancellationToken) + private async Task> CompleteLogin(ApplicationUser user, CancellationToken cancellationToken) { - AccessToken jwt; + AccessToken jwt; if (user.SelectedComplexUserRoleId != Guid.Empty) { - var complexUserRole = await _repositoryWrapper.SetRepository() - .TableNoTracking - .Where(c => c.Id == user.SelectedComplexUserRoleId) - .Select(ComplexUserRoleMapper.ProjectToSDto) - .FirstOrDefaultAsync(cancellationToken); + var userComplexRoles = await _userService.GetUserRolesAsync(user.Id, cancellationToken); + var complexUserRole = userComplexRoles.FirstOrDefault(c => c.Id == user.SelectedComplexUserRoleId); var complexUser = await _repositoryWrapper.SetRepository() .TableNoTracking @@ -172,9 +171,10 @@ public class AccountService : IAccountService .Select(ComplexUserMapper.ProjectToSDto) .FirstOrDefaultAsync( cancellationToken); - jwt = await _jwtService.Generate(user, complexUser!.ComplexId, complexUserRole!.RoleId); + jwt = await _jwtService.Generate(user, complexUser!.ComplexId, complexUserRole!.RoleId); jwt.User.SelectedComplexName = complexUser.ComplexName; jwt.User.SelectedRoleName = complexUserRole.RoleName; + jwt.Roles = userComplexRoles; } else { @@ -185,7 +185,7 @@ public class AccountService : IAccountService .Select(ComplexUserMapper.ProjectToSDto) .FirstOrDefaultAsync(cancellationToken); if (complexUser == null) - return await _jwtService.Generate(user); + return (await _jwtService.Generate(user)).Adapt>(); var complexUserRole = await _repositoryWrapper.SetRepository() .TableNoTracking @@ -201,12 +201,13 @@ public class AccountService : IAccountService user.SelectedComplexUserRoleId = complexUserRole.Id; await _userManager.UpdateAsync(user); - jwt = await _jwtService.Generate(user, complexUser.ComplexId, complexUserRole.RoleId); + jwt = (await _jwtService.Generate(user, complexUser.ComplexId, complexUserRole.RoleId)).Adapt>(); jwt.User.SelectedComplexName = complexUser.ComplexName; jwt.User.SelectedRoleName = complexUserRole.RoleName; + jwt.Roles = new List { complexUserRole }; } else - jwt = await _jwtService.Generate(user); + jwt = (new AccessToken()).Adapt>(); } diff --git a/Brizco.Core/EntityServices/Abstracts/IActivityService.cs b/Brizco.Core/EntityServices/Abstracts/IActivityService.cs index 7901a24..feb2402 100644 --- a/Brizco.Core/EntityServices/Abstracts/IActivityService.cs +++ b/Brizco.Core/EntityServices/Abstracts/IActivityService.cs @@ -3,4 +3,5 @@ public interface IActivityService : IScopedDependency { Task CreateActivitiesByShiftPlan(Guid shiftPlanId, CancellationToken cancellationToken); + Task DoneActivityAsync(Guid activityId, CancellationToken cancellationToken); } \ No newline at end of file diff --git a/Brizco.Core/EntityServices/Abstracts/IUserService.cs b/Brizco.Core/EntityServices/Abstracts/IUserService.cs index d4f0398..e551e1b 100644 --- a/Brizco.Core/EntityServices/Abstracts/IUserService.cs +++ b/Brizco.Core/EntityServices/Abstracts/IUserService.cs @@ -4,6 +4,7 @@ public interface IUserService : IScopedDependency { Task GetUserProfileAsync(CancellationToken cancellationToken); Task> GetUserRolesAsync(CancellationToken cancellationToken); + Task> GetUserRolesAsync(Guid userId, CancellationToken cancellationToken); Task> GetUsersAsync(int page = 0, CancellationToken cancellationToken = default); Task GetUserAsync(Guid userId); Task CreateUserAsync(string phoneNumber); diff --git a/Brizco.Core/EntityServices/ActivityService.cs b/Brizco.Core/EntityServices/ActivityService.cs index 5bf6e6c..34cab23 100644 --- a/Brizco.Core/EntityServices/ActivityService.cs +++ b/Brizco.Core/EntityServices/ActivityService.cs @@ -15,11 +15,28 @@ public class ActivityService : IActivityService _mediator = mediator; _repositoryWrapper = repositoryWrapper; } + + + public async Task DoneActivityAsync(Guid activityId, CancellationToken cancellationToken) + { + var activity = await _repositoryWrapper.SetRepository() + .TableNoTracking + .FirstOrDefaultAsync(a => a.Id == activityId, cancellationToken); + if (activity == null) + throw new AppException("Activity not found ", ApiResultStatusCode.NotFound); + activity.DoneActivity(); + _repositoryWrapper.SetRepository() + .Update(activity); + await _repositoryWrapper.SaveChangesAsync(cancellationToken); + return true; + } + public async Task CreateActivitiesByShiftPlan(Guid shiftPlanId,CancellationToken cancellationToken) { var shiftPlan = await _mediator.Send(new GetShiftPlanQuery(shiftPlanId), cancellationToken); if (shiftPlan.Id == Guid.Empty) return false; + var tasks = await _repositoryWrapper.SetRepository() .ExecuteCommand( $@"SELECT t.""Id"", t.""Amount"", t.""AmountType"", t.""ComplexId"", @@ -46,25 +63,15 @@ GROUP BY t.""Id""").ToListAsync(cancellationToken); .TableNoTracking .Where(tp => tp.TaskId == task.Id) .ToListAsync(cancellationToken); + foreach (var taskPosition in taskPositions) { var fundedUser = shiftPlanPositions.FirstOrDefault(spu => spu.PositionId == taskPosition.PositionId); if (fundedUser != null) { - var activity = Activity.Create(ActivityStatus.Created, - DateTime.MinValue, - string.Empty, - task.Title, - task.Description, - task.Type, - task.IsDisposable, - task.SetFor, - task.HasDisposed, - task.Amount, - task.AmountType, - task.ComplexId, - task.ScheduleType); - activity.SetUser(fundedUser.UserId); + await _mediator.Send(new CreateActivityCommand(task.Type, task.Title, task.Description, task.IsDisposable, + task.SetFor, task.HasDisposed, task.Amount, task.AmountType, + task.ScheduleType, shiftPlan.ShiftId, new List { fundedUser.UserId }),cancellationToken); } } } diff --git a/Brizco.Core/EntityServices/ShiftPlanService.cs b/Brizco.Core/EntityServices/ShiftPlanService.cs index cbbc625..23621e9 100644 --- a/Brizco.Core/EntityServices/ShiftPlanService.cs +++ b/Brizco.Core/EntityServices/ShiftPlanService.cs @@ -21,7 +21,7 @@ public class ShiftPlanService : IShiftPlanService public async Task CreateAsync(CreateShiftPlanCommand createShiftPlanCommand, CancellationToken cancellationToken) { var shiftPlan = await _sender.Send(createShiftPlanCommand, cancellationToken); - _activityService.CreateActivitiesByShiftPlan(shiftPlan.Id, cancellationToken); + await _activityService.CreateActivitiesByShiftPlan(shiftPlan.Id, cancellationToken); return true; } } \ No newline at end of file diff --git a/Brizco.Core/EntityServices/UserService.cs b/Brizco.Core/EntityServices/UserService.cs index 2925597..acf8a09 100644 --- a/Brizco.Core/EntityServices/UserService.cs +++ b/Brizco.Core/EntityServices/UserService.cs @@ -49,7 +49,7 @@ public class UserService : IUserService userSDto.SelectedComplexName = complexUserRole!.ComplexName; userSDto.SelectedRoleName = complexUserRole!.RoleName; - var role = await _roleManager.FindByNameAsync(complexUserRole.RoleName); + var role = await _roleManager.FindByIdAsync(complexUserRole.RoleId.ToString()); if (role != null) { var roleClaims = await _roleManager.GetClaimsAsync(role); @@ -93,6 +93,37 @@ public class UserService : IUserService return response; } + + public async Task> GetUserRolesAsync(Guid userId,CancellationToken cancellationToken) + { + var user = await _userManager.FindByIdAsync(userId.ToString()); + if (user == null) + throw new AppException("User NotFound", ApiResultStatusCode.NotFound); + var response = new List(); + var complexUsers = await _repositoryWrapper.SetRepository() + .TableNoTracking + .Where(mcu => mcu.UserId == user.Id) + .Select(ComplexUserMapper.ProjectToSDto) + .ToListAsync(cancellationToken); + if (complexUsers.Count == 0) + return response; + + foreach (var complexUser in complexUsers) + { + var complexUserRoles = await _repositoryWrapper.SetRepository() + .TableNoTracking + .Where(c => c.ComplexUserId == complexUser.Id) + .Select(ComplexUserRoleMapper.ProjectToSDto) + .ToListAsync(cancellationToken); + foreach (var userRole in complexUserRoles) + { + userRole.ComplexName = complexUser.ComplexName; + response.Add(userRole); + } + } + + return response; + } public async Task> GetUsersAsync(int page = 0, CancellationToken cancellationToken = default) { if (_currentUserService.ComplexId.IsNullOrEmpty()) diff --git a/Brizco.Domain/CommandQueries/Commands/ActivityCommands.cs b/Brizco.Domain/CommandQueries/Commands/ActivityCommands.cs index 0a6711c..cf76a78 100644 --- a/Brizco.Domain/CommandQueries/Commands/ActivityCommands.cs +++ b/Brizco.Domain/CommandQueries/Commands/ActivityCommands.cs @@ -1,9 +1,6 @@ namespace Brizco.Domain.CommandQueries.Commands; public sealed record CreateActivityCommand( - ActivityStatus Status, - DateTime DoneAt, - string PerformanceDescription, TaskType Type, string Title, string Description, @@ -13,9 +10,8 @@ public sealed record CreateActivityCommand( int Amount, PurchaseAmountType AmountType, TaskScheduleType ScheduleType, - List Routines, - List Shifts, - List Positions) : IRequest; + Guid ShiftId, + List UserIds) : IRequest; public sealed record UpdateActivityCommand(Guid Id, ActivityStatus Status, @@ -30,9 +26,7 @@ public sealed record UpdateActivityCommand(Guid Id, int Amount, PurchaseAmountType AmountType, TaskScheduleType ScheduleType, - List Routines, - List Shifts, - List Positions) : IRequest; + List UserIds) : IRequest; public sealed record DeleteActivityCommand(Guid Id) diff --git a/Brizco.Domain/Entities/Task/Aggregate.Task.cs b/Brizco.Domain/Entities/Task/Aggregate.Task.cs index 8061d08..fffd81b 100644 --- a/Brizco.Domain/Entities/Task/Aggregate.Task.cs +++ b/Brizco.Domain/Entities/Task/Aggregate.Task.cs @@ -128,6 +128,12 @@ public partial class Activity scheduleType); } + public void SetShift(Guid shiftId) + { + this.ShiftId = shiftId; + } + + public void SetUser(Guid userId) { this.UserId = userId; @@ -137,5 +143,6 @@ public partial class Activity { DoneAt = DateTime.UtcNow; IsDone = true; + Status = ActivityStatus.InProgress; } } \ No newline at end of file diff --git a/Brizco.Infrastructure/Services/SmsService.cs b/Brizco.Infrastructure/Services/SmsService.cs index 5d43579..16b0af2 100644 --- a/Brizco.Infrastructure/Services/SmsService.cs +++ b/Brizco.Infrastructure/Services/SmsService.cs @@ -24,7 +24,7 @@ public class SmsService : ISmsService public async Task SendVerifyCodeAsync(string phoneNumber, string verifyCode) { - var rest = await _restApiWrapper.KaveNegarRestApi.SendLookUp(_siteSettings.KaveNegarApiKey, phoneNumber, verifyCode, null, null, null, "login"); + var rest = await _restApiWrapper.KaveNegarRestApi.SendLookUp(_siteSettings.KaveNegarApiKey, phoneNumber, verifyCode, null, null, null, "login-brizco"); if (rest.Return.status != 200) throw new BaseApiException(ApiResultStatusCode.SendSmsError, rest.Return.message); diff --git a/Brizco.Repository/Handlers/Activity/CreateActivityCommandHandler.cs b/Brizco.Repository/Handlers/Activity/CreateActivityCommandHandler.cs index 95d3cb2..281a679 100644 --- a/Brizco.Repository/Handlers/Activity/CreateActivityCommandHandler.cs +++ b/Brizco.Repository/Handlers/Activity/CreateActivityCommandHandler.cs @@ -20,11 +20,11 @@ public class CreateActivityCommandHandler : IRequestHandler().Add(task); + _repositoryWrapper.SetRepository().Add(activity); await _repositoryWrapper.SaveChangesAsync(cancellationToken); await _repositoryWrapper.CommitAsync(cancellationToken); - return task.AdaptToLDto(); + return activity.AdaptToLDto(); } catch (Exception) {