diff --git a/lib/Logitar.Identity.EntityFrameworkCore.Relational/DependencyInjectionExtensions.cs b/lib/Logitar.Identity.EntityFrameworkCore.Relational/DependencyInjectionExtensions.cs new file mode 100644 index 0000000..b986eb0 --- /dev/null +++ b/lib/Logitar.Identity.EntityFrameworkCore.Relational/DependencyInjectionExtensions.cs @@ -0,0 +1,48 @@ +using Logitar.EventSourcing.EntityFrameworkCore.Relational; +using Logitar.Identity.Core.ApiKeys; +using Logitar.Identity.Core.Passwords; +using Logitar.Identity.Core.Roles; +using Logitar.Identity.Core.Sessions; +using Logitar.Identity.Core.Tokens; +using Logitar.Identity.Core.Users; +using Logitar.Identity.EntityFrameworkCore.Relational.Repositories; +using Logitar.Identity.EntityFrameworkCore.Relational.Tokens; +using Logitar.Identity.Infrastructure; +using Microsoft.Extensions.DependencyInjection; + +namespace Logitar.Identity.EntityFrameworkCore.Relational; + +public static class DependencyInjectionExtensions +{ + public static IServiceCollection AddLogitarIdentityWithEntityFrameworkCoreRelational(this IServiceCollection services) + { + return services + .AddLogitarEventSourcingWithEntityFrameworkCoreRelational() + .AddLogitarIdentityInfrastructure() + .AddEventHandlers() + .AddMediatR(config => config.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly())) + .AddRepositories() + //.AddTransient() // TODO(fpion): implement + .AddScoped(); + } + + private static IServiceCollection AddEventHandlers(this IServiceCollection services) + { + return services/* + .AddTransient() + .AddTransient() + .AddTransient() + .AddTransient() + .AddTransient()*/; // TODO(fpion): implement + } + + private static IServiceCollection AddRepositories(this IServiceCollection services) + { + return services + .AddScoped() + .AddScoped() + .AddScoped() + .AddScoped() + .AddScoped(); + } +} diff --git a/lib/Logitar.Identity.EntityFrameworkCore.Relational/Entities/ActorEntity.cs b/lib/Logitar.Identity.EntityFrameworkCore.Relational/Entities/ActorEntity.cs index c12cb42..7714be9 100644 --- a/lib/Logitar.Identity.EntityFrameworkCore.Relational/Entities/ActorEntity.cs +++ b/lib/Logitar.Identity.EntityFrameworkCore.Relational/Entities/ActorEntity.cs @@ -1,6 +1,4 @@ -using System.Text; - -namespace Logitar.Identity.EntityFrameworkCore.Relational.Entities; +namespace Logitar.Identity.EntityFrameworkCore.Relational.Entities; public sealed class ActorEntity { diff --git a/lib/Logitar.Identity.EntityFrameworkCore.Relational/Entities/ApiKeyEntity.cs b/lib/Logitar.Identity.EntityFrameworkCore.Relational/Entities/ApiKeyEntity.cs index 489b829..d5e257a 100644 --- a/lib/Logitar.Identity.EntityFrameworkCore.Relational/Entities/ApiKeyEntity.cs +++ b/lib/Logitar.Identity.EntityFrameworkCore.Relational/Entities/ApiKeyEntity.cs @@ -2,7 +2,6 @@ using Logitar.Identity.Core; using Logitar.Identity.Core.ApiKeys; using Logitar.Identity.Core.ApiKeys.Events; -using System.Text.Json; namespace Logitar.Identity.EntityFrameworkCore.Relational.Entities; diff --git a/lib/Logitar.Identity.EntityFrameworkCore.Relational/Entities/OneTimePasswordEntity.cs b/lib/Logitar.Identity.EntityFrameworkCore.Relational/Entities/OneTimePasswordEntity.cs index 7005439..5ff0828 100644 --- a/lib/Logitar.Identity.EntityFrameworkCore.Relational/Entities/OneTimePasswordEntity.cs +++ b/lib/Logitar.Identity.EntityFrameworkCore.Relational/Entities/OneTimePasswordEntity.cs @@ -1,7 +1,6 @@ using Logitar.Identity.Core; using Logitar.Identity.Core.Passwords; using Logitar.Identity.Core.Passwords.Events; -using System.Text.Json; namespace Logitar.Identity.EntityFrameworkCore.Relational.Entities; diff --git a/lib/Logitar.Identity.EntityFrameworkCore.Relational/Entities/RoleEntity.cs b/lib/Logitar.Identity.EntityFrameworkCore.Relational/Entities/RoleEntity.cs index 56ca44e..5f15e04 100644 --- a/lib/Logitar.Identity.EntityFrameworkCore.Relational/Entities/RoleEntity.cs +++ b/lib/Logitar.Identity.EntityFrameworkCore.Relational/Entities/RoleEntity.cs @@ -1,7 +1,6 @@ using Logitar.Identity.Core; using Logitar.Identity.Core.Roles; using Logitar.Identity.Core.Roles.Events; -using System.Text.Json; namespace Logitar.Identity.EntityFrameworkCore.Relational.Entities; diff --git a/lib/Logitar.Identity.EntityFrameworkCore.Relational/Entities/SessionEntity.cs b/lib/Logitar.Identity.EntityFrameworkCore.Relational/Entities/SessionEntity.cs index eb2c33e..734b3dc 100644 --- a/lib/Logitar.Identity.EntityFrameworkCore.Relational/Entities/SessionEntity.cs +++ b/lib/Logitar.Identity.EntityFrameworkCore.Relational/Entities/SessionEntity.cs @@ -2,7 +2,6 @@ using Logitar.Identity.Core; using Logitar.Identity.Core.Sessions; using Logitar.Identity.Core.Sessions.Events; -using System.Text.Json; namespace Logitar.Identity.EntityFrameworkCore.Relational.Entities; diff --git a/lib/Logitar.Identity.EntityFrameworkCore.Relational/Entities/UserEntity.cs b/lib/Logitar.Identity.EntityFrameworkCore.Relational/Entities/UserEntity.cs index 16c7d52..f37e13e 100644 --- a/lib/Logitar.Identity.EntityFrameworkCore.Relational/Entities/UserEntity.cs +++ b/lib/Logitar.Identity.EntityFrameworkCore.Relational/Entities/UserEntity.cs @@ -2,7 +2,6 @@ using Logitar.Identity.Core; using Logitar.Identity.Core.Users; using Logitar.Identity.Core.Users.Events; -using System.Text.Json; namespace Logitar.Identity.EntityFrameworkCore.Relational.Entities; diff --git a/lib/Logitar.Identity.EntityFrameworkCore.Relational/Logitar.Identity.EntityFrameworkCore.Relational.csproj b/lib/Logitar.Identity.EntityFrameworkCore.Relational/Logitar.Identity.EntityFrameworkCore.Relational.csproj index a510800..1f42b70 100644 --- a/lib/Logitar.Identity.EntityFrameworkCore.Relational/Logitar.Identity.EntityFrameworkCore.Relational.csproj +++ b/lib/Logitar.Identity.EntityFrameworkCore.Relational/Logitar.Identity.EntityFrameworkCore.Relational.csproj @@ -45,6 +45,8 @@ + + diff --git a/lib/Logitar.Identity.EntityFrameworkCore.Relational/Repositories/ApiKeyRepository.cs b/lib/Logitar.Identity.EntityFrameworkCore.Relational/Repositories/ApiKeyRepository.cs new file mode 100644 index 0000000..dfe9e78 --- /dev/null +++ b/lib/Logitar.Identity.EntityFrameworkCore.Relational/Repositories/ApiKeyRepository.cs @@ -0,0 +1,68 @@ +using Logitar.EventSourcing; +using Logitar.Identity.Core; +using Logitar.Identity.Core.ApiKeys; +using Logitar.Identity.Core.Roles; + +namespace Logitar.Identity.EntityFrameworkCore.Relational.Repositories; + +public class ApiKeyRepository : Repository, IApiKeyRepository +{ + public ApiKeyRepository(IEventStore eventStore) : base(eventStore) + { + } + + public async Task LoadAsync(ApiKeyId id, CancellationToken cancellationToken) + { + return await LoadAsync(id, isDeleted: null, cancellationToken); + } + public async Task LoadAsync(ApiKeyId id, long? version, CancellationToken cancellationToken) + { + return await LoadAsync(id, version, isDeleted: null, cancellationToken); + } + public async Task LoadAsync(ApiKeyId id, bool? isDeleted, CancellationToken cancellationToken) + { + return await LoadAsync(id, version: null, isDeleted, cancellationToken); + } + public async Task LoadAsync(ApiKeyId id, long? version, bool? isDeleted, CancellationToken cancellationToken) + { + return await LoadAsync(id.StreamId, version, isDeleted, cancellationToken); + } + + public async Task> LoadAsync(CancellationToken cancellationToken) + { + return await LoadAsync(isDeleted: null, cancellationToken); + } + public async Task> LoadAsync(bool? isDeleted, CancellationToken cancellationToken) + { + return await LoadAsync(isDeleted, cancellationToken); + } + + public async Task> LoadAsync(IEnumerable ids, CancellationToken cancellationToken) + { + return await LoadAsync(ids, isDeleted: null, cancellationToken); + } + public async Task> LoadAsync(IEnumerable ids, bool? isDeleted, CancellationToken cancellationToken) + { + IEnumerable streamIds = ids.Select(id => id.StreamId); + return await LoadAsync(streamIds, isDeleted, cancellationToken); + } + + public Task> LoadAsync(TenantId? tenantId, CancellationToken cancellationToken) + { + throw new NotImplementedException(); // TODO(fpion): implement + } + + public Task> LoadAsync(Role role, CancellationToken cancellationToken) + { + throw new NotImplementedException(); // TODO(fpion): implement + } + + public async Task SaveAsync(ApiKey apikey, CancellationToken cancellationToken) + { + await base.SaveAsync(apikey, cancellationToken); + } + public async Task SaveAsync(IEnumerable apikeys, CancellationToken cancellationToken) + { + await base.SaveAsync(apikeys, cancellationToken); + } +} diff --git a/lib/Logitar.Identity.EntityFrameworkCore.Relational/Repositories/OneTimePasswordRepository.cs b/lib/Logitar.Identity.EntityFrameworkCore.Relational/Repositories/OneTimePasswordRepository.cs new file mode 100644 index 0000000..d37deb9 --- /dev/null +++ b/lib/Logitar.Identity.EntityFrameworkCore.Relational/Repositories/OneTimePasswordRepository.cs @@ -0,0 +1,62 @@ +using Logitar.EventSourcing; +using Logitar.Identity.Core; +using Logitar.Identity.Core.Passwords; + +namespace Logitar.Identity.EntityFrameworkCore.Relational.Repositories; + +public class OneTimePasswordRepository : Repository, IOneTimePasswordRepository +{ + public OneTimePasswordRepository(IEventStore eventStore) : base(eventStore) + { + } + + public async Task LoadAsync(OneTimePasswordId id, CancellationToken cancellationToken) + { + return await LoadAsync(id, isDeleted: null, cancellationToken); + } + public async Task LoadAsync(OneTimePasswordId id, long? version, CancellationToken cancellationToken) + { + return await LoadAsync(id, version, isDeleted: null, cancellationToken); + } + public async Task LoadAsync(OneTimePasswordId id, bool? isDeleted, CancellationToken cancellationToken) + { + return await LoadAsync(id, version: null, isDeleted, cancellationToken); + } + public async Task LoadAsync(OneTimePasswordId id, long? version, bool? isDeleted, CancellationToken cancellationToken) + { + return await LoadAsync(id.StreamId, version, isDeleted, cancellationToken); + } + + public async Task> LoadAsync(CancellationToken cancellationToken) + { + return await LoadAsync(isDeleted: null, cancellationToken); + } + public async Task> LoadAsync(bool? isDeleted, CancellationToken cancellationToken) + { + return await LoadAsync(isDeleted, cancellationToken); + } + + public async Task> LoadAsync(IEnumerable ids, CancellationToken cancellationToken) + { + return await LoadAsync(ids, isDeleted: null, cancellationToken); + } + public async Task> LoadAsync(IEnumerable ids, bool? isDeleted, CancellationToken cancellationToken) + { + IEnumerable streamIds = ids.Select(id => id.StreamId); + return await LoadAsync(streamIds, isDeleted, cancellationToken); + } + + public Task> LoadAsync(TenantId? tenantId, CancellationToken cancellationToken) + { + throw new NotImplementedException(); // TODO(fpion): implement + } + + public async Task SaveAsync(OneTimePassword onetimepassword, CancellationToken cancellationToken) + { + await base.SaveAsync(onetimepassword, cancellationToken); + } + public async Task SaveAsync(IEnumerable onetimepasswords, CancellationToken cancellationToken) + { + await base.SaveAsync(onetimepasswords, cancellationToken); + } +} diff --git a/lib/Logitar.Identity.EntityFrameworkCore.Relational/Repositories/RoleRepository.cs b/lib/Logitar.Identity.EntityFrameworkCore.Relational/Repositories/RoleRepository.cs new file mode 100644 index 0000000..d974887 --- /dev/null +++ b/lib/Logitar.Identity.EntityFrameworkCore.Relational/Repositories/RoleRepository.cs @@ -0,0 +1,78 @@ +using Logitar.EventSourcing; +using Logitar.Identity.Core; +using Logitar.Identity.Core.ApiKeys; +using Logitar.Identity.Core.Roles; +using Logitar.Identity.Core.Users; + +namespace Logitar.Identity.EntityFrameworkCore.Relational.Repositories; + +public class RoleRepository : Repository, IRoleRepository +{ + public RoleRepository(IEventStore eventStore) : base(eventStore) + { + } + + public async Task LoadAsync(RoleId id, CancellationToken cancellationToken) + { + return await LoadAsync(id, isDeleted: null, cancellationToken); + } + public async Task LoadAsync(RoleId id, long? version, CancellationToken cancellationToken) + { + return await LoadAsync(id, version, isDeleted: null, cancellationToken); + } + public async Task LoadAsync(RoleId id, bool? isDeleted, CancellationToken cancellationToken) + { + return await LoadAsync(id, version: null, isDeleted, cancellationToken); + } + public async Task LoadAsync(RoleId id, long? version, bool? isDeleted, CancellationToken cancellationToken) + { + return await LoadAsync(id.StreamId, version, isDeleted, cancellationToken); + } + + public async Task> LoadAsync(CancellationToken cancellationToken) + { + return await LoadAsync(isDeleted: null, cancellationToken); + } + public async Task> LoadAsync(bool? isDeleted, CancellationToken cancellationToken) + { + return await LoadAsync(isDeleted, cancellationToken); + } + + public async Task> LoadAsync(IEnumerable ids, CancellationToken cancellationToken) + { + return await LoadAsync(ids, isDeleted: null, cancellationToken); + } + public async Task> LoadAsync(IEnumerable ids, bool? isDeleted, CancellationToken cancellationToken) + { + IEnumerable streamIds = ids.Select(id => id.StreamId); + return await LoadAsync(streamIds, isDeleted, cancellationToken); + } + + public Task> LoadAsync(TenantId? tenantId, CancellationToken cancellationToken) + { + throw new NotImplementedException(); // TODO(fpion): implement + } + + public Task LoadAsync(TenantId? tenantId, UniqueName uniqueName, CancellationToken cancellationToken) + { + throw new NotImplementedException(); // TODO(fpion): implement + } + + public Task> LoadAsync(ApiKey apiKey, CancellationToken cancellationToken) + { + throw new NotImplementedException(); // TODO(fpion): implement + } + public Task> LoadAsync(User user, CancellationToken cancellationToken) + { + throw new NotImplementedException(); // TODO(fpion): implement + } + + public async Task SaveAsync(Role role, CancellationToken cancellationToken) + { + await base.SaveAsync(role, cancellationToken); + } + public async Task SaveAsync(IEnumerable roles, CancellationToken cancellationToken) + { + await base.SaveAsync(roles, cancellationToken); + } +} diff --git a/lib/Logitar.Identity.EntityFrameworkCore.Relational/Repositories/SessionRepository.cs b/lib/Logitar.Identity.EntityFrameworkCore.Relational/Repositories/SessionRepository.cs new file mode 100644 index 0000000..fbb34be --- /dev/null +++ b/lib/Logitar.Identity.EntityFrameworkCore.Relational/Repositories/SessionRepository.cs @@ -0,0 +1,72 @@ +using Logitar.EventSourcing; +using Logitar.Identity.Core; +using Logitar.Identity.Core.Sessions; +using Logitar.Identity.Core.Users; + +namespace Logitar.Identity.EntityFrameworkCore.Relational.Repositories; + +public class SessionRepository : Repository, ISessionRepository +{ + public SessionRepository(IEventStore eventStore) : base(eventStore) + { + } + + public async Task LoadAsync(SessionId id, CancellationToken cancellationToken) + { + return await LoadAsync(id, isDeleted: null, cancellationToken); + } + public async Task LoadAsync(SessionId id, long? version, CancellationToken cancellationToken) + { + return await LoadAsync(id, version, isDeleted: null, cancellationToken); + } + public async Task LoadAsync(SessionId id, bool? isDeleted, CancellationToken cancellationToken) + { + return await LoadAsync(id, version: null, isDeleted, cancellationToken); + } + public async Task LoadAsync(SessionId id, long? version, bool? isDeleted, CancellationToken cancellationToken) + { + return await LoadAsync(id.StreamId, version, isDeleted, cancellationToken); + } + + public async Task> LoadAsync(CancellationToken cancellationToken) + { + return await LoadAsync(isDeleted: null, cancellationToken); + } + public async Task> LoadAsync(bool? isDeleted, CancellationToken cancellationToken) + { + return await LoadAsync(isDeleted, cancellationToken); + } + + public async Task> LoadAsync(IEnumerable ids, CancellationToken cancellationToken) + { + return await LoadAsync(ids, isDeleted: null, cancellationToken); + } + public async Task> LoadAsync(IEnumerable ids, bool? isDeleted, CancellationToken cancellationToken) + { + IEnumerable streamIds = ids.Select(id => id.StreamId); + return await LoadAsync(streamIds, isDeleted, cancellationToken); + } + + public Task> LoadAsync(TenantId? tenantId, CancellationToken cancellationToken) + { + throw new NotImplementedException(); // TODO(fpion): implement + } + + public Task> LoadActiveAsync(User user, CancellationToken cancellationToken) + { + throw new NotImplementedException(); // TODO(fpion): implement + } + public Task> LoadAsync(User user, CancellationToken cancellationToken) + { + throw new NotImplementedException(); // TODO(fpion): implement + } + + public async Task SaveAsync(Session session, CancellationToken cancellationToken) + { + await base.SaveAsync(session, cancellationToken); + } + public async Task SaveAsync(IEnumerable sessions, CancellationToken cancellationToken) + { + await base.SaveAsync(sessions, cancellationToken); + } +} diff --git a/lib/Logitar.Identity.EntityFrameworkCore.Relational/Repositories/UserRepository.cs b/lib/Logitar.Identity.EntityFrameworkCore.Relational/Repositories/UserRepository.cs new file mode 100644 index 0000000..37c31a5 --- /dev/null +++ b/lib/Logitar.Identity.EntityFrameworkCore.Relational/Repositories/UserRepository.cs @@ -0,0 +1,87 @@ +using Logitar.EventSourcing; +using Logitar.Identity.Core; +using Logitar.Identity.Core.Roles; +using Logitar.Identity.Core.Sessions; +using Logitar.Identity.Core.Users; + +namespace Logitar.Identity.EntityFrameworkCore.Relational.Repositories; + +public class UserRepository : Repository, IUserRepository +{ + public UserRepository(IEventStore eventStore) : base(eventStore) + { + } + + public async Task LoadAsync(UserId id, CancellationToken cancellationToken) + { + return await LoadAsync(id, isDeleted: null, cancellationToken); + } + public async Task LoadAsync(UserId id, long? version, CancellationToken cancellationToken) + { + return await LoadAsync(id, version, isDeleted: null, cancellationToken); + } + public async Task LoadAsync(UserId id, bool? isDeleted, CancellationToken cancellationToken) + { + return await LoadAsync(id, version: null, isDeleted, cancellationToken); + } + public async Task LoadAsync(UserId id, long? version, bool? isDeleted, CancellationToken cancellationToken) + { + return await LoadAsync(id.StreamId, version, isDeleted, cancellationToken); + } + + public async Task> LoadAsync(CancellationToken cancellationToken) + { + return await LoadAsync(isDeleted: null, cancellationToken); + } + public async Task> LoadAsync(bool? isDeleted, CancellationToken cancellationToken) + { + return await LoadAsync(isDeleted, cancellationToken); + } + + public async Task> LoadAsync(IEnumerable ids, CancellationToken cancellationToken) + { + return await LoadAsync(ids, isDeleted: null, cancellationToken); + } + public async Task> LoadAsync(IEnumerable ids, bool? isDeleted, CancellationToken cancellationToken) + { + IEnumerable streamIds = ids.Select(id => id.StreamId); + return await LoadAsync(streamIds, isDeleted, cancellationToken); + } + + public Task> LoadAsync(TenantId? tenantId, CancellationToken cancellationToken) + { + throw new NotImplementedException(); // TODO(fpion): implement + } + + public Task LoadAsync(TenantId? tenantId, UniqueName uniqueName, CancellationToken cancellationToken) + { + throw new NotImplementedException(); // TODO(fpion): implement + } + public Task> LoadAsync(TenantId? tenantId, Email email, CancellationToken cancellationToken) + { + throw new NotImplementedException(); // TODO(fpion): implement + } + public Task LoadAsync(TenantId? tenantId, Identifier identifierKey, CustomIdentifier identifierValue, CancellationToken cancellationToken) + { + throw new NotImplementedException(); // TODO(fpion): implement + } + + public Task> LoadAsync(Role role, CancellationToken cancellationToken) + { + throw new NotImplementedException(); // TODO(fpion): implement + } + public async Task LoadAsync(Session session, CancellationToken cancellationToken) + { + return await LoadAsync(session.UserId.StreamId, cancellationToken) + ?? throw new InvalidOperationException($"The user aggregate 'Id={session.UserId}' could not be loaded."); + } + + public async Task SaveAsync(User user, CancellationToken cancellationToken) + { + await base.SaveAsync(user, cancellationToken); + } + public async Task SaveAsync(IEnumerable users, CancellationToken cancellationToken) + { + await base.SaveAsync(users, cancellationToken); + } +}