New: Replaced HasUnmonitored with Seasons Monitored Status and migrated DB

This commit is contained in:
jbstark 2024-06-21 20:02:33 -07:00
parent 55c1ce2e3d
commit 69f771ad5e
7 changed files with 516 additions and 12 deletions

View File

@ -12,6 +12,7 @@ import LanguageFilterBuilderRowValue from './LanguageFilterBuilderRowValue';
import ProtocolFilterBuilderRowValue from './ProtocolFilterBuilderRowValue';
import QualityFilterBuilderRowValueConnector from './QualityFilterBuilderRowValueConnector';
import QualityProfileFilterBuilderRowValueConnector from './QualityProfileFilterBuilderRowValueConnector';
import SeasonsMonitoredStatusFilterBuilderRowValue from './SeasonsMonitoredStatusFilterBuilderRowValue';
import SeriesFilterBuilderRowValue from './SeriesFilterBuilderRowValue';
import SeriesStatusFilterBuilderRowValue from './SeriesStatusFilterBuilderRowValue';
import SeriesTypeFilterBuilderRowValue from './SeriesTypeFilterBuilderRowValue';
@ -78,6 +79,9 @@ function getRowValueConnector(selectedFilterBuilderProp) {
case filterBuilderValueTypes.QUALITY_PROFILE:
return QualityProfileFilterBuilderRowValueConnector;
case filterBuilderValueTypes.SEASONS_MONITORED_STATUS:
return SeasonsMonitoredStatusFilterBuilderRowValue;
case filterBuilderValueTypes.SERIES:
return SeriesFilterBuilderRowValue;

View File

@ -0,0 +1,35 @@
import React from 'react';
import translate from 'Utilities/String/translate';
import FilterBuilderRowValue from './FilterBuilderRowValue';
const seasonsMonitoredStatusList = [
{
id: 'all',
get name() {
return translate('SeasonsMonitoredAll');
}
},
{
id: 'partial',
get name() {
return translate('SeasonsMonitoredPartial');
}
},
{
id: 'none',
get name() {
return translate('SeasonsMonitoredNone');
}
}
];
function SeasonsMonitoredStatusFilterBuilderRowValue(props) {
return (
<FilterBuilderRowValue
tagList={seasonsMonitoredStatusList}
{...props}
/>
);
}
export default SeasonsMonitoredStatusFilterBuilderRowValue;

View File

@ -8,6 +8,7 @@ export const LANGUAGE = 'language';
export const PROTOCOL = 'protocol';
export const QUALITY = 'quality';
export const QUALITY_PROFILE = 'qualityProfile';
export const SEASONS_MONITORED_STATUS = 'seasonsMonitoredStatus';
export const SERIES = 'series';
export const SERIES_STATUS = 'seriesStatus';
export const SERIES_TYPES = 'seriesType';

View File

@ -194,20 +194,30 @@ export const filterPredicates = {
return predicate(hasMissingSeason, filterValue);
},
hasUnmonitoredSeason: function(item, filterValue, type) {
seasonsMonitoredStatus: function(item, filterValue, type) {
const predicate = filterTypePredicates[type];
const { seasons = [] } = item;
const hasUnmonitoredSeason = seasons.some((season) => {
const {
seasonNumber,
monitored
} = season;
const { monitoredCount, unmonitoredCount } = seasons.reduce((acc, { seasonNumber, monitored }) => {
if (seasonNumber <= 0) {
return acc;
}
if (monitored) {
acc.monitoredCount++;
} else {
acc.unmonitoredCount++;
}
return acc;
}, { monitoredCount: 0, unmonitoredCount: 0 });
return seasonNumber > 0 && !monitored;
});
let seasonsMonitoredStatus = 'partial';
if (monitoredCount === 0) {
seasonsMonitoredStatus = 'none';
} else if (unmonitoredCount === 0) {
seasonsMonitoredStatus = 'all';
}
return predicate(hasUnmonitoredSeason, filterValue);
return predicate(seasonsMonitoredStatus, filterValue);
}
};
@ -370,10 +380,10 @@ export const filterBuilderProps = [
valueType: filterBuilderValueTypes.BOOL
},
{
name: 'hasUnmonitoredSeason',
label: () => translate('HasUnmonitoredSeason'),
name: 'seasonsMonitoredStatus',
label: () => translate('SeasonsMonitoredStatus'),
type: filterBuilderTypes.EXACT,
valueType: filterBuilderValueTypes.BOOL
valueType: filterBuilderValueTypes.SEASONS_MONITORED_STATUS
},
{
name: 'year',

View File

@ -0,0 +1,372 @@
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using Newtonsoft.Json;
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 add_monitored_seasons_filterFixture : MigrationTest<add_monitored_seasons_filter>
{
[Test]
public void equal_both_becomes_equal_every_option()
{
var filter = new FilterSettings210
{
key = "hasUnmonitoredSeason",
value = new List<object> { true, false },
type = "equal"
};
var filtersJson = new List<FilterSettings210> { filter };
var filtersString = filtersJson.ToJson();
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("CustomFilters").Row(new
{
Id = 1,
Type = "series",
Label = "Is Both",
Filters = filtersString
});
});
var items = db.Query<FilterDefinition210>("SELECT * FROM \"CustomFilters\"");
items.Should().HaveCount(1);
items.First().Type.Should().Be("series");
items.First().Label.Should().Be("Is Both");
var filters = JsonConvert.DeserializeObject<List<FilterSettings210>>(items.First().Filters);
filters[0].key.Should().Be("seasonsMonitoredStatus");
filters[0].value.Should().BeEquivalentTo(new List<object> { "all", "partial", "none" });
filters[0].type.Should().Be("equal");
}
[Test]
public void notEqual_both_becomes_notEqual_every_option()
{
var filter = new FilterSettings210
{
key = "hasUnmonitoredSeason",
value = new List<object> { true, false },
type = "notEqual"
};
var filtersJson = new List<FilterSettings210> { filter };
var filtersString = filtersJson.ToJson();
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("CustomFilters").Row(new
{
Id = 1,
Type = "series",
Label = "Is Both",
Filters = filtersString
});
});
var items = db.Query<FilterDefinition210>("SELECT * FROM \"CustomFilters\"");
items.Should().HaveCount(1);
items.First().Type.Should().Be("series");
items.First().Label.Should().Be("Is Both");
var filters = JsonConvert.DeserializeObject<List<FilterSettings210>>(items.First().Filters);
filters[0].key.Should().Be("seasonsMonitoredStatus");
filters[0].value.Should().BeEquivalentTo(new List<object> { "all", "partial", "none" });
filters[0].type.Should().Be("notEqual");
}
[Test]
public void equal_true_becomes_notEqual_all()
{
var filter = new FilterSettings210
{
key = "hasUnmonitoredSeason",
value = new List<object> { true },
type = "equal"
};
var filtersJson = new List<FilterSettings210> { filter };
var filtersString = filtersJson.ToJson();
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("CustomFilters").Row(new
{
Id = 1,
Type = "series",
Label = "Is Both",
Filters = filtersString
});
});
var items = db.Query<FilterDefinition210>("SELECT * FROM \"CustomFilters\"");
items.Should().HaveCount(1);
items.First().Type.Should().Be("series");
items.First().Label.Should().Be("Is Both");
var filters = JsonConvert.DeserializeObject<List<FilterSettings210>>(items.First().Filters);
filters[0].key.Should().Be("seasonsMonitoredStatus");
filters[0].value.Should().BeEquivalentTo(new List<object> { "all" });
filters[0].type.Should().Be("notEqual");
}
[Test]
public void notEqual_true_becomes_equal_all()
{
var filter = new FilterSettings210
{
key = "hasUnmonitoredSeason",
value = new List<object> { true },
type = "notEqual"
};
var filtersJson = new List<FilterSettings210> { filter };
var filtersString = filtersJson.ToJson();
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("CustomFilters").Row(new
{
Id = 1,
Type = "series",
Label = "Is Both",
Filters = filtersString
});
});
var items = db.Query<FilterDefinition210>("SELECT * FROM \"CustomFilters\"");
items.Should().HaveCount(1);
items.First().Type.Should().Be("series");
items.First().Label.Should().Be("Is Both");
var filters = JsonConvert.DeserializeObject<List<FilterSettings210>>(items.First().Filters);
filters[0].key.Should().Be("seasonsMonitoredStatus");
filters[0].value.Should().BeEquivalentTo(new List<object> { "all" });
filters[0].type.Should().Be("equal");
}
[Test]
public void equal_false_becomes_equal_all()
{
var filter = new FilterSettings210
{
key = "hasUnmonitoredSeason",
value = new List<object> { false },
type = "equal"
};
var filtersJson = new List<FilterSettings210> { filter };
var filtersString = filtersJson.ToJson();
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("CustomFilters").Row(new
{
Id = 1,
Type = "series",
Label = "Is Both",
Filters = filtersString
});
});
var items = db.Query<FilterDefinition210>("SELECT * FROM \"CustomFilters\"");
items.Should().HaveCount(1);
items.First().Type.Should().Be("series");
items.First().Label.Should().Be("Is Both");
var filters = JsonConvert.DeserializeObject<List<FilterSettings210>>(items.First().Filters);
filters[0].key.Should().Be("seasonsMonitoredStatus");
filters[0].value.Should().BeEquivalentTo(new List<object> { "all" });
filters[0].type.Should().Be("equal");
}
[Test]
public void notEqual_false_becomes_notEqual_all()
{
var filter = new FilterSettings210
{
key = "hasUnmonitoredSeason",
value = new List<object> { false },
type = "notEqual"
};
var filtersJson = new List<FilterSettings210> { filter };
var filtersString = filtersJson.ToJson();
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("CustomFilters").Row(new
{
Id = 1,
Type = "series",
Label = "Is Both",
Filters = filtersString
});
});
var items = db.Query<FilterDefinition210>("SELECT * FROM \"CustomFilters\"");
items.Should().HaveCount(1);
items.First().Type.Should().Be("series");
items.First().Label.Should().Be("Is Both");
var filters = JsonConvert.DeserializeObject<List<FilterSettings210>>(items.First().Filters);
filters[0].key.Should().Be("seasonsMonitoredStatus");
filters[0].value.Should().BeEquivalentTo(new List<object> { "all" });
filters[0].type.Should().Be("notEqual");
}
[Test]
public void missing_hasUnmonitored_unchanged()
{
var filter = new FilterSettings210
{
key = "monitored",
value = new List<object> { false },
type = "equal"
};
var filtersJson = new List<FilterSettings210> { filter };
var filtersString = filtersJson.ToJson();
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("CustomFilters").Row(new
{
Id = 1,
Type = "series",
Label = "Is Both",
Filters = filtersString
});
});
var items = db.Query<FilterDefinition210>("SELECT * FROM \"CustomFilters\"");
items.Should().HaveCount(1);
items.First().Type.Should().Be("series");
items.First().Label.Should().Be("Is Both");
var filters = JsonConvert.DeserializeObject<List<FilterSettings210>>(items.First().Filters);
filters[0].key.Should().Be("monitored");
filters[0].value.Should().BeEquivalentTo(new List<object> { false });
filters[0].type.Should().Be("equal");
}
[Test]
public void has_hasUnmonitored_not_in_first_entry()
{
var filter1 = new FilterSettings210
{
key = "monitored",
value = new List<object> { false },
type = "equal"
};
var filter2 = new FilterSettings210
{
key = "hasUnmonitoredSeason",
value = new List<object> { true },
type = "equal"
};
var filtersJson = new List<FilterSettings210> { filter1, filter2 };
var filtersString = filtersJson.ToJson();
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("CustomFilters").Row(new
{
Id = 1,
Type = "series",
Label = "Is Both",
Filters = filtersString
});
});
var items = db.Query<FilterDefinition210>("SELECT * FROM \"CustomFilters\"");
items.Should().HaveCount(1);
items.First().Type.Should().Be("series");
items.First().Label.Should().Be("Is Both");
var filters = JsonConvert.DeserializeObject<List<FilterSettings210>>(items.First().Filters);
filters[0].key.Should().Be("monitored");
filters[0].value.Should().BeEquivalentTo(new List<object> { false });
filters[0].type.Should().Be("equal");
filters[1].key.Should().Be("seasonsMonitoredStatus");
filters[1].value.Should().BeEquivalentTo(new List<object> { "all" });
filters[1].type.Should().Be("notEqual");
}
[Test]
public void has_umonitored_is_empty()
{
var filter = new FilterSettings210
{
key = "hasUnmonitoredSeason",
value = new List<object> { },
type = "equal"
};
var filtersJson = new List<FilterSettings210> { filter };
var filtersString = filtersJson.ToJson();
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("CustomFilters").Row(new
{
Id = 1,
Type = "series",
Label = "Is Both",
Filters = filtersString
});
});
var items = db.Query<FilterDefinition210>("SELECT * FROM \"CustomFilters\"");
items.Should().HaveCount(1);
items.First().Type.Should().Be("series");
items.First().Label.Should().Be("Is Both");
var filters = JsonConvert.DeserializeObject<List<FilterSettings210>>(items.First().Filters);
filters[0].key.Should().Be("seasonsMonitoredStatus");
filters[0].value.Should().BeEquivalentTo(new List<object> { });
filters[0].type.Should().Be("equal");
}
}
public class FilterDefinition210
{
public int Id { get; set; }
public string Type { get; set; }
public string Label { get; set; }
public string Filters { get; set; }
}
public class FilterSettings210
{
public string key { get; set; }
public List<object> value { get; set; }
public string type { get; set; }
}
}

