Skip to content

Commit fe9c4df

Browse files
authored
Feat: events implementation and other improvements (#8)
* feat: fix loan creation, improve event creation and details loading, add validator support, fix some namings etc. * chore: some renames, query updates, and cleanup * feat: remove warnings and remove the `Async` postfix for some methods
1 parent f178377 commit fe9c4df

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+558
-530
lines changed

src/Tarscord.Core/Domain/Loan.cs

Lines changed: 0 additions & 22 deletions
This file was deleted.

src/Tarscord.Core/Exceptions/OperationFailedException.cs

Lines changed: 0 additions & 20 deletions
This file was deleted.

src/Tarscord.Core/Extensions/UserExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using Discord;
22
using System.Collections.Generic;
33
using System.Linq;
4-
using Tarscord.Core.Domain;
4+
using Tarscord.Core.Persistence.Entities;
55

66
namespace Tarscord.Core.Extensions;
77

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace Tarscord.Core.Features.Common;
2+
3+
internal interface IPerformedByUser
4+
{
5+
/// <summary>
6+
/// Represents the unique username of the Discord user.
7+
/// </summary>
8+
public string PerformedByUser { get; }
9+
}

src/Tarscord.Core/Features/EventAttendees/EventAttendeesEnvelope.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
using System.Collections.Generic;
2-
using Tarscord.Core.Domain;
2+
using Tarscord.Core.Persistence.Entities;
33

44
namespace Tarscord.Core.Features.EventAttendees;
55

src/Tarscord.Core/Features/EventAttendees/Update.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using System.Threading.Tasks;
44
using FluentValidation;
55
using MediatR;
6-
using Tarscord.Core.Domain;
76

87
namespace Tarscord.Core.Features.EventAttendees;
98

Lines changed: 43 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,21 @@
11
using MediatR;
22
using Microsoft.Extensions.Logging;
33
using OneOf;
4-
using Tarscord.Core.Domain;
54
using Tarscord.Core.Extensions;
65
using Tarscord.Core.Persistence;
6+
using Tarscord.Core.Persistence.Entities;
77

88
namespace Tarscord.Core.Features.Events;
99

10-
internal record Create(
11-
string EventOrganizer,
12-
ulong EventOrganizerId,
13-
string EventName,
14-
string EventDate,
15-
string EventDescription
16-
) : IRequest<OneOf<CreateResponse, FailureResponse>>;
17-
18-
internal record CreateResponse(
19-
ulong Id,
20-
string EventOrganizer,
21-
string EventName,
22-
DateTime? EventDate,
23-
string? EventDescription
24-
)
10+
internal static class Create
2511
{
26-
public static CreateResponse MapToResponse(EventInfo eventInfo) =>
27-
new(
28-
eventInfo.Id,
29-
eventInfo.EventOrganizer,
30-
eventInfo.EventName,
31-
eventInfo.EventDate,
32-
eventInfo.EventDescription
33-
);
34-
35-
public string ToMessage() =>
36-
$"'{EventName}' created by user {EventOrganizer}. Use this Id: {Id} to get the details of the event";
37-
}
12+
public record Command(
13+
string EventOrganizer,
14+
ulong EventOrganizerId,
15+
string EventName,
16+
string EventDate,
17+
string EventDescription
18+
) : IRequest<OneOf<EventInfoEnvelope, FailureResponse>>;
3819

3920
// public class CreateEventCommandValidator : AbstractValidator<CreateEventCommand>
4021
// {
@@ -44,43 +25,46 @@ public string ToMessage() =>
4425
// }
4526
// }
4627

47-
internal sealed class CreateEventCommandHandler : IRequestHandler<Create, OneOf<CreateResponse, FailureResponse>>
48-
{
49-
private readonly ILogger<CreateEventCommandHandler> _logger;
50-
private readonly TarscordContext _context;
51-
52-
public CreateEventCommandHandler(
53-
ILogger<CreateEventCommandHandler> logger,
54-
TarscordContext context)
55-
{
56-
_logger = logger;
57-
_context = context;
58-
}
59-
60-
public async Task<OneOf<CreateResponse, FailureResponse>> Handle(
61-
Create request,
62-
CancellationToken cancellationToken)
28+
internal sealed class CommandHandler : IRequestHandler<Command, OneOf<EventInfoEnvelope, FailureResponse>>
6329
{
64-
var dateOfEvent = request.EventDate.FromTextToDate();
65-
// var validDateProvided = DateTime.TryParse(dateOfEvent, out var parsedDateTime);
30+
private readonly ILogger<CommandHandler> _logger;
31+
private readonly TarscordContext _context;
32+
private readonly TimeProvider _timeProvider;
6633

67-
if (!dateOfEvent.HasValue)
34+
public CommandHandler(
35+
ILogger<CommandHandler> logger,
36+
TarscordContext context,
37+
TimeProvider timeProvider)
6838
{
69-
return new FailureResponse("Invalid event date provided");
39+
_logger = logger;
40+
_context = context;
41+
_timeProvider = timeProvider;
7042
}
7143

72-
var createdEvent = await _context.EventInfos.AddAsync(new EventInfo
44+
public async Task<OneOf<EventInfoEnvelope, FailureResponse>> Handle(
45+
Command command,
46+
CancellationToken cancellationToken)
7347
{
74-
EventOrganizer = request.EventDescription,
75-
EventOrganizerId = request.EventOrganizerId.ToString(),
76-
EventName = request.EventName,
77-
EventDate = dateOfEvent.Value.ToUniversalTime(),
78-
EventDescription = request.EventDescription,
79-
IsActive = true,
80-
Created = DateTime.UtcNow // Possibly replace with TimeProvider or remove altogether
81-
}, cancellationToken);
48+
var dateOfEvent = command.EventDate.FromTextToDate();
49+
50+
if (!dateOfEvent.HasValue)
51+
{
52+
return new FailureResponse("Invalid event date provided");
53+
}
8254

83-
await _context.SaveChangesAsync(cancellationToken);
84-
return CreateResponse.MapToResponse(createdEvent.Entity);
55+
var createdEvent = await _context.EventInfos.AddAsync(new EventInfo
56+
{
57+
EventOrganizer = command.EventDescription,
58+
EventOrganizerId = command.EventOrganizerId.ToString(),
59+
EventName = command.EventName,
60+
EventDate = dateOfEvent.Value.ToUniversalTime(),
61+
EventDescription = command.EventDescription,
62+
IsActive = true,
63+
Created = _timeProvider.GetUtcNow().UtcDateTime
64+
}, cancellationToken);
65+
66+
await _context.SaveChangesAsync(cancellationToken);
67+
return EventInfoEnvelope.FromEntity(createdEvent.Entity);
68+
}
8569
}
8670
}
Lines changed: 38 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,45 @@
1-
using System.Linq;
2-
using System.Threading;
3-
using System.Threading.Tasks;
41
using FluentValidation;
52
using MediatR;
6-
using Tarscord.Core.Domain;
3+
using Microsoft.EntityFrameworkCore;
4+
using Tarscord.Core.Persistence;
5+
using OneOf;
76

