diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserDelegationRepository.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserDelegationRepository.cs new file mode 100644 index 0000000000..c60b998b64 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserDelegationRepository.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; + +namespace Volo.Abp.Identity; + +public interface IIdentityUserDelegationRepository: IBasicRepository +{ + Task> GetListAsync( + Guid? sourceUserId, + Guid? targetUserId, + CancellationToken cancellationToken = default); + + Task FindAsync( + Guid sourceUserId, + Guid targetUserId, + CancellationToken cancellationToken = default); +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserDelegation.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserDelegation.cs new file mode 100644 index 0000000000..8cab00f882 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserDelegation.cs @@ -0,0 +1,41 @@ +using System; +using Volo.Abp.Domain.Entities; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.Identity; + +public class IdentityUserDelegation : BasicAggregateRoot, IMultiTenant +{ + public virtual Guid? TenantId { get; protected set; } + + public virtual Guid SourceUserId { get; protected set; } + + public virtual Guid TargetUserId { get; protected set; } + + public virtual DateTime StartTime { get; protected set; } + + public virtual DateTime EndTime { get; protected set; } + + /// + /// Initializes a new instance of . + /// + protected IdentityUserDelegation() + { + } + + public IdentityUserDelegation( + Guid id, + Guid sourceUserId, + Guid targetUserId, + DateTime startTime, + DateTime endTime, + Guid? tenantId = null) + : base(id) + { + TenantId = tenantId; + SourceUserId = sourceUserId; + TargetUserId = targetUserId; + StartTime = startTime; + EndTime = endTime; + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserDelegationManager.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserDelegationManager.cs new file mode 100644 index 0000000000..4d08385835 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserDelegationManager.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Services; + +namespace Volo.Abp.Identity; + +public class IdentityUserDelegationManager : DomainService +{ + protected IIdentityUserDelegationRepository IdentityUserDelegationRepository { get; } + + public IdentityUserDelegationManager(IIdentityUserDelegationRepository identityUserDelegationRepository) + { + IdentityUserDelegationRepository = identityUserDelegationRepository; + } + + public virtual async Task> GetListAsync(Guid? sourceUserId = null, Guid? targetUserId = null, CancellationToken cancellationToken = default) + { + return await IdentityUserDelegationRepository.GetListAsync(sourceUserId, targetUserId, cancellationToken: cancellationToken); + } + + public virtual async Task DeleteDelegationAsync(Guid id, Guid sourceUserId, CancellationToken cancellationToken = default) + { + var delegation = await IdentityUserDelegationRepository.FindAsync(id, cancellationToken: cancellationToken); + + if (delegation != null && delegation.SourceUserId == sourceUserId) + { + await IdentityUserDelegationRepository.DeleteAsync(delegation, cancellationToken: cancellationToken); + } + } + + public virtual async Task IsDelegatedAsync(Guid sourceUserId, Guid targetUserId, CancellationToken cancellationToken = default) + { + return await IdentityUserDelegationRepository.FindAsync(sourceUserId, targetUserId, cancellationToken: cancellationToken) != null; + } + + public virtual Task IsExpiredAsync(IdentityUserDelegation userDelegation) + { + return Task.FromResult(userDelegation.EndTime <= Clock.Now); + } + + public virtual async Task IsValidAsync(IdentityUserDelegation userDelegation) + { + return userDelegation.StartTime <= Clock.Now && !await IsExpiredAsync(userDelegation); + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/AbpIdentityEntityFrameworkCoreModule.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/AbpIdentityEntityFrameworkCoreModule.cs index 4bfa96d253..a58a73a996 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/AbpIdentityEntityFrameworkCoreModule.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/AbpIdentityEntityFrameworkCoreModule.cs @@ -19,6 +19,7 @@ public class AbpIdentityEntityFrameworkCoreModule : AbpModule options.AddRepository(); options.AddRepository(); options.AddRepository(); + options.AddRepository(); }); } } diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserDelegationRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserDelegationRepository.cs new file mode 100644 index 0000000000..4f455c2d68 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserDelegationRepository.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +namespace Volo.Abp.Identity.EntityFrameworkCore; + +public class EfCoreIdentityUserDelegationRepository : EfCoreRepository, IIdentityUserDelegationRepository +{ + public EfCoreIdentityUserDelegationRepository(IDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } + + public async Task> GetListAsync(Guid? sourceUserId, Guid? targetUserId, CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .AsNoTracking() + .WhereIf(sourceUserId.HasValue, x => x.SourceUserId == sourceUserId) + .WhereIf(targetUserId.HasValue, x => x.TargetUserId == targetUserId) + .ToListAsync(cancellationToken: cancellationToken); + } + + public async Task FindAsync(Guid sourceUserId, Guid targetUserId, CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .AsNoTracking() + .FirstOrDefaultAsync(x => + x.SourceUserId == sourceUserId && + x.TargetUserId == targetUserId + , cancellationToken: GetCancellationToken(cancellationToken)); + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IIdentityDbContext.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IIdentityDbContext.cs index e84b2811c5..2f409a61b2 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IIdentityDbContext.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IIdentityDbContext.cs @@ -18,4 +18,6 @@ public interface IIdentityDbContext : IEfCoreDbContext DbSet SecurityLogs { get; } DbSet LinkUsers { get; } + + DbSet UserDelegations { get; } } diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContext.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContext.cs index bc2b4dd4b0..79adece5e1 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContext.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContext.cs @@ -22,6 +22,8 @@ public class IdentityDbContext : AbpDbContext, IIdentityDbCon public DbSet LinkUsers { get; set; } + public DbSet UserDelegations { get; set; } + public IdentityDbContext(DbContextOptions options) : base(options) { diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs index 472581fdbd..7520b12e26 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs @@ -270,6 +270,20 @@ public static class IdentityDbContextModelBuilderExtensions }); } + builder.Entity(b => + { + b.ToTable(AbpIdentityDbProperties.DbTablePrefix + "UserDelegations", AbpIdentityDbProperties.DbSchema); + + b.ConfigureByConvention(); + + b.HasIndex(x => new { + x.SourceUserId, + x.TargetUserId, + }).IsUnique(); + + b.ApplyObjectExtensionMappings(); + }); + builder.TryConfigureObjectExtensions(); } } diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContext.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContext.cs index 1acc952024..90118a534e 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContext.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContext.cs @@ -19,6 +19,8 @@ public class AbpIdentityMongoDbContext : AbpMongoDbContext, IAbpIdentityMongoDbC public IMongoCollection LinkUsers => Collection(); + public IMongoCollection UserDelegations => Collection(); + protected override void CreateModel(IMongoModelBuilder modelBuilder) { base.CreateModel(modelBuilder); diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContextExtensions.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContextExtensions.cs index 4816664d68..52d84a7478 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContextExtensions.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContextExtensions.cs @@ -37,5 +37,10 @@ public static class AbpIdentityMongoDbContextExtensions { b.CollectionName = AbpIdentityDbProperties.DbTablePrefix + "LinkUsers"; }); + + builder.Entity(b => + { + b.CollectionName = AbpIdentityDbProperties.DbTablePrefix + "LinkUsers"; + }); } } diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbModule.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbModule.cs index 85fc619180..35c81b25bb 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbModule.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbModule.cs @@ -20,6 +20,7 @@ public class AbpIdentityMongoDbModule : AbpModule options.AddRepository(); options.AddRepository(); options.AddRepository(); + options.AddRepository(); }); } } diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/IAbpIdentityMongoDbContext.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/IAbpIdentityMongoDbContext.cs index ad2ae429e1..39bcc23b50 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/IAbpIdentityMongoDbContext.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/IAbpIdentityMongoDbContext.cs @@ -18,4 +18,6 @@ public interface IAbpIdentityMongoDbContext : IAbpMongoDbContext IMongoCollection SecurityLogs { get; } IMongoCollection LinkUsers { get; } + + IMongoCollection UserDelegations { get; } } diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserDelegationRepository.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserDelegationRepository.cs new file mode 100644 index 0000000000..ac9ac753e6 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserDelegationRepository.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using MongoDB.Driver; +using MongoDB.Driver.Linq; +using Volo.Abp.Domain.Repositories.MongoDB; +using Volo.Abp.MongoDB; + +namespace Volo.Abp.Identity.MongoDB; + +public class MongoIdentityUserDelegationRepository : MongoDbRepository, IIdentityUserDelegationRepository +{ + public MongoIdentityUserDelegationRepository(IMongoDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } + + public async Task> GetListAsync(Guid? sourceUserId, Guid? targetUserId, + CancellationToken cancellationToken = default) + { + return await (await GetMongoQueryableAsync(cancellationToken)) + .WhereIf(sourceUserId.HasValue, x => x.SourceUserId == sourceUserId) + .WhereIf(targetUserId.HasValue, x => x.TargetUserId == targetUserId) + .As>() + .ToListAsync(cancellationToken: cancellationToken); + } + + public async Task FindAsync(Guid sourceUserId, Guid targetUserId, CancellationToken cancellationToken = default) + { + return await (await GetMongoQueryableAsync(cancellationToken)) + .FirstOrDefaultAsync(x => + x.SourceUserId == sourceUserId && + x.TargetUserId == targetUserId + , cancellationToken: GetCancellationToken(cancellationToken)); + } +}