From 943946c7f9f7b79c8674128d51f2cc87f3fa5e8f Mon Sep 17 00:00:00 2001 From: eggwhat Date: Fri, 26 Apr 2024 16:12:03 +0200 Subject: [PATCH] (#87) add events with handlers for creating and deleting organizers --- .../Program.cs | 6 ++-- .../Dto/OrganizationDto.cs | 1 + .../Handlers/OrganizerRightsGrantedHandler.cs | 27 ++++++++++++++ .../Handlers/OrganizerRightsRevokedHandler.cs | 36 +++++++++++++++++++ .../Events/External/OrganizerRightsGranted.cs | 17 +++++++++ .../Events/External/OrganizerRightsRevoked.cs | 16 +++++++++ .../OrganizerAlreadyAddedException.cs | 13 +++++++ .../Exceptions/OrganizerNotFoundException.cs | 13 +++++++ .../Entities/Organization.cs | 6 +++- .../Repositories/IOrganizationRepository.cs | 1 + .../Mongo/Documents/Extensions.cs | 8 +++-- .../Mongo/Documents/OrganizationDocument.cs | 4 ++- .../OrganizationMongoRepository.cs | 8 +++++ 13 files changed, 148 insertions(+), 8 deletions(-) create mode 100644 MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Events/External/Handlers/OrganizerRightsGrantedHandler.cs create mode 100644 MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Events/External/Handlers/OrganizerRightsRevokedHandler.cs create mode 100644 MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Events/External/OrganizerRightsGranted.cs create mode 100644 MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Events/External/OrganizerRightsRevoked.cs create mode 100644 MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Exceptions/OrganizerAlreadyAddedException.cs create mode 100644 MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Exceptions/OrganizerNotFoundException.cs diff --git a/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Api/Program.cs b/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Api/Program.cs index bd875c068..ed0bcde1e 100644 --- a/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Api/Program.cs +++ b/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Api/Program.cs @@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using MiniSpace.Services.Organizations.Application; +using MiniSpace.Services.Organizations.Application.Commands; using MiniSpace.Services.Organizations.Infrastructure; namespace MiniSpace.Services.Organizations.Api @@ -31,9 +32,8 @@ public static async Task Main(string[] args) //.Get>("organizations/user") //.Get>("organizations/root") //.Get>("organizations/{organizationId}/children") - //.Get>("organizers") - //.Post("organizations", - // afterDispatch: (cmd, ctx) => ctx.Response.Created($"organizations/{cmd.OrganizationId}")) + .Post("organizations", + afterDispatch: (cmd, ctx) => ctx.Response.Created($"organizations/root")) //.Post("organizations/user") //.Delete("organizations/user") )) diff --git a/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Dto/OrganizationDto.cs b/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Dto/OrganizationDto.cs index d39bff20a..fed6c1795 100644 --- a/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Dto/OrganizationDto.cs +++ b/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Dto/OrganizationDto.cs @@ -5,6 +5,7 @@ public class OrganizationDto public Guid Id { get; set; } public string Name { get; set; } public Guid ParentId { get; set; } + public int MemberCount { get; set; } } } diff --git a/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Events/External/Handlers/OrganizerRightsGrantedHandler.cs b/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Events/External/Handlers/OrganizerRightsGrantedHandler.cs new file mode 100644 index 000000000..c267c0b4b --- /dev/null +++ b/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Events/External/Handlers/OrganizerRightsGrantedHandler.cs @@ -0,0 +1,27 @@ +using Convey.CQRS.Events; +using MiniSpace.Services.Organizations.Application.Exceptions; +using MiniSpace.Services.Organizations.Core.Entities; +using MiniSpace.Services.Organizations.Core.Repositories; + +namespace MiniSpace.Services.Organizations.Application.Events.External.Handlers +{ + public class OrganizerRightsGrantedHandler : IEventHandler + { + private readonly IOrganizerRepository _organizerRepository; + + public OrganizerRightsGrantedHandler(IOrganizerRepository organizerRepository) + { + _organizerRepository = organizerRepository; + } + + public async Task HandleAsync(OrganizerRightsGranted @event, CancellationToken cancellationToken) + { + if (await _organizerRepository.ExistsAsync(@event.UserId)) + { + throw new OrganizerAlreadyAddedException(@event.UserId); + } + + await _organizerRepository.AddAsync(new Organizer(@event.UserId)); + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Events/External/Handlers/OrganizerRightsRevokedHandler.cs b/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Events/External/Handlers/OrganizerRightsRevokedHandler.cs new file mode 100644 index 000000000..ae4a671af --- /dev/null +++ b/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Events/External/Handlers/OrganizerRightsRevokedHandler.cs @@ -0,0 +1,36 @@ +using Convey.CQRS.Events; +using MiniSpace.Services.Organizations.Application.Exceptions; +using MiniSpace.Services.Organizations.Core.Repositories; + +namespace MiniSpace.Services.Organizations.Application.Events.External.Handlers +{ + public class OrganizerRightsRevokedHandler : IEventHandler + { + private readonly IOrganizerRepository _organizerRepository; + private readonly IOrganizationRepository _organizationRepository; + + public OrganizerRightsRevokedHandler(IOrganizerRepository organizerRepository, IOrganizationRepository organizationRepository) + { + _organizerRepository = organizerRepository; + _organizationRepository = organizationRepository; + } + + public async Task HandleAsync(OrganizerRightsRevoked @event, CancellationToken cancellationToken) + { + var organizer = await _organizerRepository.GetAsync(@event.UserId); + if (organizer is null) + { + throw new OrganizerNotFoundException(@event.UserId); + } + + var organizerOrganizations = await _organizationRepository.GetOrganizerOrganizationsAsync(@event.UserId); + foreach (var organization in organizerOrganizations) + { + organization.RemoveOrganizer(organizer); + await _organizationRepository.UpdateAsync(organization); + } + + await _organizerRepository.DeleteAsync(@event.UserId); + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Events/External/OrganizerRightsGranted.cs b/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Events/External/OrganizerRightsGranted.cs new file mode 100644 index 000000000..771c3bb87 --- /dev/null +++ b/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Events/External/OrganizerRightsGranted.cs @@ -0,0 +1,17 @@ +using Convey.CQRS.Events; +using Convey.MessageBrokers; +using MiniSpace.Services.Organizations.Core.Entities; + +namespace MiniSpace.Services.Organizations.Application.Events.External +{ + [Message("identity") ] + public class OrganizerRightsGranted : IEvent + { + public Guid UserId { get; } + + public OrganizerRightsGranted(Guid userId) + { + UserId = userId; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Events/External/OrganizerRightsRevoked.cs b/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Events/External/OrganizerRightsRevoked.cs new file mode 100644 index 000000000..90c7a2f4d --- /dev/null +++ b/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Events/External/OrganizerRightsRevoked.cs @@ -0,0 +1,16 @@ +using Convey.CQRS.Events; +using Convey.MessageBrokers; + +namespace MiniSpace.Services.Organizations.Application.Events.External +{ + [Message("identity")] + public class OrganizerRightsRevoked: IEvent + { + public Guid UserId { get; } + + public OrganizerRightsRevoked(Guid userId) + { + UserId = userId; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Exceptions/OrganizerAlreadyAddedException.cs b/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Exceptions/OrganizerAlreadyAddedException.cs new file mode 100644 index 000000000..37653a2fa --- /dev/null +++ b/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Exceptions/OrganizerAlreadyAddedException.cs @@ -0,0 +1,13 @@ +namespace MiniSpace.Services.Organizations.Application.Exceptions +{ + public class OrganizerAlreadyAddedException : AppException + { + public override string Code { get; } = "organizer_already_added"; + public Guid OrganizerId { get; } + + public OrganizerAlreadyAddedException(Guid organizerId) : base($"Organizer with ID: '{organizerId}' was already added.") + { + OrganizerId = organizerId; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Exceptions/OrganizerNotFoundException.cs b/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Exceptions/OrganizerNotFoundException.cs new file mode 100644 index 000000000..9abb900be --- /dev/null +++ b/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Application/Exceptions/OrganizerNotFoundException.cs @@ -0,0 +1,13 @@ +namespace MiniSpace.Services.Organizations.Application.Exceptions +{ + public class OrganizerNotFoundException : AppException + { + public override string Code { get; } = "organizer_not_found"; + public Guid OrganizerId { get; } + + public OrganizerNotFoundException(Guid organizerId) : base($"Organizer with ID: {organizerId} was not found.") + { + OrganizerId = organizerId; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Core/Entities/Organization.cs b/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Core/Entities/Organization.cs index facbacd36..f1329d140 100644 --- a/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Core/Entities/Organization.cs +++ b/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Core/Entities/Organization.cs @@ -14,11 +14,15 @@ public IEnumerable Organizers private set => _organizers = new HashSet(value); } - public Organization(Guid id, string name, Guid parentId) + public Organization(Guid id, string name, Guid parentId, IEnumerable organizers = null) { Id = id; Name = name; ParentId = parentId; + Organizers = organizers ?? Enumerable.Empty(); } + + public void RemoveOrganizer(Organizer organizer) + => _organizers.Remove(organizer); } } \ No newline at end of file diff --git a/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Core/Repositories/IOrganizationRepository.cs b/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Core/Repositories/IOrganizationRepository.cs index 6bb1f3291..2e13079e1 100644 --- a/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Core/Repositories/IOrganizationRepository.cs +++ b/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Core/Repositories/IOrganizationRepository.cs @@ -5,6 +5,7 @@ namespace MiniSpace.Services.Organizations.Core.Repositories public interface IOrganizationRepository { Task GetAsync(Guid id); + Task> GetOrganizerOrganizationsAsync(Guid organizerId); Task AddAsync(Organization organization); Task UpdateAsync(Organization organization); Task DeleteAsync(Guid id); diff --git a/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Infrastructure/Mongo/Documents/Extensions.cs b/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Infrastructure/Mongo/Documents/Extensions.cs index 02d0c94a8..521b1436d 100644 --- a/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Infrastructure/Mongo/Documents/Extensions.cs +++ b/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Infrastructure/Mongo/Documents/Extensions.cs @@ -6,14 +6,15 @@ namespace MiniSpace.Services.Organizations.Infrastructure.Mongo.Documents public static class Extensions { public static Organization AsEntity(this OrganizationDocument document) - => new Organization(document.Id, document.Name, document.ParentId); + => new Organization(document.Id, document.Name, document.ParentId, document.Organizers); public static OrganizationDocument AsDocument(this Organization entity) => new OrganizationDocument() { Id = entity.Id, Name = entity.Name, - ParentId = entity.ParentId + ParentId = entity.ParentId, + Organizers = entity.Organizers }; public static OrganizationDto AsDto(this OrganizationDocument document) @@ -21,7 +22,8 @@ public static OrganizationDto AsDto(this OrganizationDocument document) { Id = document.Id, Name = document.Name, - ParentId = document.ParentId + ParentId = document.ParentId, + MemberCount = document.Organizers.Count() }; public static Organizer AsEntity(this OrganizerDocument document) diff --git a/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Infrastructure/Mongo/Documents/OrganizationDocument.cs b/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Infrastructure/Mongo/Documents/OrganizationDocument.cs index 387e19249..913f7da50 100644 --- a/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Infrastructure/Mongo/Documents/OrganizationDocument.cs +++ b/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Infrastructure/Mongo/Documents/OrganizationDocument.cs @@ -1,11 +1,13 @@ using Convey.Types; +using MiniSpace.Services.Organizations.Core.Entities; namespace MiniSpace.Services.Organizations.Infrastructure.Mongo.Documents { - public class OrganizationDocument:IIdentifiable + public class OrganizationDocument: IIdentifiable { public Guid Id { get; set; } public string Name { get; set; } public Guid ParentId { get; set; } + public IEnumerable Organizers { get; set; } } } \ No newline at end of file diff --git a/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Infrastructure/Mongo/Repositories/OrganizationMongoRepository.cs b/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Infrastructure/Mongo/Repositories/OrganizationMongoRepository.cs index 88e684578..452841d0e 100644 --- a/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Infrastructure/Mongo/Repositories/OrganizationMongoRepository.cs +++ b/MiniSpace.Services.Organizations/src/MiniSpace.Services.Organizations.Infrastructure/Mongo/Repositories/OrganizationMongoRepository.cs @@ -20,6 +20,14 @@ public async Task GetAsync(Guid id) return organization?.AsEntity(); } + + public async Task> GetOrganizerOrganizationsAsync(Guid organizerId) + { + var organizations = await _repository.FindAsync(o + => o.Organizers.Any(x => x.Id == organizerId)); + + return organizations?.Select(o => o.AsEntity()); + } public Task AddAsync(Organization organization) => _repository.AddAsync(organization.AsDocument());