feat: introduce Shared.Contracts for account management and refactor related services

This commit is contained in:
2025-12-13 13:48:05 +03:30
parent c059066b13
commit 9469a5f76e
50 changed files with 520 additions and 1622 deletions

View File

@@ -4,10 +4,7 @@
using GozareshgirProgramManager.Application._Common.Interfaces;
using GozareshgirProgramManager.Domain.CustomerAgg;
using GozareshgirProgramManager.Domain.ProjectAgg.Entities;
using GozareshgirProgramManager.Domain.RoleAgg.Entities;
using GozareshgirProgramManager.Domain.RoleUserAgg;
using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities;
using GozareshgirProgramManager.Domain.UserAgg.Entities;
using GozareshgirProgramManager.Domain.SkillAgg.Entities;
using Microsoft.EntityFrameworkCore;

View File

@@ -1,50 +0,0 @@
using GozareshgirProgramManager.Domain.UserAgg.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace GozareshgirProgramManager.Infrastructure.Persistence.Mappings;
public class RefreshTokenMapping : IEntityTypeConfiguration<UserRefreshToken>
{
public void Configure(EntityTypeBuilder<UserRefreshToken> builder)
{
builder.ToTable("UserRefreshTokens");
builder.HasKey(x => x.Id);
builder.Property(x => x.Token)
.HasMaxLength(500)
.IsRequired();
builder.Property(x => x.ExpiresAt)
.IsRequired();
builder.Property(x => x.RevokedAt)
.IsRequired(false);
builder.Property(x => x.IpAddress)
.HasMaxLength(50)
.IsRequired(false);
builder.Property(x => x.UserAgent)
.HasMaxLength(500)
.IsRequired(false);
builder.Property(x => x.UserId)
.IsRequired();
// رابطه با User
builder.HasOne(x => x.User)
.WithMany(u => u.RefreshTokens)
.HasForeignKey(x => x.UserId)
.OnDelete(DeleteBehavior.Cascade);
// Index برای بهینه‌سازی جستجو
builder.HasIndex(x => x.Token)
.IsUnique();
builder.HasIndex(x => x.UserId);
builder.HasIndex(x => x.ExpiresAt);
}
}

View File

@@ -1,23 +0,0 @@
using GozareshgirProgramManager.Domain.RoleAgg.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace GozareshgirProgramManager.Infrastructure.Persistence.Mappings;
public class RoleMapping : IEntityTypeConfiguration<Role>
{
public void Configure(EntityTypeBuilder<Role> builder)
{
builder.ToTable("PmRoles");
builder.HasKey(x => x.Id);
builder.Property(x => x.RoleName).HasMaxLength(100).IsRequired();
builder.OwnsMany(x => x.Permissions, navigationBuilder =>
{
navigationBuilder.HasKey(x => x.Id);
navigationBuilder.ToTable("PmRolePermissions");
navigationBuilder.WithOwner(x => x.Role);
});
}
}

View File

@@ -1,34 +0,0 @@
using GozareshgirProgramManager.Domain.UserAgg.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace GozareshgirProgramManager.Infrastructure.Persistence.Mappings;
public class UserMapping :IEntityTypeConfiguration<User>
{
public void Configure(EntityTypeBuilder<User> builder)
{
builder.ToTable("Users");
builder.HasKey(x => x.Id);
builder.Property(x => x.FullName).HasMaxLength(100).IsRequired();
builder.Property(x => x.UserName).HasMaxLength(100).IsRequired();
builder.Property(x => x.Password).HasMaxLength(1000).IsRequired();
builder.Property(x => x.ProfilePhotoPath).HasMaxLength(500).IsRequired(false);
builder.Property(x => x.Mobile).HasMaxLength(20).IsRequired();
builder.Property(x => x.Email).HasMaxLength(150).IsRequired(false); ;
builder.Property(x => x.VerifyCode).HasMaxLength(10).IsRequired(false);
builder.OwnsMany(x => x.RoleUser, navigationBuilder =>
{
navigationBuilder.HasKey(x => x.Id);
navigationBuilder.ToTable("RoleUsers");
navigationBuilder.WithOwner(x => x.User);
});
builder.HasMany(x=>x.RefreshTokens)
.WithOne(x=>x.User)
.HasForeignKey(x=>x.UserId)
.OnDelete(DeleteBehavior.Cascade);
}
}

