-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implementing Repositories & Event Handlers. (#74)
- Loading branch information
Showing
23 changed files
with
883 additions
and
741 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
lib/Logitar.Identity.EntityFrameworkCore.Relational/EntityType.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
namespace Logitar.Identity.EntityFrameworkCore.Relational; | ||
|
||
public static class EntityType | ||
{ | ||
public const string ApiKey = "ApiKey"; | ||
public const string OneTimePassword = "OneTimePassword"; | ||
public const string Role = "Role"; | ||
public const string Session = "Session"; | ||
public const string User = "User"; | ||
} |
129 changes: 129 additions & 0 deletions
129
lib/Logitar.Identity.EntityFrameworkCore.Relational/Handlers/ApiKeyEvents.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
using Logitar.Identity.Core.ApiKeys.Events; | ||
using Logitar.Identity.EntityFrameworkCore.Relational.Entities; | ||
using MediatR; | ||
using Microsoft.EntityFrameworkCore; | ||
|
||
namespace Logitar.Identity.EntityFrameworkCore.Relational.Handlers; | ||
|
||
public sealed class ApiKeyEvents : INotificationHandler<ApiKeyAuthenticated>, | ||
INotificationHandler<ApiKeyCreated>, | ||
INotificationHandler<ApiKeyDeleted>, | ||
INotificationHandler<ApiKeyRoleAdded>, | ||
INotificationHandler<ApiKeyRoleRemoved>, | ||
INotificationHandler<ApiKeyUpdated> | ||
{ | ||
private readonly IdentityContext _context; | ||
private readonly ICustomAttributeService _customAttributes; | ||
|
||
public ApiKeyEvents(IdentityContext context, ICustomAttributeService customAttributes) | ||
{ | ||
_context = context; | ||
_customAttributes = customAttributes; | ||
} | ||
|
||
public async Task Handle(ApiKeyAuthenticated @event, CancellationToken cancellationToken) | ||
{ | ||
ApiKeyEntity apiKey = await _context.ApiKeys | ||
.SingleOrDefaultAsync(x => x.StreamId == @event.StreamId.Value, cancellationToken) | ||
?? throw new InvalidOperationException($"The API key entity 'StreamId={@event.StreamId}' could not be found."); | ||
|
||
apiKey.Authenticate(@event); | ||
|
||
await _context.SaveChangesAsync(cancellationToken); | ||
} | ||
|
||
public async Task Handle(ApiKeyCreated @event, CancellationToken cancellationToken) | ||
{ | ||
ApiKeyEntity? apiKey = await _context.ApiKeys.AsNoTracking() | ||
.SingleOrDefaultAsync(x => x.StreamId == @event.StreamId.Value, cancellationToken); | ||
if (apiKey == null) | ||
{ | ||
apiKey = new(@event); | ||
|
||
_context.ApiKeys.Add(apiKey); | ||
|
||
await SaveActorAsync(apiKey, cancellationToken); | ||
await _context.SaveChangesAsync(cancellationToken); | ||
} | ||
} | ||
|
||
public async Task Handle(ApiKeyDeleted @event, CancellationToken cancellationToken) | ||
{ | ||
ApiKeyEntity? apiKey = await _context.ApiKeys | ||
.SingleOrDefaultAsync(x => x.StreamId == @event.StreamId.Value, cancellationToken); | ||
if (apiKey != null) | ||
{ | ||
_context.ApiKeys.Remove(apiKey); | ||
|
||
await DeleteActorAsync(apiKey, cancellationToken); | ||
await _customAttributes.RemoveAsync(EntityType.ApiKey, apiKey.ApiKeyId, cancellationToken); | ||
await _context.SaveChangesAsync(cancellationToken); | ||
} | ||
} | ||
|
||
public async Task Handle(ApiKeyRoleAdded @event, CancellationToken cancellationToken) | ||
{ | ||
ApiKeyEntity apiKey = await _context.ApiKeys | ||
.SingleOrDefaultAsync(x => x.StreamId == @event.StreamId.Value, cancellationToken) | ||
?? throw new InvalidOperationException($"The API key entity 'StreamId={@event.StreamId}' could not be found."); | ||
|
||
RoleEntity role = await _context.Roles | ||
.SingleOrDefaultAsync(x => x.StreamId == @event.RoleId.Value, cancellationToken) | ||
?? throw new InvalidOperationException($"The role entity 'StreamId={@event.RoleId}' could not be found."); | ||
|
||
apiKey.AddRole(role, @event); | ||
|
||
await _context.SaveChangesAsync(cancellationToken); | ||
} | ||
|
||
public async Task Handle(ApiKeyRoleRemoved @event, CancellationToken cancellationToken) | ||
{ | ||
ApiKeyEntity apiKey = await _context.ApiKeys | ||
.Include(x => x.Roles) | ||
.SingleOrDefaultAsync(x => x.StreamId == @event.StreamId.Value, cancellationToken) | ||
?? throw new InvalidOperationException($"The API key entity 'StreamId={@event.StreamId}' could not be found."); | ||
|
||
apiKey.RemoveRole(@event); | ||
|
||
await _context.SaveChangesAsync(cancellationToken); | ||
} | ||
|
||
public async Task Handle(ApiKeyUpdated @event, CancellationToken cancellationToken) | ||
{ | ||
ApiKeyEntity apiKey = await _context.ApiKeys | ||
.SingleOrDefaultAsync(x => x.StreamId == @event.StreamId.Value, cancellationToken) | ||
?? throw new InvalidOperationException($"The API key entity 'StreamId={@event.StreamId}' could not be found."); | ||
|
||
apiKey.Update(@event); | ||
|
||
await SaveActorAsync(apiKey, cancellationToken); | ||
await _customAttributes.UpdateAsync(EntityType.ApiKey, apiKey.ApiKeyId, @event.CustomAttributes, cancellationToken); | ||
await _context.SaveChangesAsync(cancellationToken); | ||
} | ||
|
||
private async Task DeleteActorAsync(ApiKeyEntity apiKey, CancellationToken cancellationToken) | ||
{ | ||
await SaveActorAsync(apiKey, isDeleted: true, cancellationToken); | ||
} | ||
private async Task SaveActorAsync(ApiKeyEntity apiKey, CancellationToken cancellationToken) | ||
{ | ||
await SaveActorAsync(apiKey, isDeleted: false, cancellationToken); | ||
} | ||
private async Task SaveActorAsync(ApiKeyEntity apiKey, bool isDeleted, CancellationToken cancellationToken) | ||
{ | ||
ActorEntity? actor = await _context.Actors.SingleOrDefaultAsync(x => x.Id == apiKey.StreamId, cancellationToken); | ||
if (actor == null) | ||
{ | ||
actor = new() | ||
{ | ||
Id = apiKey.StreamId, | ||
Type = ActorType.ApiKey | ||
}; | ||
_context.Actors.Add(actor); | ||
} | ||
|
||
actor.IsDeleted = isDeleted; | ||
|
||
actor.DisplayName = apiKey.DisplayName; | ||
} | ||
} |
83 changes: 83 additions & 0 deletions
83
lib/Logitar.Identity.EntityFrameworkCore.Relational/Handlers/OneTimePasswordEvents.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
using Logitar.Identity.Core.Passwords.Events; | ||
using Logitar.Identity.EntityFrameworkCore.Relational.Entities; | ||
using MediatR; | ||
using Microsoft.EntityFrameworkCore; | ||
|
||
namespace Logitar.Identity.EntityFrameworkCore.Relational.Handlers; | ||
|
||
public sealed class OneTimePasswordEvents : INotificationHandler<OneTimePasswordCreated>, | ||
INotificationHandler<OneTimePasswordDeleted>, | ||
INotificationHandler<OneTimePasswordUpdated>, | ||
INotificationHandler<OneTimePasswordValidationFailed>, | ||
INotificationHandler<OneTimePasswordValidationSucceeded> | ||
{ | ||
private readonly IdentityContext _context; | ||
private readonly ICustomAttributeService _customAttributes; | ||
|
||
public OneTimePasswordEvents(IdentityContext context, ICustomAttributeService customAttributes) | ||
{ | ||
_context = context; | ||
_customAttributes = customAttributes; | ||
} | ||
|
||
public async Task Handle(OneTimePasswordCreated @event, CancellationToken cancellationToken) | ||
{ | ||
OneTimePasswordEntity? oneTimePassword = await _context.OneTimePasswords.AsNoTracking() | ||
.SingleOrDefaultAsync(x => x.StreamId == @event.StreamId.Value, cancellationToken); | ||
if (oneTimePassword == null) | ||
{ | ||
oneTimePassword = new(@event); | ||
|
||
_context.OneTimePasswords.Add(oneTimePassword); | ||
|
||
await _context.SaveChangesAsync(cancellationToken); | ||
} | ||
} | ||
|
||
public async Task Handle(OneTimePasswordDeleted @event, CancellationToken cancellationToken) | ||
{ | ||
OneTimePasswordEntity? oneTimePassword = await _context.OneTimePasswords | ||
.SingleOrDefaultAsync(x => x.StreamId == @event.StreamId.Value, cancellationToken); | ||
if (oneTimePassword != null) | ||
{ | ||
_context.OneTimePasswords.Remove(oneTimePassword); | ||
|
||
await _customAttributes.RemoveAsync(EntityType.OneTimePassword, oneTimePassword.OneTimePasswordId, cancellationToken); | ||
await _context.SaveChangesAsync(cancellationToken); | ||
} | ||
} | ||
|
||
public async Task Handle(OneTimePasswordUpdated @event, CancellationToken cancellationToken) | ||
{ | ||
OneTimePasswordEntity oneTimePassword = await _context.OneTimePasswords | ||
.SingleOrDefaultAsync(x => x.StreamId == @event.StreamId.Value, cancellationToken) | ||
?? throw new InvalidOperationException($"The One-Time Password (OTP) entity 'StreamId={@event.StreamId}' could not be found."); | ||
|
||
oneTimePassword.Update(@event); | ||
|
||
await _customAttributes.UpdateAsync(EntityType.OneTimePassword, oneTimePassword.OneTimePasswordId, @event.CustomAttributes, cancellationToken); | ||
await _context.SaveChangesAsync(cancellationToken); | ||
} | ||
|
||
public async Task Handle(OneTimePasswordValidationFailed @event, CancellationToken cancellationToken) | ||
{ | ||
OneTimePasswordEntity oneTimePassword = await _context.OneTimePasswords | ||
.SingleOrDefaultAsync(x => x.StreamId == @event.StreamId.Value, cancellationToken) | ||
?? throw new InvalidOperationException($"The One-Time Password (OTP) entity 'StreamId={@event.StreamId}' could not be found."); | ||
|
||
oneTimePassword.Fail(@event); | ||
|
||
await _context.SaveChangesAsync(cancellationToken); | ||
} | ||
|
||
public async Task Handle(OneTimePasswordValidationSucceeded @event, CancellationToken cancellationToken) | ||
{ | ||
OneTimePasswordEntity oneTimePassword = await _context.OneTimePasswords | ||
.SingleOrDefaultAsync(x => x.StreamId == @event.StreamId.Value, cancellationToken) | ||
?? throw new InvalidOperationException($"The One-Time Password (OTP) entity 'StreamId={@event.StreamId}' could not be found."); | ||
|
||
oneTimePassword.Succeed(@event); | ||
|
||
await _context.SaveChangesAsync(cancellationToken); | ||
} | ||
} |
71 changes: 71 additions & 0 deletions
71
lib/Logitar.Identity.EntityFrameworkCore.Relational/Handlers/RoleEvents.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
using Logitar.Identity.Core.Roles.Events; | ||
using Logitar.Identity.EntityFrameworkCore.Relational.Entities; | ||
using MediatR; | ||
using Microsoft.EntityFrameworkCore; | ||
|
||
namespace Logitar.Identity.EntityFrameworkCore.Relational.Handlers; | ||
|
||
public sealed class RoleEvents : INotificationHandler<RoleCreated>, | ||
INotificationHandler<RoleDeleted>, | ||
INotificationHandler<RoleUniqueNameChanged>, | ||
INotificationHandler<RoleUpdated> | ||
{ | ||
private readonly IdentityContext _context; | ||
private readonly ICustomAttributeService _customAttributes; | ||
|
||
public RoleEvents(IdentityContext context, ICustomAttributeService customAttributes) | ||
{ | ||
_context = context; | ||
_customAttributes = customAttributes; | ||
} | ||
|
||
public async Task Handle(RoleCreated @event, CancellationToken cancellationToken) | ||
{ | ||
RoleEntity? role = await _context.Roles.AsNoTracking() | ||
.SingleOrDefaultAsync(x => x.StreamId == @event.StreamId.Value, cancellationToken); | ||
if (role == null) | ||
{ | ||
role = new(@event); | ||
|
||
_context.Roles.Add(role); | ||
|
||
await _context.SaveChangesAsync(cancellationToken); | ||
} | ||
} | ||
|
||
public async Task Handle(RoleDeleted @event, CancellationToken cancellationToken) | ||
{ | ||
RoleEntity? role = await _context.Roles | ||
.SingleOrDefaultAsync(x => x.StreamId == @event.StreamId.Value, cancellationToken); | ||
if (role != null) | ||
{ | ||
_context.Roles.Remove(role); | ||
|
||
await _customAttributes.RemoveAsync(EntityType.Role, role.RoleId, cancellationToken); | ||
await _context.SaveChangesAsync(cancellationToken); | ||
} | ||
} | ||
|
||
public async Task Handle(RoleUniqueNameChanged @event, CancellationToken cancellationToken) | ||
{ | ||
RoleEntity role = await _context.Roles | ||
.SingleOrDefaultAsync(x => x.StreamId == @event.StreamId.Value, cancellationToken) | ||
?? throw new InvalidOperationException($"The role entity 'StreamId={@event.StreamId}' could not be found."); | ||
|
||
role.SetUniqueName(@event); | ||
|
||
await _context.SaveChangesAsync(cancellationToken); | ||
} | ||
|
||
public async Task Handle(RoleUpdated @event, CancellationToken cancellationToken) | ||
{ | ||
RoleEntity role = await _context.Roles | ||
.SingleOrDefaultAsync(x => x.StreamId == @event.StreamId.Value, cancellationToken) | ||
?? throw new InvalidOperationException($"The role entity 'StreamId={@event.StreamId}' could not be found."); | ||
|
||
role.Update(@event); | ||
|
||
await _customAttributes.UpdateAsync(EntityType.Role, role.RoleId, @event.CustomAttributes, cancellationToken); | ||
await _context.SaveChangesAsync(cancellationToken); | ||
} | ||
} |
Oops, something went wrong.