Fixed: Migrate categories to capabilities in Newznab/Torznab settings

pull/2085/head
Bogdan 1 month ago
parent 1b8f09f2ce
commit 41b0a1211b

@ -0,0 +1,200 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using Newtonsoft.Json.Linq;
using NUnit.Framework;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Datastore.Migration;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.Datastore.Migration
{
[TestFixture]
public class newznab_category_to_capabilities_settingsFixture : MigrationTest<newznab_category_to_capabilities_settings>
{
[Test]
public void should_migrate_categories_when_capabilities_is_not_defined()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Indexers").Row(new
{
Name = "Usenet Indexer",
Redirect = false,
AppProfileId = 0,
DownloadClientId = 0,
Priority = 25,
Added = DateTime.UtcNow,
Implementation = "Newznab",
Settings = new
{
Categories = new[]
{
new { Id = 2000, Name = "Movies" },
new { Id = 5000, Name = "TV" }
}
}.ToJson(),
ConfigContract = "NewznabSettings"
});
});
var items = db.Query<IndexerDefinition40>("SELECT \"Id\", \"Implementation\", \"ConfigContract\", \"Settings\" FROM \"Indexers\"");
items.Should().HaveCount(1);
items.First().Implementation.Should().Be("Newznab");
items.First().ConfigContract.Should().Be("NewznabSettings");
items.First().Settings.Should().ContainKey("capabilities");
items.First().Settings.Should().NotContainKey("categories");
var newznabSettings = items.First().Settings.ToObject<NewznabSettings40>();
newznabSettings.Capabilities.Should().NotBeNull();
newznabSettings.Capabilities.SupportsRawSearch.Should().Be(false);
newznabSettings.Capabilities.Categories.Should().HaveCount(2);
newznabSettings.Capabilities.Categories.Should().Contain(c => c.Id == 2000 && c.Name == "Movies");
newznabSettings.Capabilities.Categories.Should().Contain(c => c.Id == 5000 && c.Name == "TV");
}
[Test]
public void should_migrate_categories_when_capabilities_is_defined()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Indexers").Row(new
{
Name = "Usenet Indexer",
Redirect = false,
AppProfileId = 0,
DownloadClientId = 0,
Priority = 25,
Added = DateTime.UtcNow,
Implementation = "Newznab",
Settings = new
{
Capabilities = new
{
SupportsRawSearch = true
},
Categories = new[]
{
new { Id = 2000, Name = "Movies" },
new { Id = 5000, Name = "TV" }
}
}.ToJson(),
ConfigContract = "NewznabSettings"
});
});
var items = db.Query<IndexerDefinition40>("SELECT \"Id\", \"Implementation\", \"ConfigContract\", \"Settings\" FROM \"Indexers\"");
items.Should().HaveCount(1);
items.First().Implementation.Should().Be("Newznab");
items.First().ConfigContract.Should().Be("NewznabSettings");
items.First().Settings.Should().ContainKey("capabilities");
items.First().Settings.Should().NotContainKey("categories");
var newznabSettings = items.First().Settings.ToObject<NewznabSettings40>();
newznabSettings.Capabilities.Should().NotBeNull();
newznabSettings.Capabilities.SupportsRawSearch.Should().Be(true);
newznabSettings.Capabilities.Categories.Should().HaveCount(2);
newznabSettings.Capabilities.Categories.Should().Contain(c => c.Id == 2000 && c.Name == "Movies");
newznabSettings.Capabilities.Categories.Should().Contain(c => c.Id == 5000 && c.Name == "TV");
}
[Test]
public void should_use_defaults_when_categories_are_empty()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Indexers").Row(new
{
Name = "Usenet Indexer",
Redirect = false,
AppProfileId = 0,
DownloadClientId = 0,
Priority = 25,
Added = DateTime.UtcNow,
Implementation = "Newznab",
Settings = new
{
Categories = Array.Empty<object>()
}.ToJson(),
ConfigContract = "NewznabSettings"
});
});
var items = db.Query<IndexerDefinition40>("SELECT \"Id\", \"Implementation\", \"ConfigContract\", \"Settings\" FROM \"Indexers\"");
items.Should().HaveCount(1);
items.First().Implementation.Should().Be("Newznab");
items.First().ConfigContract.Should().Be("NewznabSettings");
items.First().Settings.Should().ContainKey("capabilities");
items.First().Settings.Should().NotContainKey("categories");
var newznabSettings = items.First().Settings.ToObject<NewznabSettings40>();
newznabSettings.Capabilities.Should().NotBeNull();
newznabSettings.Capabilities.SupportsRawSearch.Should().Be(false);
newznabSettings.Capabilities.Categories.Should().NotBeNull();
newznabSettings.Capabilities.Categories.Should().HaveCount(0);
}
[Test]
public void should_use_defaults_when_settings_are_empty()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Indexers").Row(new
{
Name = "Usenet Indexer",
Redirect = false,
AppProfileId = 0,
DownloadClientId = 0,
Priority = 25,
Added = DateTime.UtcNow,
Implementation = "Newznab",
Settings = new { }.ToJson(),
ConfigContract = "NewznabSettings"
});
});
var items = db.Query<IndexerDefinition40>("SELECT \"Id\", \"Implementation\", \"ConfigContract\", \"Settings\" FROM \"Indexers\"");
items.Should().HaveCount(1);
items.First().Implementation.Should().Be("Newznab");
items.First().ConfigContract.Should().Be("NewznabSettings");
items.First().Settings.Should().NotContainKey("capabilities");
items.First().Settings.Should().NotContainKey("categories");
items.First().Settings.ToObject<NewznabSettings40>().Capabilities.Should().BeNull();
}
}
public class IndexerDefinition40
{
public int Id { get; set; }
public string Implementation { get; set; }
public string ConfigContract { get; set; }
public JObject Settings { get; set; }
}
public class NewznabSettings39
{
public object Categories { get; set; }
}
public class NewznabSettings40
{
public NewznabCapabilitiesSettings40 Capabilities { get; set; }
}
public class NewznabCapabilitiesSettings40
{
public bool SupportsRawSearch { get; set; }
public List<IndexerCategory40> Categories { get; set; }
}
public class IndexerCategory40
{
public int Id { get; set; }
public string Name { get; set; }
}
}

