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
163 changes: 163 additions & 0 deletions API/Controllers/PublisherController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
using Application.Commands.PublisherCommands.AddPublisher;
using Application.Commands.PublisherCommands.DeletePublisher;
using Application.Commands.PublisherCommands.UpdatePublisher;
using Application.Dtos.PublisherDtos;
using Application.Queries.PublisherQueries.GetAllPublishers;
using Application.Queries.PublisherQueries.GetPublisherById;
using MediatR;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations;

namespace API.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class PublisherController : ControllerBase
{
private readonly IMediator _mediator;
private readonly ILogger<PublisherController> _logger;

public PublisherController(IMediator mediator, ILogger<PublisherController> logger)
{
_mediator = mediator;
_logger = logger;
}

[HttpGet]
[Route("GetAll")]
[SwaggerOperation(Description = "Gets All Publishers")]
[SwaggerResponse(200, "Successfully retrieved Publishers.")]
[SwaggerResponse(400, "Invalid input data")]
[SwaggerResponse(404, "Publishers not found")]
public async Task<IActionResult> GetAllPublishers()
{
_logger.LogInformation("Fetching all Publishers at {time}", DateTime.Now.ToString("MM/dd/yyyy hh:mm tt"));

try
{
var operationResult = await _mediator.Send(new GetAllPublishersQuery());

if (operationResult.IsSuccess)
{
return Ok(operationResult.Data);
}
return BadRequest(new { message = operationResult.Message, errors = operationResult.ErrorMessage });
}

catch (Exception ex)
{
_logger.LogError(ex, "An error occurred while fetching all Publishers at {time}", DateTime.Now.ToString("MM/dd/yyyy hh:mm tt"));
return BadRequest(ex.InnerException);
}
}

[HttpGet]
[Route("GetById/{id}")]
[SwaggerOperation(Description = "Gets Publisher by Id")]
[SwaggerResponse(200, "Successfully retrieved Publisher.")]
[SwaggerResponse(400, "Invalid input data")]
[SwaggerResponse(404, "Publisher not found")]
public async Task<IActionResult> GetPublisher([FromRoute] int id)
{
_logger.LogInformation("Fetching Publisher with ID: {id} at {time}", id, DateTime.Now.ToString("MM/dd/yyyy hh:mm tt"));
try
{
var operationResult = await _mediator.Send(new GetPublisherByIdQuery(id));

if (operationResult.IsSuccess)
{
return Ok(operationResult.Data);
}
return BadRequest(new { message = operationResult.Message, errors = operationResult.ErrorMessage });
}

catch (Exception ex)
{
_logger.LogError(ex, "An error occurred while fetching Publisher with ID: {id} at {time}", id, DateTime.Now.ToString("MM/dd/yyyy hh:mm tt"));
return BadRequest(ex.InnerException);
}
}

[HttpPost]
[Route("Create")]
[SwaggerOperation(Description = "Adds a new Publisher")]
[SwaggerResponse(200, "Successfully added Publisher.")]
[SwaggerResponse(400, "Invalid input data")]
public async Task<IActionResult> AddPublisher([FromBody] AddPublisherDto dto)
{
_logger.LogInformation("Adding a new Publisher at {time}", DateTime.Now.ToString("MM/dd/yyyy hh:mm tt"));

try
{
var operationResult = await _mediator.Send(new AddPublisherCommand(dto));

if (operationResult.IsSuccess)
{
return Ok(operationResult.Data);
}
return BadRequest(new { message = operationResult.Message, errors = operationResult.ErrorMessage });
}

catch (Exception ex)
{
_logger.LogError(ex, "An error occurred while adding a new Publisher at {time}", DateTime.Now.ToString("MM/dd/yyyy hh:mm tt"));
return BadRequest(ex.InnerException);
}
}

[HttpPut]
[Route("Update")]
[SwaggerOperation(Description = "Updates a Publisher")]
[SwaggerResponse(200, "Successfully updated Publisher.")]
[SwaggerResponse(400, "Invalid input data")]
public async Task<IActionResult> UpdatePublisher([FromBody] UpdatePublisherDto dto)
{
_logger.LogInformation("Updating Publisher with ID: {id} at {time}", dto.PublisherId, DateTime.Now.ToString("MM/dd/yyyy hh:mm tt"));

try
{
var operationResult = await _mediator.Send(new UpdatePublisherCommand(dto));

if (operationResult.IsSuccess)
{
return Ok(operationResult.Data);
}
return BadRequest(new { message = operationResult.Message, errors = operationResult.ErrorMessage });
}

catch (Exception ex)
{
_logger.LogError(ex, "An error occurred while updating Publisher with ID: {id} at {time}", dto.PublisherId, DateTime.Now.ToString("MM/dd/yyyy hh:mm tt"));
return BadRequest(ex.InnerException);
}
}

[HttpDelete]
[Route("Delete/{id}")]
[SwaggerOperation(Description = "Deletes a Publisher")]
[SwaggerResponse(200, "Successfully deleted Publisher.")]
[SwaggerResponse(400, "Invalid input data")]
public async Task<IActionResult> DeletePublisher([FromRoute] int id)
{
_logger.LogInformation("Deleting Publisher with ID: {id} at {time}", id, DateTime.Now.ToString("MM/dd/yyyy hh:mm tt"));

try
{
var operationResult = await _mediator.Send(new DeletePublisherCommand(id));

if (operationResult.IsSuccess)
{
return Ok(operationResult.Data);
}
return BadRequest(new { message = operationResult.Message, errors = operationResult.ErrorMessage });
}

catch (Exception ex)
{
_logger.LogError(ex, "An error occurred while deleting Publisher with ID: {id} at {time}", id, DateTime.Now.ToString("MM/dd/yyyy hh:mm tt"));
return BadRequest(ex.InnerException);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using Application.Dtos.PublisherDtos;
using Application.Models;
using MediatR;

namespace Application.Commands.PublisherCommands.AddPublisher
{
public class AddPublisherCommand(AddPublisherDto dto) : IRequest<OperationResult<GetPublisherDto>>
{
public AddPublisherDto Dto { get; set; } = dto;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using Application.Dtos.PublisherDtos;
using Application.Interfaces.RepositoryInterfaces;
using Application.Models;
using AutoMapper;
using Domain.Entities.Metadata;
using MediatR;

namespace Application.Commands.PublisherCommands.AddPublisher
{
internal class AddPublisherCommandHandler(IGenericRepository<Publisher, int> repository, IMapper mapper) : IRequestHandler<AddPublisherCommand, OperationResult<GetPublisherDto>>
{
private readonly IGenericRepository<Publisher, int> _repository = repository;
private readonly IMapper _mapper = mapper;

public async Task<OperationResult<GetPublisherDto>> Handle(AddPublisherCommand request, CancellationToken cancellationToken)
{
try
{
Publisher publisher = new()
{
Name = request.Dto.Name,
Address = request.Dto.Address,
ContactInfo = request.Dto.ContactInfo
};

var createdPublisher = await _repository.AddAsync(publisher);
var mappedPublisher = _mapper.Map<GetPublisherDto>(createdPublisher);
return OperationResult<GetPublisherDto>.Success(mappedPublisher);
}
catch (Exception e)
{
return OperationResult<GetPublisherDto>.Failure(e.Message);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using FluentValidation;

namespace Application.Commands.PublisherCommands.AddPublisher
{
public class AddPublisherCommandValidator : AbstractValidator<AddPublisherCommand>
{
public AddPublisherCommandValidator()
{
RuleFor(x => x.Dto.Name)
.NotEmpty().WithMessage("Name is required")
.MaximumLength(50).WithMessage("Name must not exceed 50 characters");

RuleFor(x => x.Dto.Address)
.NotEmpty().WithMessage("Address is required");

RuleFor(x => x.Dto.ContactInfo)
.NotEmpty().WithMessage("Contact info is required");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using Application.Dtos.PublisherDtos;
using Application.Models;
using MediatR;

namespace Application.Commands.PublisherCommands.DeletePublisher
{
public class DeletePublisherCommand(int id) : IRequest<OperationResult<bool>>
{
public int Id { get; set; } = id;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using Application.Interfaces.RepositoryInterfaces;
using Application.Models;
using AutoMapper;
using Domain.Entities.Metadata;
using MediatR;

namespace Application.Commands.PublisherCommands.DeletePublisher
{
internal class DeletePublisherCommandHandler(IGenericRepository<Publisher, int> repository, IMapper mapper) : IRequestHandler<DeletePublisherCommand, OperationResult<bool>>
{
private readonly IGenericRepository<Publisher, int> _repository = repository;
private readonly IMapper _mapper = mapper;

public async Task<OperationResult<bool>> Handle(DeletePublisherCommand request, CancellationToken cancellationToken)
{
try
{
var successfulDeletion = await _repository.DeleteAsync(request.Id);
if (!successfulDeletion)
{
return OperationResult<bool>.Failure("Publisher not found");
}
return OperationResult<bool>.Success(true);
}
catch (Exception e)
{
return OperationResult<bool>.Failure(e.Message);

}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using FluentValidation;

namespace Application.Commands.PublisherCommands.DeletePublisher
{
public class DeletePublisherCommandValidator : AbstractValidator<DeletePublisherCommand>
{
public DeletePublisherCommandValidator()
{
RuleFor(x => x.Id)
.GreaterThan(0).NotNull().WithMessage("Id must be greater than 0");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using Application.Dtos.PublisherDtos;
using Application.Models;
using MediatR;

namespace Application.Commands.PublisherCommands.UpdatePublisher
{
public class UpdatePublisherCommand(UpdatePublisherDto dto) : IRequest<OperationResult<GetPublisherDto>>
{
public UpdatePublisherDto Dto { get; set; } = dto;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using Application.Dtos.PublisherDtos;
using Application.Interfaces.RepositoryInterfaces;
using Application.Models;
using AutoMapper;
using Domain.Entities.Metadata;
using MediatR;

namespace Application.Commands.PublisherCommands.UpdatePublisher
{
internal class UpdatePublisherCommandHandler(IGenericRepository<Publisher, int> repository, IMapper mapper) : IRequestHandler<UpdatePublisherCommand, OperationResult<GetPublisherDto>>
{
private readonly IGenericRepository<Publisher, int> _repository = repository;
private readonly IMapper _mapper = mapper;

public async Task<OperationResult<GetPublisherDto>> Handle(UpdatePublisherCommand request, CancellationToken cancellationToken)
{
try
{
var publisher = await _repository.GetByIdAsync(request.Dto.PublisherId);
if (publisher is null)
{
return OperationResult<GetPublisherDto>.Failure("Publisher not found");
}


publisher.Name = request.Dto.Name;
publisher.Address = request.Dto.Address;
publisher.ContactInfo = request.Dto.ContactInfo;

var updatedPublisher = await _repository.UpdateAsync(publisher);
var mappedPublisher = _mapper.Map<GetPublisherDto>(updatedPublisher);
return OperationResult<GetPublisherDto>.Success(mappedPublisher);
}
catch (Exception e)
{
return OperationResult<GetPublisherDto>.Failure(e.Message);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

using FluentValidation;

namespace Application.Commands.PublisherCommands.UpdatePublisher
{
public class UpdatePublisherCommandValidator : AbstractValidator<UpdatePublisherCommand>
{
public UpdatePublisherCommandValidator()
{
RuleFor(x => x.Dto.PublisherId)
.GreaterThan(0).NotNull().WithMessage("Id must be greater than 0");

RuleFor(x => x.Dto.Name)
.NotEmpty().WithMessage("Name is required")
.MaximumLength(50).WithMessage("Name must not exceed 50 characters");

RuleFor(x => x.Dto.Address)
.NotEmpty().WithMessage("Address is required");

RuleFor(x => x.Dto.ContactInfo)
.NotEmpty().WithMessage("Contact info is required");
}
}
}
1 change: 1 addition & 0 deletions Application/DependencyInjection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public static IServiceCollection AddApplication(this IServiceCollection services
services.AddAutoMapper(typeof(LibraryBranchMappingProfiles).Assembly);
services.AddAutoMapper(typeof(GenreMappingProfiles).Assembly);
services.AddAutoMapper(typeof(ReviewMappingProfiles).Assembly);
services.AddAutoMapper(typeof(PublisherMappingProfiles).Assembly);

// Register validators
services.AddValidatorsFromAssemblyContaining<AddAuthorCommandValidator>();
Expand Down
10 changes: 10 additions & 0 deletions Application/Dtos/PublisherDtos/AddPublisherDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

namespace Application.Dtos.PublisherDtos
{
public class AddPublisherDto
{
public string Name { get; set; }
public string? Address { get; set; }
public string? ContactInfo { get; set; }
}
}
Loading
Loading