Skip to content
This repository has been archived by the owner on Jul 9, 2024. It is now read-only.

Commit

Permalink
Actor synchronization. (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
Utar94 authored Apr 29, 2024
1 parent edce269 commit ed9d93c
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Logitar.Master.Contracts.Accounts;
using Logitar.Master.Application.Accounts.Events;
using Logitar.Master.Contracts.Accounts;
using Logitar.Portal.Contracts;
using Logitar.Portal.Contracts.Messages;
using Logitar.Portal.Contracts.Passwords;
Expand All @@ -19,15 +20,17 @@ internal class SignInCommandHandler : IRequestHandler<SignInCommand, SignInComma

private readonly IMessageService _messageService;
private readonly IOneTimePasswordService _oneTimePasswordService;
private readonly IPublisher _publisher;
private readonly ISessionService _sessionService;
private readonly ITokenService _tokenService;
private readonly IUserService _userService;

public SignInCommandHandler(IMessageService messageService, IOneTimePasswordService oneTimePasswordService,
ISessionService sessionService, ITokenService tokenService, IUserService userService)
IPublisher publisher, ISessionService sessionService, ITokenService tokenService, IUserService userService)
{
_messageService = messageService;
_oneTimePasswordService = oneTimePasswordService;
_publisher = publisher;
_sessionService = sessionService;
_tokenService = tokenService;
_userService = userService;
Expand Down Expand Up @@ -83,7 +86,8 @@ private async Task<SignInCommandResult> HandleCredentialsAsync(Credentials crede
MultiFactorAuthenticationMode? mfaMode = user.GetMultiFactorAuthenticationMode();
if (mfaMode == MultiFactorAuthenticationMode.None && user.IsProfileCompleted())
{
Session session = await _sessionService.SignInAsync(user, credentials.Password, customAttributes, cancellationToken); // TODO(fpion): create actor
Session session = await _sessionService.SignInAsync(user, credentials.Password, customAttributes, cancellationToken);
await _publisher.Publish(new UserSignedInEvent(session), cancellationToken);
return SignInCommandResult.Succeed(session);
}
else
Expand Down Expand Up @@ -184,7 +188,8 @@ private async Task<SignInCommandResult> EnsureProfileIsCompleted(User user, IEnu
return SignInCommandResult.RequireProfileCompletion(token);
}

Session session = await _sessionService.CreateAsync(user, customAttributes, cancellationToken); // TODO(fpion): create actor
Session session = await _sessionService.CreateAsync(user, customAttributes, cancellationToken);
await _publisher.Publish(new UserSignedInEvent(session), cancellationToken);
return SignInCommandResult.Succeed(session);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
using Logitar.Portal.Contracts.Sessions;
using MediatR;

namespace Logitar.Master.Application.Accounts.Events;

public record UserSignedInEvent(Session Session) : INotification;
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Logitar.Portal.Contracts.Actors;
using Logitar.EventSourcing;
using Logitar.Portal.Contracts.Actors;
using Logitar.Portal.Contracts.Users;

namespace Logitar.Master.EntityFrameworkCore.Entities;

Expand All @@ -14,10 +16,31 @@ internal class ActorEntity
public string? EmailAddress { get; private set; }
public string? PictureUrl { get; private set; }

public ActorEntity(User user)
{
Id = new ActorId(user.Id).Value;
Type = ActorType.User;

Update(user);
}

private ActorEntity()
{
}

public void Update(User user)
{
string id = new ActorId(user.Id).Value;
if (Id != id || Type != ActorType.User)
{
throw new ArgumentException($"The actor '{Type}.Id={Id}' cannot be updated as the user 'User.Id={id}'.", nameof(user));
}

DisplayName = user.FullName ?? user.UniqueName;
EmailAddress = user.Email?.Address;
PictureUrl = user.Picture;
}

public override bool Equals(object? obj) => obj is ActorEntity actor && actor.Id == Id;
public override int GetHashCode() => HashCode.Combine(GetType(), Id);
public override string ToString()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using Logitar.EventSourcing;
using Logitar.Master.Application.Accounts.Events;
using Logitar.Master.EntityFrameworkCore.Entities;
using Logitar.Portal.Contracts.Users;
using MediatR;
using Microsoft.EntityFrameworkCore;

namespace Logitar.Master.EntityFrameworkCore.Handlers;

internal static class Accounts
{
public class UserSignedInEventHandler : INotificationHandler<UserSignedInEvent>
{
private readonly MasterContext _context;

public UserSignedInEventHandler(MasterContext context)
{
_context = context;
}

public async Task Handle(UserSignedInEvent @event, CancellationToken cancellationToken)
{
User user = @event.Session.User;

string id = new ActorId(user.Id).Value;
ActorEntity? actor = await _context.Actors.SingleOrDefaultAsync(x => x.Id == id, cancellationToken);
if (actor == null)
{
actor = new(user);

_context.Actors.Add(actor);
}
else
{
actor.Update(user);
}

await _context.SaveChangesAsync(cancellationToken);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ namespace Logitar.Master.EntityFrameworkCore.Queriers;
internal class ProjectQuerier : IProjectQuerier
{
private readonly IActorService _actorService;
private readonly MasterContext _context;
private readonly DbSet<ProjectEntity> _projects;
private readonly ISqlHelper _sqlHelper;

public ProjectQuerier(IActorService actorService, MasterContext context, ISqlHelper sqlHelper)
{
_actorService = actorService;
_context = context;
_projects = context.Projects;
_sqlHelper = sqlHelper;
}

Expand All @@ -37,7 +37,7 @@ public async Task<Project> ReadAsync(ProjectAggregate project, CancellationToken
{
string aggregateId = new AggregateId(id).Value;

ProjectEntity? project = await _context.Projects.AsNoTracking()
ProjectEntity? project = await _projects.AsNoTracking()
.SingleOrDefaultAsync(x => x.AggregateId == aggregateId, cancellationToken);

return project == null ? null : await MapAsync(project, cancellationToken);
Expand All @@ -47,7 +47,7 @@ public async Task<Project> ReadAsync(ProjectAggregate project, CancellationToken
{
string uniqueKeyNormalized = MasterDb.Normalize(uniqueKey);

ProjectEntity? project = await _context.Projects.AsNoTracking()
ProjectEntity? project = await _projects.AsNoTracking()
.SingleOrDefaultAsync(x => x.UniqueKeyNormalized == uniqueKeyNormalized, cancellationToken);

return project == null ? null : await MapAsync(project, cancellationToken);
Expand All @@ -59,7 +59,7 @@ public async Task<SearchResults<Project>> SearchAsync(SearchProjectsPayload payl
.ApplyIdFilter(MasterDb.Projects.AggregateId, payload.Ids);
_sqlHelper.ApplyTextSearch(builder, payload.Search, MasterDb.Projects.UniqueKey, MasterDb.Projects.DisplayName);

IQueryable<ProjectEntity> query = _context.Projects.FromQuery(builder).AsNoTracking();
IQueryable<ProjectEntity> query = _projects.FromQuery(builder).AsNoTracking();
long total = await query.LongCountAsync(cancellationToken);

IOrderedQueryable<ProjectEntity>? ordered = null;
Expand Down
2 changes: 0 additions & 2 deletions backend/src/Logitar.Master/Controllers/AccountController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ public AccountController(IBearerTokenService bearerTokenService, IRequestPipelin
_sessionService = sessionService;
}

// TODO(fpion): get profile

[HttpPost("/auth/sign/in")]
public async Task<ActionResult<SignInResponse>> SignInAsync([FromBody] SignInPayload payload, CancellationToken cancellationToken)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
using Logitar.EventSourcing.EntityFrameworkCore.Relational;
using Logitar.Master.Application;
using Logitar.Master.Application.Accounts;
using Logitar.Master.Application.Caching;
using Logitar.Master.EntityFrameworkCore;
using Logitar.Master.EntityFrameworkCore.Entities;
using Logitar.Master.EntityFrameworkCore.SqlServer;
using Logitar.Master.Infrastructure;
using Logitar.Master.Infrastructure.Commands;
Expand Down Expand Up @@ -101,8 +101,6 @@ protected IntegrationTests()
user.CreatedBy = Actor;
user.UpdatedBy = Actor;
_context.User = user;

ServiceProvider.GetRequiredService<ICacheService>().SetActor(Actor); // TODO(fpion): insert into database
}

public virtual async Task InitializeAsync()
Expand All @@ -115,6 +113,13 @@ public virtual async Task InitializeAsync()
command.AppendLine(CreateDeleteBuilder(MasterDb.Actors.Table).Build().Text);
command.AppendLine(CreateDeleteBuilder(EventDb.Events.Table).Build().Text);
await MasterContext.Database.ExecuteSqlRawAsync(command.ToString());

if (_context.User != null)
{
ActorEntity actor = new(_context.User);
MasterContext.Actors.Add(actor);
await MasterContext.SaveChangesAsync();
}
}
private IDeleteBuilder CreateDeleteBuilder(TableId table) => _databaseProvider switch
{
Expand Down

0 comments on commit ed9d93c

Please sign in to comment.