@ -0,0 +1,65 @@
using System.Collections.Generic;
using System.Data;
using Dapper;
using FluentMigrator;
using Newtonsoft.Json.Linq;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(40)]
public class newznab_category_to_capabilities_settings : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Execute.WithConnection(MoveCategoriesToCapabilities);
}
private void MoveCategoriesToCapabilities(IDbConnection conn, IDbTransaction tran)
{
var updated = new List<object>();
using (var cmd = conn.CreateCommand())
{
cmd.Transaction = tran;
cmd.CommandText = "SELECT \"Id\", \"Settings\" FROM \"Indexers\" WHERE \"Implementation\" IN ('Newznab', 'Torznab')";
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var id = reader.GetInt32(0);
var settings = Json.Deserialize<JObject>(reader.GetString(1));
if ((settings.Value<JObject>("capabilities")?.ContainsKey("categories") ?? false) == false
&& settings.ContainsKey("categories")
&& settings.TryGetValue("categories", out var categories))
{
if (!settings.ContainsKey("capabilities"))
{
settings.Add("capabilities", new JObject());
}
settings.Value<JObject>("capabilities")?.Add(new JProperty("categories", JArray.FromObject(categories)));
if (settings.ContainsKey("categories"))
{
settings.Remove("categories");
}
}
updated.Add(new
{
Settings = settings.ToJson(),
Id = id
});
}
}
}
var updateSql = "UPDATE \"Indexers\" SET \"Settings\" = @Settings WHERE \"Id\" = @Id";
conn.Execute(updateSql, updated, transaction: tran);
}
}
}

