diff --git a/src/Application/Common/Models/Dtos/Physical/RoomDto.cs b/src/Application/Common/Models/Dtos/Physical/RoomDto.cs index a2ed7b95..ff0ab27a 100644 --- a/src/Application/Common/Models/Dtos/Physical/RoomDto.cs +++ b/src/Application/Common/Models/Dtos/Physical/RoomDto.cs @@ -11,7 +11,7 @@ public class RoomDto : IMapFrom public string Name { get; set; } = null!; public string? Description { get; set; } public StaffDto? Staff { get; set; } - public DepartmentDto? Department { get; set; } + public DepartmentDto Department { get; set; } public int Capacity { get; set; } public int NumberOfLockers { get; set; } public bool IsAvailable { get; set; } diff --git a/src/Application/Rooms/Commands/EnableRoom.cs b/src/Application/Rooms/Commands/EnableRoom.cs index 0e0cf048..af5d710b 100644 --- a/src/Application/Rooms/Commands/EnableRoom.cs +++ b/src/Application/Rooms/Commands/EnableRoom.cs @@ -1,12 +1,59 @@ +using Application.Common.Exceptions; +using Application.Common.Interfaces; using Application.Common.Models.Dtos.Physical; +using AutoMapper; +using FluentValidation; using MediatR; +using Microsoft.EntityFrameworkCore; namespace Application.Rooms.Commands; public class EnableRoom { + public class Validator : AbstractValidator + { + public Validator() + { + RuleLevelCascadeMode = CascadeMode.Stop; + RuleFor(x => x.RoomId) + .NotEmpty().WithMessage("RoomId is required."); + } + } public record Command : IRequest { public Guid RoomId { get; init; } } + + public class CommandHandler : IRequestHandler + { + private readonly IApplicationDbContext _context; + private readonly IMapper _mapper; + + public CommandHandler(IApplicationDbContext context, IMapper mapper) + { + _context = context; + _mapper = mapper; + } + + public async Task Handle(Command request, CancellationToken cancellationToken) + { + var room = await _context.Rooms + .FirstOrDefaultAsync(x => x.Id.Equals(request.RoomId), cancellationToken: cancellationToken); + + if (room is null) + { + throw new KeyNotFoundException("Room does not exist."); + } + + if (room.IsAvailable) + { + throw new ConflictException("Room has already been enabled."); + } + + room.IsAvailable = true; + var result = _context.Rooms.Update(room); + await _context.SaveChangesAsync(cancellationToken); + return _mapper.Map(result.Entity); + } + } } \ No newline at end of file diff --git a/tests/Application.Tests.Integration/Rooms/Commands/EnableRoomTests.cs b/tests/Application.Tests.Integration/Rooms/Commands/EnableRoomTests.cs new file mode 100644 index 00000000..fa07d0b8 --- /dev/null +++ b/tests/Application.Tests.Integration/Rooms/Commands/EnableRoomTests.cs @@ -0,0 +1,94 @@ +using Application.Common.Exceptions; +using Application.Rooms.Commands; +using Domain.Entities; +using Domain.Entities.Physical; +using FluentAssertions; +using Xunit; + +namespace Application.Tests.Integration.Rooms.Commands; + +public class EnableRoomTests : BaseClassFixture +{ + public EnableRoomTests(CustomApiFactory apiFactory) : base(apiFactory) + { + } + + [Fact] + public async Task ShouldEnableRoom_WhenRoomExistsAndIsDisabled() + { + // Arrange + var department = CreateDepartment(); + var folder = CreateFolder(); + var locker = CreateLocker(folder); + var room = CreateRoom(department, locker); + folder.IsAvailable = false; + locker.IsAvailable = false; + room.IsAvailable = false; + await AddAsync(room); + + var command = new EnableRoom.Command() + { + RoomId = room.Id + }; + + // Act + var result = await SendAsync(command); + + // Assert + var folderResult = await FindAsync(folder.Id); + var lockerResult = await FindAsync(locker.Id); + + result.IsAvailable.Should().BeTrue(); + folderResult!.IsAvailable.Should().BeFalse(); + lockerResult!.IsAvailable.Should().BeFalse(); + + // Cleanup + Remove(folder); + Remove(locker); + Remove(room); + Remove(await FindAsync(department.Id)); + } + + [Fact] + public async Task ShouldThrowKeyNotFoundException_WhenRoomDoesNotExist() + { + // Arrange + var command = new EnableRoom.Command() + { + RoomId = Guid.NewGuid() + }; + + // Act + var action = async () => await SendAsync(command); + + // Assert + await action.Should().ThrowAsync() + .WithMessage("Room does not exist."); + } + + [Fact] + public async Task ShouldThrowConflictException_WhenRoomIsAlreadyAvailable() + { + // Arrange + var department = CreateDepartment(); + var room = CreateRoom(department); + room.IsAvailable = true; + await AddAsync(room); + + var command = new EnableRoom.Command() + { + RoomId = room.Id + }; + + // Act + var action = async () => await SendAsync(command); + + // Assert + await action.Should().ThrowAsync() + .WithMessage("Room has already been enabled."); + + // Cleanup + Remove(room); + Remove(await FindAsync(department.Id)); + } +} \ No newline at end of file