View File

@ -0,0 +1,78 @@
using System;
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(210)]
public class add_monitored_seasons_filter : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Execute.WithConnection(ChangeHasUnmonitoredSeason);
}
private void ChangeHasUnmonitoredSeason(IDbConnection conn, IDbTransaction tran)
{
var updated = new List<object>();
using (var getUnmonitoredSeasonFilter = conn.CreateCommand())
{
getUnmonitoredSeasonFilter.Transaction = tran;
getUnmonitoredSeasonFilter.CommandText = "SELECT \"Id\", \"Filters\" FROM \"CustomFilters\" WHERE EXISTS (SELECT 1 FROM json_each(\"Filters\") AS EACH WHERE json_extract(EACH.value, '$.key') = 'hasUnmonitoredSeason')";
using (var reader = getUnmonitoredSeasonFilter.ExecuteReader())
{
while (reader.Read())
{
var id = reader.GetInt32(0);
var filters = JArray.Parse(reader.GetString(1));
foreach (var filter in filters)
{
if (filter["key"].ToString() == "hasUnmonitoredSeason")
{
var value = filter["value"].ToString();
var type = filter["type"].ToString();
filter["key"] = "seasonsMonitoredStatus";
if (value.Contains("true") && value.Contains("false"))
{
filter["value"] = new JArray("all", "partial", "none");
}
else if (value.Contains("true"))
{
filter["type"] = type == "equal" ? "notEqual" : "equal";
filter["value"] = new JArray("all");
}
else if (value.Contains("false"))
{
filter["value"] = new JArray("all");
}
else
{
filter["value"] = new JArray();
}
}
}
updated.Add(new
{
Filters = filters.ToJson(),
Id = id
});
}
}
}
Console.WriteLine("Migrating 210");
var updateSql = "UPDATE \"CustomFilters\" SET \"Filters\" = @Filters WHERE \"Id\" = @Id";
conn.Execute(updateSql, updated, transaction: tran);
}
}
}

View File

@ -1773,6 +1773,10 @@
"SeasonPremiere": "Season Premiere",
"SeasonPremieresOnly": "Season Premieres Only",
"Seasons": "Seasons",
"SeasonsMonitoredAll": "All",
"SeasonsMonitoredPartial": "Partial",
"SeasonsMonitoredNone": "None",
"SeasonsMonitoredStatus": "Seasons Monitored",
"SecretToken": "Secret Token",
"Security": "Security",
"Seeders": "Seeders",