87
namespace Tarscord.Core.Features.Events;
98

10-
public class Details
9+
internal static class Details
1110
{
12-
// public class Query : IRequest<EventInfo>
13-
// {
14-
// public ulong EventId { get; init; }
15-
// }
16-
//
17-
// public class QueryValidator : AbstractValidator<Query>
18-
// {
19-
// public QueryValidator()
20-
// {
21-
// RuleFor(x => x.EventId).NotNull().NotEmpty().GreaterThan((ulong)0);
22-
// }
23-
// }
24-
//
25-
// public class QueryHandler : IRequestHandler<Query, EventInfoEnvelope>
26-
// {
27-
// private readonly IEventRepository _eventRepository;
28-
//
29-
// public QueryHandler(IEventRepository eventRepository)
30-
// {
31-
// _eventRepository = eventRepository;
32-
// }
33-
//
34-
// public async Task<EventInfoEnvelope> Handle(Query message, CancellationToken cancellationToken)
35-
// {
36-
// var events = await _eventRepository.FindBy(eventInfo => eventInfo.Id == message.EventId)
37-
// .ConfigureAwait(false);
38-
//
39-
// return new EventInfoEnvelope(events.FirstOrDefault());
40-
// }
41-
// }
11+
public record Query(ulong EventId) : IRequest<OneOf<EventInfoEnvelope, FailureResponse>>;
12+
13+
public class QueryValidator : AbstractValidator<Query>
14+
{
15+
public QueryValidator()
16+
{
17+
RuleFor(x => x.EventId).NotNull().NotEmpty().GreaterThan((ulong)0);
18+
}
19+
}
20+
21+
public class QueryHandler(TarscordContext tarscordContext, IValidator<Query> validator)
22+
: IRequestHandler<Query, OneOf<EventInfoEnvelope, FailureResponse>>
23+
{
24+
public async Task<OneOf<EventInfoEnvelope, FailureResponse>> Handle(Query message,
25+
CancellationToken cancellationToken)
26+
{
27+
var isValid = await validator.ValidateAsync(message, cancellationToken);
28+
29+
if (!isValid.IsValid)
30+
{
31+
return new FailureResponse($"Event '{message.EventId}' does not exist");
32+
}
33+
34+
var eventInfo = await tarscordContext.EventInfos
35+
.FirstOrDefaultAsync(eventInfo => eventInfo.Id == message.EventId,
36+
cancellationToken: cancellationToken);
37+
38+
return eventInfo switch
39+
{
40+
null => new FailureResponse($"Event '{message.EventId}' does not exist"),
41+
_ => EventInfoEnvelope.FromEntity(eventInfo)
42+
};
43+
}
44+
}
4245
}

