Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ public async Task<Response<CountryContentRequestDto>> Handle(
e.ProposedTitleAr, e.ProposedTitleEn,
e.ProposedDescriptionAr, e.ProposedDescriptionEn,
e.ProposedResourceType, e.ProposedAssetFileId,
e.ProposedTopicId, e.ProposedStartsOn, e.ProposedEndsOn,
e.ProposedTopicId, e.ProposedCategoryId,
e.ProposedStartsOn, e.ProposedEndsOn,
e.ProposedLocationAr, e.ProposedLocationEn, e.ProposedOnlineMeetingUrl,
e.SubmittedOn, e.AdminNotesAr, e.AdminNotesEn,
e.ProcessedById, e.ProcessedOn);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ private async Task<CountryContentRequest> SubmitResourceAsync(
body.TitleAr, body.TitleEn,
body.DescriptionAr, body.DescriptionEn,
body.ResourceType, body.AssetFileId,
body.CategoryId,
_clock);
}

Expand Down Expand Up @@ -184,6 +185,7 @@ private async Task<CountryContentRequest> SubmitEventAsync(
body.TopicId,
body.StartsOn, body.EndsOn,
body.LocationAr, body.LocationEn, body.OnlineMeetingUrl,
body.FeaturedImageAssetId,
_clock);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public sealed record CountryContentRequestDto(
ResourceType? ProposedResourceType,
System.Guid? ProposedAssetFileId,
System.Guid? ProposedTopicId,
System.Guid? ProposedCategoryId,
System.DateTimeOffset? ProposedStartsOn,
System.DateTimeOffset? ProposedEndsOn,
string? ProposedLocationAr,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
using CCE.Application.Common.Interfaces;
using CCE.Domain.Common;
using CCE.Domain.Content;
using CCE.Domain.Country;
using CCE.Domain.Country.Events;
using MediatR;
using Microsoft.EntityFrameworkCore;

namespace CCE.Application.Content.EventHandlers;

public sealed class CountryContentRequestApprovedContentHandler
: INotificationHandler<CountryContentRequestApprovedEvent>
{
private readonly ICceDbContext _db;
private readonly ISystemClock _clock;

public CountryContentRequestApprovedContentHandler(
ICceDbContext db,
ISystemClock clock)
{
_db = db;
_clock = clock;
}

public async Task Handle(
CountryContentRequestApprovedEvent notification,
CancellationToken cancellationToken)
{
var request = await _db.CountryContentRequests
.FirstOrDefaultAsync(r => r.Id == notification.RequestId, cancellationToken)
.ConfigureAwait(false);

if (request is null)
return;

switch (request.Type)
{
case ContentType.Resource:
await CreateResourceAsync(request, cancellationToken).ConfigureAwait(false);
break;
case ContentType.News:
await CreateNewsAsync(request, cancellationToken).ConfigureAwait(false);
break;
case ContentType.Event:
await CreateEventAsync(request, cancellationToken).ConfigureAwait(false);
break;
}
}

private async Task CreateResourceAsync(CountryContentRequest request, CancellationToken ct)
{
var categoryId = request.ProposedCategoryId
?? throw new DomainException("CategoryId is required for resource requests.");

var resource = Resource.Draft(
request.ProposedTitleAr,
request.ProposedTitleEn,
request.ProposedDescriptionAr,
request.ProposedDescriptionEn,
request.ProposedResourceType ?? throw new DomainException("ResourceType is required for resource requests."),
categoryId,
request.CountryId,
request.RequestedById,
request.ProposedAssetFileId ?? throw new DomainException("AssetFileId is required for resource requests."),
[request.CountryId],
_clock);

resource.Publish(_clock);
_db.Add(resource);
}

private async Task CreateNewsAsync(CountryContentRequest request, CancellationToken ct)
{
string? featuredImageUrl = null;
if (request.ProposedAssetFileId.HasValue)
{
var asset = await _db.AssetFiles
.FirstOrDefaultAsync(a => a.Id == request.ProposedAssetFileId.Value, ct)
.ConfigureAwait(false);
featuredImageUrl = asset?.Url;
}

var news = News.Draft(
request.ProposedTitleAr,
request.ProposedTitleEn,
request.ProposedDescriptionAr,
request.ProposedDescriptionEn,
request.ProposedTopicId ?? throw new DomainException("TopicId is required for news requests."),
request.RequestedById,
featuredImageUrl,
_clock);

news.Publish(_clock);
_db.Add(news);
}

private async Task CreateEventAsync(CountryContentRequest request, CancellationToken ct)
{
string? featuredImageUrl = null;
if (request.ProposedAssetFileId.HasValue)
{
var asset = await _db.AssetFiles
.FirstOrDefaultAsync(a => a.Id == request.ProposedAssetFileId.Value, ct)
.ConfigureAwait(false);
featuredImageUrl = asset?.Url;
}

var ev = Event.Schedule(
request.ProposedTitleAr,
request.ProposedTitleEn,
request.ProposedDescriptionAr,
request.ProposedDescriptionEn,
request.ProposedStartsOn ?? throw new DomainException("StartsOn is required for event requests."),
request.ProposedEndsOn ?? throw new DomainException("EndsOn is required for event requests."),
request.ProposedLocationAr,
request.ProposedLocationEn,
request.ProposedOnlineMeetingUrl,
featuredImageUrl,
request.ProposedTopicId ?? throw new DomainException("TopicId is required for event requests."),
_clock);

_db.Add(ev);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ public async Task<Response<CountryContentRequestDto>> Handle(
entity.ProposedTitleAr, entity.ProposedTitleEn,
entity.ProposedDescriptionAr, entity.ProposedDescriptionEn,
entity.ProposedResourceType, entity.ProposedAssetFileId,
entity.ProposedTopicId, entity.ProposedStartsOn, entity.ProposedEndsOn,
entity.ProposedTopicId, entity.ProposedCategoryId,
entity.ProposedStartsOn, entity.ProposedEndsOn,
entity.ProposedLocationAr, entity.ProposedLocationEn, entity.ProposedOnlineMeetingUrl,
entity.SubmittedOn, entity.AdminNotesAr, entity.AdminNotesEn,
entity.ProcessedById, entity.ProcessedOn);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ public async Task<Response<PagedResult<CountryContentRequestDto>>> Handle(
r.ProposedTitleAr, r.ProposedTitleEn,
r.ProposedDescriptionAr, r.ProposedDescriptionEn,
r.ProposedResourceType, r.ProposedAssetFileId,
r.ProposedTopicId, r.ProposedStartsOn, r.ProposedEndsOn,
r.ProposedTopicId, r.ProposedCategoryId,
r.ProposedStartsOn, r.ProposedEndsOn,
r.ProposedLocationAr, r.ProposedLocationEn, r.ProposedOnlineMeetingUrl,
r.SubmittedOn, r.AdminNotesAr, r.AdminNotesEn,
r.ProcessedById, r.ProcessedOn),
Expand Down
17 changes: 13 additions & 4 deletions backend/src/CCE.Domain/Country/CountryResourceRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ private CountryContentRequest(
ResourceType? proposedResourceType,
System.Guid? proposedAssetFileId,
System.Guid? proposedTopicId,
System.Guid? proposedCategoryId,
System.DateTimeOffset? proposedStartsOn,
System.DateTimeOffset? proposedEndsOn,
string? proposedLocationAr,
Expand All @@ -43,6 +44,7 @@ private CountryContentRequest(
ProposedResourceType = proposedResourceType;
ProposedAssetFileId = proposedAssetFileId;
ProposedTopicId = proposedTopicId;
ProposedCategoryId = proposedCategoryId;
ProposedStartsOn = proposedStartsOn;
ProposedEndsOn = proposedEndsOn;
ProposedLocationAr = proposedLocationAr;
Expand All @@ -64,6 +66,7 @@ private CountryContentRequest(
// Resource-specific (null for News/Event)
public ResourceType? ProposedResourceType { get; private set; }
public System.Guid? ProposedAssetFileId { get; private set; }
public System.Guid? ProposedCategoryId { get; private set; }

// News/Event-specific
public System.Guid? ProposedTopicId { get; private set; }
Expand All @@ -90,6 +93,7 @@ public static CountryContentRequest SubmitResource(
string descriptionAr, string descriptionEn,
ResourceType resourceType,
System.Guid assetFileId,
System.Guid categoryId,
ISystemClock clock)
{
if (countryId == System.Guid.Empty) throw new DomainException("CountryId is required.");
Expand All @@ -99,12 +103,14 @@ public static CountryContentRequest SubmitResource(
if (string.IsNullOrWhiteSpace(descriptionAr)) throw new DomainException("DescriptionAr is required.");
if (string.IsNullOrWhiteSpace(descriptionEn)) throw new DomainException("DescriptionEn is required.");
if (assetFileId == System.Guid.Empty) throw new DomainException("AssetFileId is required.");
if (categoryId == System.Guid.Empty) throw new DomainException("CategoryId is required.");
return new CountryContentRequest(
System.Guid.NewGuid(), countryId, requestedById,
ContentType.Resource,
titleAr, titleEn, descriptionAr, descriptionEn,
resourceType, assetFileId,
null, null, null, null, null, null,
null, categoryId,
null, null, null, null, null,
clock.UtcNow);
}

Expand All @@ -129,7 +135,8 @@ public static CountryContentRequest SubmitNews(
ContentType.News,
titleAr, titleEn, contentAr, contentEn,
null, featuredImageAssetId,
topicId, null, null, null, null, null,
topicId, null,
null, null, null, null, null,
clock.UtcNow);
}

Expand All @@ -144,6 +151,7 @@ public static CountryContentRequest SubmitEvent(
string? locationAr,
string? locationEn,
string? onlineMeetingUrl,
System.Guid? featuredImageAssetId,
ISystemClock clock)
{
if (countryId == System.Guid.Empty) throw new DomainException("CountryId is required.");
Expand All @@ -158,8 +166,9 @@ public static CountryContentRequest SubmitEvent(
System.Guid.NewGuid(), countryId, requestedById,
ContentType.Event,
titleAr, titleEn, descriptionAr, descriptionEn,
null, null,
topicId, startsOn, endsOn, locationAr, locationEn, onlineMeetingUrl,
null, featuredImageAssetId,
topicId, null,
startsOn, endsOn, locationAr, locationEn, onlineMeetingUrl,
clock.UtcNow);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public void Configure(EntityTypeBuilder<CountryContentRequest> builder)
// Resource-specific (nullable for News/Event)
builder.Property(r => r.ProposedResourceType).HasConversion<int>().IsRequired(false);
builder.Property(r => r.ProposedAssetFileId).IsRequired(false);
builder.Property(r => r.ProposedCategoryId).IsRequired(false);

// News/Event-specific
builder.Property(r => r.ProposedTopicId).IsRequired(false);
Expand Down
Loading