@ -61,26 +61,23 @@ namespace NzbDrone.Core.Indexers.Newznab
{
var caps = new IndexerCapabilities();
if (Definition == null || Settings?.Capabilities == null)
if (Definition == null || Settings?.Capabilities?.Categories == null)
{
return caps;
}
caps.SupportsRawSearch = Settings.Capabilities?.SupportsRawSearch ?? false;
caps.SearchParams = Settings.Capabilities?.SearchParams ?? new List<SearchParam> { SearchParam.Q };
caps.TvSearchParams = Settings.Capabilities?.TvSearchParams ?? new List<TvSearchParam>();
caps.MovieSearchParams = Settings.Capabilities?.MovieSearchParams ?? new List<MovieSearchParam>();
caps.MusicSearchParams = Settings.Capabilities?.MusicSearchParams ?? new List<MusicSearchParam>();
caps.BookSearchParams = Settings.Capabilities?.BookSearchParams ?? new List<BookSearchParam>();
if (Settings.Capabilities?.Categories != null)
foreach (var category in Settings.Capabilities.Categories)
{
foreach (var category in Settings.Capabilities.Categories)
{
caps.Categories.AddCategoryMapping(category.Name, category);
}
caps.Categories.AddCategoryMapping(category.Name, category);
}
caps.SupportsRawSearch = Settings?.Capabilities?.SupportsRawSearch ?? false;
caps.SearchParams = Settings?.Capabilities?.SearchParams ?? new List<SearchParam> { SearchParam.Q };
caps.TvSearchParams = Settings?.Capabilities?.TvSearchParams ?? new List<TvSearchParam>();
caps.MovieSearchParams = Settings?.Capabilities?.MovieSearchParams ?? new List<MovieSearchParam>();
caps.MusicSearchParams = Settings?.Capabilities?.MusicSearchParams ?? new List<MusicSearchParam>();
caps.BookSearchParams = Settings?.Capabilities?.BookSearchParams ?? new List<BookSearchParam>();
return caps;
}

@ -6,17 +6,17 @@ public class NewznabCapabilitiesSettings
{
public bool SupportsRawSearch { get; set; }
public List<SearchParam> SearchParams { get; set; } = new ();
public List<SearchParam> SearchParams { get; set; }
public List<TvSearchParam> TvSearchParams { get; set; } = new ();
public List<TvSearchParam> TvSearchParams { get; set; }
public List<MovieSearchParam> MovieSearchParams { get; set; } = new ();
public List<MovieSearchParam> MovieSearchParams { get; set; }
public List<MusicSearchParam> MusicSearchParams { get; set; } = new ();
public List<MusicSearchParam> MusicSearchParams { get; set; }
public List<BookSearchParam> BookSearchParams { get; set; } = new ();
public List<BookSearchParam> BookSearchParams { get; set; }
public List<IndexerCategory> Categories { get; set; } = new ();
public List<IndexerCategory> Categories { get; set; }
public NewznabCapabilitiesSettings()
{

@ -61,26 +61,23 @@ namespace NzbDrone.Core.Indexers.Torznab
{
var caps = new IndexerCapabilities();
if (Definition == null || Settings?.Capabilities == null)
if (Definition == null || Settings?.Capabilities?.Categories == null)
{
return caps;
}
caps.SupportsRawSearch = Settings.Capabilities?.SupportsRawSearch ?? false;
caps.SearchParams = Settings.Capabilities?.SearchParams ?? new List<SearchParam> { SearchParam.Q };
caps.TvSearchParams = Settings.Capabilities?.TvSearchParams ?? new List<TvSearchParam>();
caps.MovieSearchParams = Settings.Capabilities?.MovieSearchParams ?? new List<MovieSearchParam>();
caps.MusicSearchParams = Settings.Capabilities?.MusicSearchParams ?? new List<MusicSearchParam>();
caps.BookSearchParams = Settings.Capabilities?.BookSearchParams ?? new List<BookSearchParam>();
if (Settings.Capabilities?.Categories != null)
foreach (var category in Settings.Capabilities.Categories)
{
foreach (var category in Settings.Capabilities.Categories)
{
caps.Categories.AddCategoryMapping(category.Name, category);
}
caps.Categories.AddCategoryMapping(category.Name, category);
}
caps.SupportsRawSearch = Settings?.Capabilities?.SupportsRawSearch ?? false;
caps.SearchParams = Settings?.Capabilities?.SearchParams ?? new List<SearchParam> { SearchParam.Q };
caps.TvSearchParams = Settings?.Capabilities?.TvSearchParams ?? new List<TvSearchParam>();
caps.MovieSearchParams = Settings?.Capabilities?.MovieSearchParams ?? new List<MovieSearchParam>();
caps.MusicSearchParams = Settings?.Capabilities?.MusicSearchParams ?? new List<MusicSearchParam>();
caps.BookSearchParams = Settings?.Capabilities?.BookSearchParams ?? new List<BookSearchParam>();
return caps;
}

Loading…
Cancel
Save