src/Tarscord.Core/Features/Events/EnvelopeExtensions.cs

Lines changed: 0 additions & 40 deletions
This file was deleted.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using Discord;
2+
using Tarscord.Core.Extensions;
3+
using Tarscord.Core.Persistence.Entities;
4+
5+
namespace Tarscord.Core.Features.Events;
6+
7+
internal record EventInfoEnvelope(
8+
ulong EventId,
9+
string EventOrganizer,
10+
string EventOrganizerId,
11+
string EventName,
12+
DateTime? EventDate,
13+
string EventDescription) // TODO: Create an interface to implement for envelopes
14+
{
15+
// public static Embed ToEmbeddedMessage(this EventInfoListEnvelope events)
16+
// {
17+
// var eventsInformation = new StringBuilder();
18+
//
19+
// foreach (var eventInfo in events.EventInfo)
20+
// {
21+
// eventsInformation
22+
// .Append(eventInfo.Id).Append(": '")
23+
// .Append(eventInfo.EventName)
24+
// .Append("' by user: ").Append(eventInfo.EventOrganizer).Append(".\n");
25+
// }
26+
//
27+
// if (eventsInformation.Length == 0)
28+
// {
29+
// return "No events found".EmbedMessage();
30+
// }
31+
//
32+
// return eventsInformation.ToString().EmbedMessage();
33+
// }
34+
35+
public static EventInfoEnvelope FromEntity(EventInfo eventInfo)
36+
{
37+
return new EventInfoEnvelope(
38+
eventInfo.Id,
39+
eventInfo.EventOrganizer,
40+
eventInfo.EventOrganizerId,
41+
eventInfo.EventName,
42+
eventInfo.EventDate,
43+
eventInfo.EventDescription);
44+
}
45+
46+
public Embed ToEmbeddedMessage()
47+
{
48+
return
49+
($"'Event Name: {EventName}', " +
50+
$"created by user '{EventOrganizer}', " +
51+
$"with description '{EventDescription}'").EmbedMessage();
52+
}
53+
}

0 commit comments

Comments
 (0)