diff --git a/src/Sonarr.Api.V5/ImportLists/ImportListExclusionBulkResource.cs b/src/Sonarr.Api.V5/ImportLists/ImportListExclusionBulkResource.cs new file mode 100644 index 000000000..667d970fb --- /dev/null +++ b/src/Sonarr.Api.V5/ImportLists/ImportListExclusionBulkResource.cs @@ -0,0 +1,6 @@ +namespace Sonarr.Api.V5.ImportLists; + +public class ImportListExclusionBulkResource +{ + public required HashSet Ids { get; set; } +} diff --git a/src/Sonarr.Api.V5/ImportLists/ImportListExclusionController.cs b/src/Sonarr.Api.V5/ImportLists/ImportListExclusionController.cs new file mode 100644 index 000000000..fd9ed5cbe --- /dev/null +++ b/src/Sonarr.Api.V5/ImportLists/ImportListExclusionController.cs @@ -0,0 +1,86 @@ +using FluentValidation; +using Microsoft.AspNetCore.Mvc; +using NzbDrone.Core.Datastore; +using NzbDrone.Core.ImportLists.Exclusions; +using Sonarr.Http; +using Sonarr.Http.Extensions; +using Sonarr.Http.REST; +using Sonarr.Http.REST.Attributes; + +namespace Sonarr.Api.V5.ImportLists; + +[V5ApiController] +public class ImportListExclusionController : RestController +{ + private readonly IImportListExclusionService _importListExclusionService; + + public ImportListExclusionController(IImportListExclusionService importListExclusionService, + ImportListExclusionExistsValidator importListExclusionExistsValidator) + { + _importListExclusionService = importListExclusionService; + + SharedValidator.RuleFor(c => c.TvdbId).Cascade(CascadeMode.Stop) + .NotEmpty() + .SetValidator(importListExclusionExistsValidator); + + SharedValidator.RuleFor(c => c.Title).NotEmpty(); + } + + protected override ImportListExclusionResource GetResourceById(int id) + { + return _importListExclusionService.Get(id).ToResource(); + } + + [HttpGet] + [Produces("application/json")] + public PagingResource GetImportListExclusions([FromQuery] PagingRequestResource paging) + { + var pagingResource = new PagingResource(paging); + var pageSpec = pagingResource.MapToPagingSpec( + new HashSet(StringComparer.OrdinalIgnoreCase) + { + "id", + "title", + "tvdbId" + }, + "id", + SortDirection.Descending); + + return pageSpec.ApplyToPage(_importListExclusionService.Paged, ImportListExclusionResourceMapper.ToResource); + } + + [RestPostById] + [Consumes("application/json")] + public ActionResult AddImportListExclusion([FromBody] ImportListExclusionResource resource) + { + var importListExclusion = _importListExclusionService.Add(resource.ToModel()); + + return Created(importListExclusion.Id); + } + + [RestPutById] + [Consumes("application/json")] + public ActionResult UpdateImportListExclusion([FromBody] ImportListExclusionResource resource) + { + _importListExclusionService.Update(resource.ToModel()); + + return Accepted(resource.Id); + } + + [RestDeleteById] + public ActionResult DeleteImportListExclusion(int id) + { + _importListExclusionService.Delete(id); + + return NoContent(); + } + + [HttpDelete("bulk")] + [Consumes("application/json")] + public ActionResult DeleteImportListExclusions([FromBody] ImportListExclusionBulkResource resource) + { + _importListExclusionService.Delete(resource.Ids.ToList()); + + return NoContent(); + } +} diff --git a/src/Sonarr.Api.V5/ImportLists/ImportListExclusionExistsValidator.cs b/src/Sonarr.Api.V5/ImportLists/ImportListExclusionExistsValidator.cs new file mode 100644 index 000000000..4b06274cc --- /dev/null +++ b/src/Sonarr.Api.V5/ImportLists/ImportListExclusionExistsValidator.cs @@ -0,0 +1,31 @@ +using FluentValidation.Validators; +using NzbDrone.Core.ImportLists.Exclusions; + +namespace Sonarr.Api.V5.ImportLists; + +public class ImportListExclusionExistsValidator : PropertyValidator +{ + private readonly IImportListExclusionService _importListExclusionService; + + public ImportListExclusionExistsValidator(IImportListExclusionService importListExclusionService) + { + _importListExclusionService = importListExclusionService; + } + + protected override string GetDefaultMessageTemplate() => "This exclusion has already been added."; + + protected override bool IsValid(PropertyValidatorContext context) + { + if (context.PropertyValue == null) + { + return true; + } + + if (context.InstanceToValidate is not ImportListExclusionResource listExclusionResource) + { + return true; + } + + return !_importListExclusionService.All().Exists(v => v.TvdbId == (int)context.PropertyValue && v.Id != listExclusionResource.Id); + } +} diff --git a/src/Sonarr.Api.V5/ImportLists/ImportListExclusionResource.cs b/src/Sonarr.Api.V5/ImportLists/ImportListExclusionResource.cs new file mode 100644 index 000000000..e3a2a6aa5 --- /dev/null +++ b/src/Sonarr.Api.V5/ImportLists/ImportListExclusionResource.cs @@ -0,0 +1,38 @@ +using NzbDrone.Core.ImportLists.Exclusions; +using Sonarr.Http.REST; + +namespace Sonarr.Api.V5.ImportLists; + +public class ImportListExclusionResource : RestResource +{ + public int TvdbId { get; set; } + public string? Title { get; set; } +} + +public static class ImportListExclusionResourceMapper +{ + public static ImportListExclusionResource ToResource(this ImportListExclusion model) + { + return new ImportListExclusionResource + { + Id = model.Id, + TvdbId = model.TvdbId, + Title = model.Title, + }; + } + + public static ImportListExclusion ToModel(this ImportListExclusionResource resource) + { + return new ImportListExclusion + { + Id = resource.Id, + TvdbId = resource.TvdbId, + Title = resource.Title + }; + } + + public static List ToResource(this IEnumerable models) + { + return models.Select(ToResource).ToList(); + } +}