Add redux
Some checks failed
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is failing

This commit is contained in:
2021-11-18 23:00:24 +01:00
parent 7db2ceca08
commit 7712f63999
28 changed files with 501 additions and 218 deletions

View File

@@ -7,5 +7,5 @@ namespace Todo.Api.Controllers;
[ApiController]
public class ApiController : ControllerBase
{
public IMediator Mediator => HttpContext.RequestServices.GetRequiredService<IMediator>();
protected IMediator Mediator => HttpContext.RequestServices.GetRequiredService<IMediator>();
}

View File

@@ -47,8 +47,33 @@ public class TodosController : ApiController
public async Task<ActionResult<IEnumerable<Core.Entities.Todo>>> GetTodos()
=> Ok(await _todoRepository.GetTodosAsync());
[HttpGet("not-done")]
public async Task<ActionResult<IEnumerable<Core.Entities.Todo>>>
GetNotDoneTodos()
=> Ok(await _todoRepository.GetNotDoneTodos());
[HttpPut("{todoId}")]
public async Task<ActionResult> ReplaceTodo([FromRoute] string todoId, [FromBody] ReplaceTodoRequest request)
{
await Mediator.Send(request.To(todoId));
return NoContent();
}
public record ReplaceTodoRequest
{
[Required]
[JsonPropertyName("title")]
public string Title { get; init; }
[JsonPropertyName("description")]
public string? Description { get; init; }
[JsonPropertyName("project")]
public string? Project { get; init; }
[JsonPropertyName("status")]
public bool Status { get; init; }
internal ReplaceTodoCommand To(string id) => new(
id,
Title,
Project,
Description,
Status);
}
}

View File

@@ -27,8 +27,9 @@ public class TodoPublisher : ITodoPublisher
_logger = logger;
}
public async Task Publish(
string todoId,
public async Task Publish<T>(
string eventType,
T message,
CancellationToken cancellationToken)
{
var userId = _currentUserService.GetUserId() ??
@@ -36,14 +37,33 @@ public class TodoPublisher : ITodoPublisher
var connections =
await _userConnectionStore.GetConnectionsAsync(userId);
await _hubContext
.Clients
.Clients(connections)
.SendAsync(
"todoCreated",
todoId,
cancellationToken);
switch (eventType)
{
case "todoCreated":
await _hubContext
.Clients
.Clients(connections)
.SendAsync(
"todoCreated",
message,
cancellationToken);
break;
_logger.LogInformation("todo created {TodoId}", todoId);
case "todoUpdated":
await _hubContext
.Clients
.Clients(connections)
.SendAsync(
"todoUpdated",
message,
cancellationToken);
break;
}
_logger.LogInformation(
"todo event: {EventType} with message: {Message}",
eventType,
message);
}
}

View File

@@ -0,0 +1,55 @@
using System.Threading;
using MediatR;
using Todo.Core.Application.Notifications.Todo;
using Todo.Core.Interfaces.Persistence;
using Todo.Core.Interfaces.User;
namespace Todo.Core.Application.Commands.Todo;
public record ReplaceTodoCommand(
string Id,
string Title,
string Project,
string Description,
bool Status) : IRequest<Unit>
{
internal class Handler : IRequestHandler<ReplaceTodoCommand, Unit>
{
private readonly ICurrentUserService _currentUserService;
private readonly ITodoRepository _todoRepository;
private readonly IMediator _mediator;
public Handler(
ICurrentUserService currentUserService,
ITodoRepository todoRepository,
IMediator mediator)
{
_currentUserService = currentUserService;
_todoRepository = todoRepository;
_mediator = mediator;
}
public async Task<Unit> Handle(ReplaceTodoCommand request, CancellationToken cancellationToken)
{
var userId = _currentUserService.GetUserId();
if (userId is null)
throw new InvalidOperationException("User was not found");
//TODO: Make sure the author actually owns the todo
await _todoRepository.UpdateTodoAsync(request.To(userId));
await _mediator.Publish(new TodoUpdated(request.Id), cancellationToken);
return Unit.Value;
}
}
private Entities.Todo To(string authorId) => new()
{
Id = Id,
Description = Description,
Project = Project,
Status = Status,
Title = Title,
AuthorId = authorId
};
}

View File

@@ -20,6 +20,7 @@ public record TodoCreated(
CancellationToken cancellationToken)
{
await _todoPublisher.Publish(
"todoCreated",
JsonSerializer.Serialize(notification),
cancellationToken);
}

View File

@@ -0,0 +1,28 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using MediatR;
using Todo.Core.Interfaces.Publisher;
namespace Todo.Core.Application.Notifications.Todo;
public record TodoUpdated(
[property: JsonPropertyName("todoId")] string TodoId) : INotification
{
internal class Handler : INotificationHandler<TodoUpdated>
{
private readonly ITodoPublisher _todoPublisher;
public Handler(ITodoPublisher todoPublisher) => _todoPublisher = todoPublisher;
public async Task Handle(
TodoUpdated notification,
CancellationToken cancellationToken)
{
await _todoPublisher.Publish(
"todoUpdated",
JsonSerializer.Serialize(notification),
cancellationToken);
}
}
}

View File

@@ -4,5 +4,5 @@ namespace Todo.Core.Interfaces.Publisher;
public interface ITodoPublisher
{
Task Publish(string todoId, CancellationToken cancellationToken = new());
Task Publish<T>(string eventType, T message, CancellationToken cancellationToken = new());
}

View File

@@ -16,4 +16,4 @@ public record TodoViewModel(
t.AuthorId,
t.Project,
t.Description);
};
}

View File

@@ -39,7 +39,14 @@ internal class InMemoryUserConnectionStore : IUserConnectionStore
ConnectedUsers.TryGetValue(userId, out var existingUserConnectionIds);
// remove the connection id from the List
existingUserConnectionIds?.Remove(connectionId);
try
{
existingUserConnectionIds?.Remove(connectionId);
}
catch (Exception e)
{
Console.WriteLine(e);
}
// If there are no connection ids in the List, delete the user from the global cache (ConnectedUsers).
if (existingUserConnectionIds?.Count == 0)

View File

@@ -1,3 +1,4 @@
using System.Diagnostics;
using MongoDB.Driver;
using Todo.Core.Interfaces.Persistence;
using Todo.Persistence.Mongo.Repositories.Dtos;
@@ -35,7 +36,8 @@ public class TodoRepository : ITodoRepository
Title = todo.Title,
Status = false,
Project = todo.ProjectName,
Description = todo.Description
Description = todo.Description,
AuthorId = todo.AuthorId
};
}
@@ -52,7 +54,8 @@ public class TodoRepository : ITodoRepository
Title = t.Title,
Status = t.Status,
Project = t.ProjectName,
Description = t.Description
Description = t.Description,
AuthorId = t.AuthorId
});
}
@@ -84,7 +87,8 @@ public class TodoRepository : ITodoRepository
Project = todo.ProjectName,
Status = todo.Status,
Title = todo.Title,
Description = todo.Description
Description = todo.Description,
AuthorId = todo.AuthorId
};
}