View File

@@ -1,24 +0,0 @@
using GozareshgirProgramManager.Domain.RoleAgg.Entities;
using GozareshgirProgramManager.Domain.RoleAgg.Repositories;
using GozareshgirProgramManager.Infrastructure.Persistence._Common;
using GozareshgirProgramManager.Infrastructure.Persistence.Context;
using Microsoft.EntityFrameworkCore;
namespace GozareshgirProgramManager.Infrastructure.Persistence.Repositories;
public class RoleRepository : RepositoryBase<long, Role>, IRoleRepository
{
private readonly ProgramManagerDbContext _context;
public RoleRepository(ProgramManagerDbContext context) : base(context)
{
_context = context;
}
public async Task<Role?> GetByGozareshgirRoleIdAsync(long? gozareshgirRolId)
{
return await _context.Roles.FirstOrDefaultAsync(x => x.GozareshgirRoleId == gozareshgirRolId);
}
}

View File

@@ -1,19 +1,22 @@
using GozareshgirProgramManager.Application.Modules.SalaryPaymentSettings.Queries.GetSalarySettingToEdit;
using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.DTOs;
using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.DTOs;
using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities;
using GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Repositories;
using GozareshgirProgramManager.Infrastructure.Persistence._Common;
using GozareshgirProgramManager.Infrastructure.Persistence.Context;
using Microsoft.EntityFrameworkCore;
using Shared.Contracts.Account;
namespace GozareshgirProgramManager.Infrastructure.Persistence.Repositories;
public class SalaryPaymentSettingRepository : RepositoryBase<long, SalaryPaymentSetting>, ISalaryPaymentSettingRepository
{
private readonly ProgramManagerDbContext _context;
public SalaryPaymentSettingRepository(ProgramManagerDbContext context) : base(context)
private readonly IAccountQueryService _accountQueryService;
public SalaryPaymentSettingRepository(ProgramManagerDbContext context, IAccountQueryService accountQueryService) : base(context)
{
_context = context;
_accountQueryService = accountQueryService;
}
@@ -25,31 +28,36 @@ public class SalaryPaymentSettingRepository : RepositoryBase<long, SalaryPayment
public async Task<List<UserSalarySettingDto>> GetAllSettings(List<long> userIdList)
{
_context.SalaryPaymentSettings.AsNoTracking();
var query = await _context.SalaryPaymentSettings.Where(s=> userIdList.Contains(s.AccountId))
.Join(_context.Users.AsNoTracking(),
setting => setting.AccountId,
user => user.Id,
(setting, user) => new { setting, user }
)
.Select(x => new UserSalarySettingDto
{
UserId = x.user.Id,
HolidayWorking = x.setting!.HolidayWorking,
FullName = x.user.FullName,
MonthlySalary = x.setting.MonthlySalary,
WorkingHoursListDto = x.setting.WorkingHoursList
.Where(wh => wh.IsActiveDay)
.Select(wh => new WorkingHoursListDto()
{
ShiftDuration = wh.ShiftDuration,
PersianDayOfWeek = wh.PersianDayOfWeek
}).ToList()
})
// دریافت تنظیمات حقوق
var settings = await _context.SalaryPaymentSettings
.AsNoTracking()
.Where(s => userIdList.Contains(s.AccountId))
.ToListAsync();
return query;
// دریافت اطلاعات پایه کاربران از ACL
var accountIds = settings.Select(s => s.AccountId).Distinct().ToList();
var accounts = await _accountQueryService.GetProgramManagerAccountListAsync(accountIds);
var accountDictionary = accounts.ToDictionary(a => a.Id, a => a);
// ترکیب داده‌ها
var result = settings.Select(setting => new UserSalarySettingDto
{
UserId = setting.AccountId,
HolidayWorking = setting.HolidayWorking,
FullName = accountDictionary.ContainsKey(setting.AccountId)
? accountDictionary[setting.AccountId].Username
: "Unknown",
MonthlySalary = setting.MonthlySalary,
WorkingHoursListDto = setting.WorkingHoursList
.Where(wh => wh.IsActiveDay)
.Select(wh => new WorkingHoursListDto
{
ShiftDuration = wh.ShiftDuration,
PersianDayOfWeek = wh.PersianDayOfWeek
}).ToList()
}).ToList();
return result;
}
public void RemoveRangeSalarySettings(List<SalaryPaymentSetting> removedItems)

View File

@@ -1,20 +0,0 @@
using System.Linq.Expressions;
using GozareshgirProgramManager.Application._Common.Interfaces;
using GozareshgirProgramManager.Domain.UserAgg.Entities;
using GozareshgirProgramManager.Domain.UserAgg.Repositories;
using GozareshgirProgramManager.Infrastructure.Persistence._Common;
using GozareshgirProgramManager.Infrastructure.Persistence.Context;
using Microsoft.EntityFrameworkCore;
namespace GozareshgirProgramManager.Infrastructure.Persistence.Repositories;
public class UserRefreshTokenRepository : RepositoryBase<Guid, UserRefreshToken>, IUserRefreshTokenRepository
{
private readonly ProgramManagerDbContext _context;
public UserRefreshTokenRepository(ProgramManagerDbContext context) : base(context)
{
_context = context;
}
}

View File

@@ -1,87 +0,0 @@
using GozareshgirProgramManager.Domain.UserAgg.Entities;
using GozareshgirProgramManager.Domain.UserAgg.Repositories;
using GozareshgirProgramManager.Infrastructure.Persistence._Common;
using GozareshgirProgramManager.Infrastructure.Persistence.Context;
using Microsoft.EntityFrameworkCore;
namespace GozareshgirProgramManager.Infrastructure.Persistence.Repositories;
public class UserRepository : RepositoryBase<long, User>, IUserRepository
{
private readonly ProgramManagerDbContext _context;
public UserRepository(ProgramManagerDbContext context) : base(context)
{
_context = context;
}
public Task<User?> GetByIdAsync(long id)
{
throw new NotImplementedException();
}
public async Task<User?> GetByGozareshgirAccountId(long accountId)
{
return await _context.Users.FirstOrDefaultAsync(x => x.AccountId == accountId);
}
public Task<User?> GetByEmailAsync(string email)
{
throw new NotImplementedException();
}
public Task<User?> GetByMobileAsync(string mobile)
{
throw new NotImplementedException();
}
public Task<IEnumerable<User>> GetAllAsync()
{
throw new NotImplementedException();
}
public Task<IEnumerable<User>> GetActiveUsersAsync()
{
throw new NotImplementedException();
}
public Task<User> AddAsync(User user)
{
throw new NotImplementedException();
}
public void Update(User user)
{
throw new NotImplementedException();
}
public void Delete(User user)
{
throw new NotImplementedException();
}
public Task<bool> ExistsAsync(long id)
{
throw new NotImplementedException();
}
public Task<bool> UsernameExistsAsync(string username)
{
throw new NotImplementedException();
}
public Task<bool> EmailExistsAsync(string email)
{
throw new NotImplementedException();
}
public Task<bool> MobileExistsAsync(string mobile)
{
throw new NotImplementedException();
}
public async Task<User?> GetUserWithRolesByIdAsync(long userId, CancellationToken cancellationToken)
{
return await _context.Users.Include(x => x.RoleUser)
.FirstOrDefaultAsync(x=>x.Id == userId, cancellationToken);
}
}