diff --git a/frontend/src/Components/Form/TextTagInputConnector.js b/frontend/src/Components/Form/TextTagInputConnector.js
index 587066610..e0df9342d 100644
--- a/frontend/src/Components/Form/TextTagInputConnector.js
+++ b/frontend/src/Components/Form/TextTagInputConnector.js
@@ -46,13 +46,13 @@ class TextTagInputConnector extends Component {
// to oddities with restrictions (as an example).
const newValue = [...valueArray];
- const newTags = split(tag.name);
+ const newTags = tag.name.startsWith('/') ? [tag.name] : split(tag.name);
newTags.forEach((newTag) => {
newValue.push(newTag.trim());
});
- onChange({ name, value: newValue.join(',') });
+ onChange({ name, value: newValue });
}
onTagDelete = ({ index }) => {
diff --git a/frontend/src/Settings/Profiles/Release/EditReleaseProfileModalContent.js b/frontend/src/Settings/Profiles/Release/EditReleaseProfileModalContent.js
index 1c90faa36..cbc720a89 100644
--- a/frontend/src/Settings/Profiles/Release/EditReleaseProfileModalContent.js
+++ b/frontend/src/Settings/Profiles/Release/EditReleaseProfileModalContent.js
@@ -13,7 +13,7 @@ import FormLabel from 'Components/Form/FormLabel';
import FormInputGroup from 'Components/Form/FormInputGroup';
import styles from './EditReleaseProfileModalContent.css';
-const tagInputDelimiters = ['Tab', 'Enter', ','];
+const tagInputDelimiters = ['Tab', 'Enter'];
function EditReleaseProfileModalContent(props) {
const {
diff --git a/frontend/src/Settings/Profiles/Release/ReleaseProfile.js b/frontend/src/Settings/Profiles/Release/ReleaseProfile.js
index 8daef52a3..f9dfea1f0 100644
--- a/frontend/src/Settings/Profiles/Release/ReleaseProfile.js
+++ b/frontend/src/Settings/Profiles/Release/ReleaseProfile.js
@@ -90,7 +90,7 @@ class ReleaseProfile extends Component {
{
- split(required).map((item) => {
+ required.map((item) => {
if (!item) {
return null;
}
@@ -126,7 +126,7 @@ class ReleaseProfile extends Component {
{
- split(ignored).map((item) => {
+ ignored.map((item) => {
if (!item) {
return null;
}
@@ -195,8 +195,8 @@ ReleaseProfile.propTypes = {
id: PropTypes.number.isRequired,
name: PropTypes.string,
enabled: PropTypes.bool.isRequired,
- required: PropTypes.string.isRequired,
- ignored: PropTypes.string.isRequired,
+ required: PropTypes.arrayOf(PropTypes.string).isRequired,
+ ignored: PropTypes.arrayOf(PropTypes.string).isRequired,
preferred: PropTypes.arrayOf(PropTypes.object).isRequired,
tags: PropTypes.arrayOf(PropTypes.number).isRequired,
indexerId: PropTypes.number.isRequired,
diff --git a/src/NzbDrone.Api/Restrictions/RestrictionResource.cs b/src/NzbDrone.Api/Restrictions/RestrictionResource.cs
index 2849a8d34..3989eefa2 100644
--- a/src/NzbDrone.Api/Restrictions/RestrictionResource.cs
+++ b/src/NzbDrone.Api/Restrictions/RestrictionResource.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.Profiles.Releases;
@@ -27,8 +28,8 @@ namespace NzbDrone.Api.Restrictions
{
Id = model.Id,
- Required = model.Required,
- Ignored = model.Ignored,
+ Required = string.Join(",", model.Required),
+ Ignored = string.Join(",", model.Ignored),
Tags = new HashSet(model.Tags)
};
}
@@ -41,8 +42,8 @@ namespace NzbDrone.Api.Restrictions
{
Id = resource.Id,
- Required = resource.Required,
- Ignored = resource.Ignored,
+ Required = resource.Required.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(),
+ Ignored = resource.Ignored.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(),
Tags = new HashSet(resource.Tags)
};
}
diff --git a/src/NzbDrone.Core.Test/DecisionEngineTests/ReleaseRestrictionsSpecificationFixture.cs b/src/NzbDrone.Core.Test/DecisionEngineTests/ReleaseRestrictionsSpecificationFixture.cs
index 208782c6a..838aeb416 100644
--- a/src/NzbDrone.Core.Test/DecisionEngineTests/ReleaseRestrictionsSpecificationFixture.cs
+++ b/src/NzbDrone.Core.Test/DecisionEngineTests/ReleaseRestrictionsSpecificationFixture.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.Linq;
using FluentAssertions;
using Moq;
using NUnit.Framework;
@@ -33,7 +34,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
Mocker.SetConstant(Mocker.Resolve());
}
- private void GivenRestictions(string required, string ignored)
+ private void GivenRestictions(List required, List ignored)
{
Mocker.GetMock()
.Setup(s => s.EnabledForTags(It.IsAny>(), It.IsAny()))
@@ -60,7 +61,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[Test]
public void should_be_true_when_title_contains_one_required_term()
{
- GivenRestictions("WEBRip", null);
+ GivenRestictions(new List { "WEBRip" }, null);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
}
@@ -68,7 +69,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[Test]
public void should_be_false_when_title_does_not_contain_any_required_terms()
{
- GivenRestictions("doesnt,exist", null);
+ GivenRestictions(new List { "doesnt", "exist" }, null);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse();
}
@@ -76,7 +77,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[Test]
public void should_be_true_when_title_does_not_contain_any_ignored_terms()
{
- GivenRestictions(null, "ignored");
+ GivenRestictions(null, new List { "ignored" });
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
}
@@ -84,7 +85,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[Test]
public void should_be_false_when_title_contains_one_anded_ignored_terms()
{
- GivenRestictions(null, "edited");
+ GivenRestictions(null, new List { "edited" });
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse();
}
@@ -95,7 +96,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[TestCase("X264,NOTTHERE")]
public void should_ignore_case_when_matching_required(string required)
{
- GivenRestictions(required, null);
+ GivenRestictions(required.Split(',').ToList(), null);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
}
@@ -106,7 +107,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[TestCase("X264,NOTTHERE")]
public void should_ignore_case_when_matching_ignored(string ignored)
{
- GivenRestictions(null, ignored);
+ GivenRestictions(null, ignored.Split(',').ToList());
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse();
}
@@ -120,7 +121,11 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
.Setup(s => s.EnabledForTags(It.IsAny>(), It.IsAny()))
.Returns(new List
{
- new ReleaseProfile { Required = "x264", Ignored = "www.Speed.cd" }
+ new ReleaseProfile
+ {
+ Required = new List { "x264" },
+ Ignored = new List { "www.Speed.cd" }
+ }
});
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse();
@@ -132,7 +137,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[TestCase(@"/\.WEB/", true)]
public void should_match_perl_regex(string pattern, bool expected)
{
- GivenRestictions(pattern, null);
+ GivenRestictions(pattern.Split(',').ToList(), null);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().Be(expected);
}
diff --git a/src/NzbDrone.Core/Datastore/Migration/162_release_profile_to_array.cs b/src/NzbDrone.Core/Datastore/Migration/162_release_profile_to_array.cs
new file mode 100644
index 000000000..3c3e48252
--- /dev/null
+++ b/src/NzbDrone.Core/Datastore/Migration/162_release_profile_to_array.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Data;
+using System.Linq;
+using FluentMigrator;
+using NzbDrone.Common.Serializer;
+using NzbDrone.Core.Datastore.Migration.Framework;
+
+namespace NzbDrone.Core.Datastore.Migration
+{
+ [Migration(162)]
+ public class release_profile_to_array : NzbDroneMigrationBase
+ {
+ protected override void MainDbUpgrade()
+ {
+ Execute.WithConnection(ChangeRequiredIgnoredTypes);
+ }
+
+ private void ChangeRequiredIgnoredTypes(IDbConnection conn, IDbTransaction tran)
+ {
+ using (var getEmailCmd = conn.CreateCommand())
+ {
+ getEmailCmd.Transaction = tran;
+ getEmailCmd.CommandText = "SELECT Id, Required, Ignored FROM ReleaseProfiles";
+
+ using (var reader = getEmailCmd.ExecuteReader())
+ {
+ while (reader.Read())
+ {
+ var id = reader.GetInt32(0);
+ var required = reader.GetString(1).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
+ var ignored = reader.GetString(2).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
+
+ using (var updateCmd = conn.CreateCommand())
+ {
+ updateCmd.Transaction = tran;
+ updateCmd.CommandText = "UPDATE ReleaseProfiles SET Required = ?, Ignored = ? WHERE Id = ?";
+ updateCmd.AddParameter(required.ToJson());
+ updateCmd.AddParameter(ignored.ToJson());
+ updateCmd.AddParameter(id);
+
+ updateCmd.ExecuteNonQuery();
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/ReleaseRestrictionsSpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/ReleaseRestrictionsSpecification.cs
index e2bed10c5..c48d64f0d 100644
--- a/src/NzbDrone.Core/DecisionEngine/Specifications/ReleaseRestrictionsSpecification.cs
+++ b/src/NzbDrone.Core/DecisionEngine/Specifications/ReleaseRestrictionsSpecification.cs
@@ -32,12 +32,12 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
var title = subject.Release.Title;
var releaseProfiles = _releaseProfileService.EnabledForTags(subject.Series.Tags, subject.Release.IndexerId);
- var required = releaseProfiles.Where(r => r.Required.IsNotNullOrWhiteSpace());
- var ignored = releaseProfiles.Where(r => r.Ignored.IsNotNullOrWhiteSpace());
+ var required = releaseProfiles.Where(r => r.Required.Any());
+ var ignored = releaseProfiles.Where(r => r.Ignored.Any());
foreach (var r in required)
{
- var requiredTerms = r.Required.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).ToList();
+ var requiredTerms = r.Required;
var foundTerms = ContainsAny(requiredTerms, title);
if (foundTerms.Empty())
@@ -50,7 +50,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
foreach (var r in ignored)
{
- var ignoredTerms = r.Ignored.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
+ var ignoredTerms = r.Ignored;
var foundTerms = ContainsAny(ignoredTerms, title);
if (foundTerms.Any())
diff --git a/src/NzbDrone.Core/Profiles/Releases/ReleaseProfile.cs b/src/NzbDrone.Core/Profiles/Releases/ReleaseProfile.cs
index 527ca483a..bd29da39f 100644
--- a/src/NzbDrone.Core/Profiles/Releases/ReleaseProfile.cs
+++ b/src/NzbDrone.Core/Profiles/Releases/ReleaseProfile.cs
@@ -7,8 +7,8 @@ namespace NzbDrone.Core.Profiles.Releases
{
public string Name { get; set; }
public bool Enabled { get; set; }
- public string Required { get; set; }
- public string Ignored { get; set; }
+ public List Required { get; set; }
+ public List Ignored { get; set; }
public List> Preferred { get; set; }
public bool IncludePreferredWhenRenaming { get; set; }
public int IndexerId { get; set; }
@@ -17,6 +17,8 @@ namespace NzbDrone.Core.Profiles.Releases
public ReleaseProfile()
{
Enabled = true;
+ Required = new List();
+ Ignored = new List();
Preferred = new List>();
IncludePreferredWhenRenaming = true;
Tags = new HashSet();
diff --git a/src/Sonarr.Api.V3/Profiles/Release/ReleaseProfileModule.cs b/src/Sonarr.Api.V3/Profiles/Release/ReleaseProfileModule.cs
index ed8587083..d3fed8e8a 100644
--- a/src/Sonarr.Api.V3/Profiles/Release/ReleaseProfileModule.cs
+++ b/src/Sonarr.Api.V3/Profiles/Release/ReleaseProfileModule.cs
@@ -1,7 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using FluentValidation;
-using FluentValidation.Results;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Profiles.Releases;
@@ -28,7 +27,7 @@ namespace Sonarr.Api.V3.Profiles.Release
SharedValidator.RuleFor(d => d).Custom((restriction, context) =>
{
- if (restriction.Ignored.IsNullOrWhiteSpace() && restriction.Required.IsNullOrWhiteSpace() && restriction.Preferred.Empty())
+ if (restriction.Ignored.Empty() && restriction.Required.Empty() && restriction.Preferred.Empty())
{
context.AddFailure("'Must contain', 'Must not contain' or 'Preferred' is required");
}
diff --git a/src/Sonarr.Api.V3/Profiles/Release/ReleaseProfileResource.cs b/src/Sonarr.Api.V3/Profiles/Release/ReleaseProfileResource.cs
index d9c814a3a..9a5f5187c 100644
--- a/src/Sonarr.Api.V3/Profiles/Release/ReleaseProfileResource.cs
+++ b/src/Sonarr.Api.V3/Profiles/Release/ReleaseProfileResource.cs
@@ -9,8 +9,8 @@ namespace Sonarr.Api.V3.Profiles.Release
{
public string Name { get; set; }
public bool Enabled { get; set; }
- public string Required { get; set; }
- public string Ignored { get; set; }
+ public List Required { get; set; }
+ public List Ignored { get; set; }
public List> Preferred { get; set; }
public bool IncludePreferredWhenRenaming { get; set; }
public int IndexerId { get; set; }