From 0eec2cd5f79d4b22a43503c551262a5b5c8aa4a2 Mon Sep 17 00:00:00 2001 From: "kay.one" Date: Sun, 22 Sep 2013 16:40:36 -0700 Subject: [PATCH] schema updates --- .../ClientSchemaTests/SchemaBuilderFixture.cs | 4 +- NzbDrone.Api/ClientSchema/SchemaBuilder.cs | 51 ++++++++++++++++++- .../ClientSchema/SchemaDeserializer.cs | 34 +------------ NzbDrone.Api/Indexers/IndexerModule.cs | 21 +++++--- NzbDrone.Api/Indexers/IndexerSchemaModule.cs | 6 ++- .../Notifications/NotificationModule.cs | 8 ++- .../Notifications/NotificationSchemaModule.cs | 2 +- .../Reflection/ReflectionExtensions.cs | 7 +++ .../ProviderSettingConverterFixture.cs | 39 ++++++++++++++ NzbDrone.Core.Test/NzbDrone.Core.Test.csproj | 1 + .../Converters/EmbeddedDocumentConverter.cs | 32 ------------ .../Converters/ProviderSettingConverter.cs | 36 +++++++++++++ .../023_add_config_contract_to_indexers.cs | 23 +++++++++ NzbDrone.Core/Indexers/IndexerService.cs | 2 +- NzbDrone.Core/NzbDrone.Core.csproj | 2 + NzbDrone.Core/ThingiProvider/IProvider.cs | 15 ++++-- .../ThingiProvider/ProviderService.cs | 23 ++------- 17 files changed, 199 insertions(+), 107 deletions(-) create mode 100644 NzbDrone.Core.Test/Datastore/Converters/ProviderSettingConverterFixture.cs create mode 100644 NzbDrone.Core/Datastore/Converters/ProviderSettingConverter.cs create mode 100644 NzbDrone.Core/Datastore/Migration/023_add_config_contract_to_indexers.cs diff --git a/NzbDrone.Api.Test/ClientSchemaTests/SchemaBuilderFixture.cs b/NzbDrone.Api.Test/ClientSchemaTests/SchemaBuilderFixture.cs index bf3d72d11..385a9b989 100644 --- a/NzbDrone.Api.Test/ClientSchemaTests/SchemaBuilderFixture.cs +++ b/NzbDrone.Api.Test/ClientSchemaTests/SchemaBuilderFixture.cs @@ -12,7 +12,7 @@ public class SchemaBuilderFixture : TestBase [Test] public void should_return_field_for_every_property() { - var schema = SchemaBuilder.GenerateSchema(new TestModel()); + var schema = SchemaBuilder.ToSchema(new TestModel()); schema.Should().HaveCount(2); } @@ -26,7 +26,7 @@ public void schema_should_have_proper_fields() LastName = "Poop" }; - var schema = SchemaBuilder.GenerateSchema(model); + var schema = SchemaBuilder.ToSchema(model); schema.Should().Contain(c => c.Order == 1 && c.Name == "LastName" && c.Label == "Last Name" && c.HelpText == "Your Last Name" && (string) c.Value == "Poop"); schema.Should().Contain(c => c.Order == 0 && c.Name == "FirstName" && c.Label == "First Name" && c.HelpText == "Your First Name" && (string) c.Value == "Bob"); diff --git a/NzbDrone.Api/ClientSchema/SchemaBuilder.cs b/NzbDrone.Api/ClientSchema/SchemaBuilder.cs index 99b2c6d15..1393387bc 100644 --- a/NzbDrone.Api/ClientSchema/SchemaBuilder.cs +++ b/NzbDrone.Api/ClientSchema/SchemaBuilder.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using NzbDrone.Common; +using NzbDrone.Common.EnsureThat; using NzbDrone.Common.Reflection; using NzbDrone.Core.Annotations; @@ -8,8 +10,10 @@ namespace NzbDrone.Api.ClientSchema { public static class SchemaBuilder { - public static List GenerateSchema(object model) + public static List ToSchema(object model) { + Ensure.That(() => model).IsNotNull(); + var properties = model.GetType().GetSimpleProperties(); var result = new List(properties.Count); @@ -50,10 +54,53 @@ public static List GenerateSchema(object model) } + + public static object ReadFormSchema(List fields, Type targetType) + { + var properties = targetType.GetSimpleProperties(); + + var target = Activator.CreateInstance(targetType); + + foreach (var propertyInfo in properties) + { + var fieldAttribute = propertyInfo.GetAttribute(false); + + if (fieldAttribute != null) + { + var field = fields.Find(f => f.Name == propertyInfo.Name); + + if (propertyInfo.PropertyType == typeof(Int32)) + { + var intValue = Convert.ToInt32(field.Value); + propertyInfo.SetValue(target, intValue, null); + } + + else if (propertyInfo.PropertyType == typeof(Nullable)) + { + var intValue = field.Value.ToString().ParseInt32(); + propertyInfo.SetValue(target, intValue, null); + } + + else + { + propertyInfo.SetValue(target, field.Value, null); + } + } + } + + return target; + + } + + public static T ReadFormSchema(List fields) + { + return (T)ReadFormSchema(fields, typeof (T)); + } + private static List GetSelectOptions(Type selectOptions) { var options = from Enum e in Enum.GetValues(selectOptions) - select new SelectOption { Value = Convert.ToInt32(e), Name = e.ToString() }; + select new SelectOption { Value = Convert.ToInt32(e), Name = e.ToString() }; return options.OrderBy(o => o.Value).ToList(); } diff --git a/NzbDrone.Api/ClientSchema/SchemaDeserializer.cs b/NzbDrone.Api/ClientSchema/SchemaDeserializer.cs index 9985ffb49..36d2a68e8 100644 --- a/NzbDrone.Api/ClientSchema/SchemaDeserializer.cs +++ b/NzbDrone.Api/ClientSchema/SchemaDeserializer.cs @@ -8,38 +8,6 @@ namespace NzbDrone.Api.ClientSchema { public static class SchemaDeserializer { - public static T DeserializeSchema(T model, List fields) - { - var properties = model.GetType().GetSimpleProperties(); - - foreach (var propertyInfo in properties) - { - var fieldAttribute = propertyInfo.GetAttribute(false); - - if (fieldAttribute != null) - { - var field = fields.Find(f => f.Name == propertyInfo.Name); - - if (propertyInfo.PropertyType == typeof (Int32)) - { - var intValue = Convert.ToInt32(field.Value); - propertyInfo.SetValue(model, intValue, null); - } - - else if (propertyInfo.PropertyType == typeof(Nullable)) - { - var intValue = field.Value.ToString().ParseInt32(); - propertyInfo.SetValue(model, intValue, null); - } - - else - { - propertyInfo.SetValue(model, field.Value, null); - } - } - } - - return model; - } + } } \ No newline at end of file diff --git a/NzbDrone.Api/Indexers/IndexerModule.cs b/NzbDrone.Api/Indexers/IndexerModule.cs index cd5ed90c0..531a7dee8 100644 --- a/NzbDrone.Api/Indexers/IndexerModule.cs +++ b/NzbDrone.Api/Indexers/IndexerModule.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using NzbDrone.Api.ClientSchema; +using NzbDrone.Common.Reflection; using NzbDrone.Core.Indexers; using NzbDrone.Core.ThingiProvider; using Omu.ValueInjecter; @@ -35,15 +36,15 @@ private IndexerResource GetIndexer(int id) private List GetAll() { - var indexers = _indexerService.All(); + var indexerDefinitions = _indexerService.All(); - var result = new List(indexers.Count); + var result = new List(indexerDefinitions.Count); - foreach (var indexer in indexers) + foreach (var definition in indexerDefinitions) { var indexerResource = new IndexerResource(); - indexerResource.InjectFrom(indexer); - indexerResource.Fields = SchemaBuilder.GenerateSchema(indexer.Settings); + indexerResource.InjectFrom(definition); + indexerResource.Fields = SchemaBuilder.ToSchema(definition.Settings); result.Add(indexerResource); } @@ -53,14 +54,14 @@ private List GetAll() private int CreateIndexer(IndexerResource indexerResource) { - var indexer = GetIndexer(indexerResource); + var indexer = GetDefinition(indexerResource); indexer = _indexerService.Create(indexer); return indexer.Id; } private void UpdateIndexer(IndexerResource indexerResource) { - var indexer = GetIndexer(indexerResource); + var indexer = GetDefinition(indexerResource); ValidateIndexer(indexer.Settings); @@ -78,12 +79,16 @@ private static void ValidateIndexer(IProviderConfig config) } } - private IndexerDefinition GetIndexer(IndexerResource indexerResource) + private IndexerDefinition GetDefinition(IndexerResource indexerResource) { var definition = new IndexerDefinition(); definition.InjectFrom(indexerResource); + + var configContract = ReflectionExtensions.CoreAssembly.FindTypeByName(definition.ConfigContract); + definition.Settings = (IProviderConfig)SchemaBuilder.ReadFormSchema(indexerResource.Fields, configContract); + if (indexerResource.Enable) { ValidateIndexer(definition.Settings); diff --git a/NzbDrone.Api/Indexers/IndexerSchemaModule.cs b/NzbDrone.Api/Indexers/IndexerSchemaModule.cs index 9fe425cf0..8d9b09f2a 100644 --- a/NzbDrone.Api/Indexers/IndexerSchemaModule.cs +++ b/NzbDrone.Api/Indexers/IndexerSchemaModule.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using NzbDrone.Api.ClientSchema; +using NzbDrone.Api.Mapping; using NzbDrone.Core.Indexers; using Omu.ValueInjecter; @@ -18,6 +19,9 @@ public IndexerSchemaModule(IIndexerService indexerService) private List GetSchema() { + + var indexers = _indexerService.All().InjectTo>(); + /* var indexers = _indexerService.Schema(); var result = new List(indexers.Count); @@ -33,7 +37,7 @@ private List GetSchema() return result;*/ - return null; + return indexers; } } } \ No newline at end of file diff --git a/NzbDrone.Api/Notifications/NotificationModule.cs b/NzbDrone.Api/Notifications/NotificationModule.cs index bc7ca8aac..c8be13f67 100644 --- a/NzbDrone.Api/Notifications/NotificationModule.cs +++ b/NzbDrone.Api/Notifications/NotificationModule.cs @@ -4,6 +4,7 @@ using NzbDrone.Api.ClientSchema; using NzbDrone.Api.Mapping; using NzbDrone.Api.REST; +using NzbDrone.Common.Reflection; using NzbDrone.Core.Notifications; using Omu.ValueInjecter; @@ -39,7 +40,7 @@ private List GetAll() { var notificationResource = new NotificationResource(); notificationResource.InjectFrom(notification); - notificationResource.Fields = SchemaBuilder.GenerateSchema(notification.Settings); + notificationResource.Fields = SchemaBuilder.ToSchema(notification.Settings); notificationResource.TestCommand = String.Format("test{0}", notification.Implementation.ToLowerInvariant()); result.Add(notificationResource); @@ -79,7 +80,10 @@ private Notification ConvertToNotification(NotificationResource notificationReso } notification.InjectFrom(notificationResource); - notification.Settings = SchemaDeserializer.DeserializeSchema(notification.Settings, notificationResource.Fields); + + //var configType = ReflectionExtensions.CoreAssembly.FindTypeByName(notification) + + //notification.Settings = SchemaBuilder.ReadFormSchema(notification.Settings, notificationResource.Fields); return notification; } diff --git a/NzbDrone.Api/Notifications/NotificationSchemaModule.cs b/NzbDrone.Api/Notifications/NotificationSchemaModule.cs index d347e343c..68a5bd594 100644 --- a/NzbDrone.Api/Notifications/NotificationSchemaModule.cs +++ b/NzbDrone.Api/Notifications/NotificationSchemaModule.cs @@ -28,7 +28,7 @@ private List GetSchema() { var notificationResource = new NotificationResource(); notificationResource.InjectFrom(notification); - notificationResource.Fields = SchemaBuilder.GenerateSchema(notification.Settings); + notificationResource.Fields = SchemaBuilder.ToSchema(notification.Settings); notificationResource.TestCommand = String.Format("test{0}", notification.Implementation.ToLowerInvariant()); result.Add(notificationResource); diff --git a/NzbDrone.Common/Reflection/ReflectionExtensions.cs b/NzbDrone.Common/Reflection/ReflectionExtensions.cs index 98ff9ff12..0c70d0c42 100644 --- a/NzbDrone.Common/Reflection/ReflectionExtensions.cs +++ b/NzbDrone.Common/Reflection/ReflectionExtensions.cs @@ -7,6 +7,8 @@ namespace NzbDrone.Common.Reflection { public static class ReflectionExtensions { + public static readonly Assembly CoreAssembly = Assembly.Load("NzbDrone.Core"); + public static List GetSimpleProperties(this Type type) { var properties = type.GetProperties(); @@ -58,6 +60,11 @@ public static T GetAttribute(this MemberInfo member, bool isRequired = true) return (T)attribute; } + public static Type FindTypeByName(this Assembly assembly, string name) + { + return assembly.GetTypes().Single(c => c.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)); + } + public static bool HasAttribute(this Type type) { return type.GetCustomAttributes(typeof(TAttribute), true).Any(); diff --git a/NzbDrone.Core.Test/Datastore/Converters/ProviderSettingConverterFixture.cs b/NzbDrone.Core.Test/Datastore/Converters/ProviderSettingConverterFixture.cs new file mode 100644 index 000000000..9aafbee73 --- /dev/null +++ b/NzbDrone.Core.Test/Datastore/Converters/ProviderSettingConverterFixture.cs @@ -0,0 +1,39 @@ +using System; +using FluentAssertions; +using Marr.Data.Converters; +using NUnit.Framework; +using NzbDrone.Core.Datastore.Converters; +using NzbDrone.Core.Test.Framework; +using NzbDrone.Core.ThingiProvider; + +namespace NzbDrone.Core.Test.Datastore.Converters +{ + [TestFixture] + public class ProviderSettingConverterFixture : CoreTest + { + [Test] + public void should_return_null_config_if_config_is_null() + { + var result = Subject.FromDB(new ConverterContext() + { + DbValue = DBNull.Value + }); + + + result.Should().Be(NullConfig.Instance); + } + + [TestCase(null)] + [TestCase("")] + public void should_return_null_config_if_config_is_empty(object dbValue) + { + var result = Subject.FromDB(new ConverterContext() + { + DbValue = dbValue + }); + + + result.Should().Be(NullConfig.Instance); + } + } +} \ No newline at end of file diff --git a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index 430b4d934..39bda7be4 100644 --- a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -102,6 +102,7 @@ + diff --git a/NzbDrone.Core/Datastore/Converters/EmbeddedDocumentConverter.cs b/NzbDrone.Core/Datastore/Converters/EmbeddedDocumentConverter.cs index 89b2ecea1..e144d4cf4 100644 --- a/NzbDrone.Core/Datastore/Converters/EmbeddedDocumentConverter.cs +++ b/NzbDrone.Core/Datastore/Converters/EmbeddedDocumentConverter.cs @@ -1,42 +1,10 @@ using System; -using System.Linq; using Marr.Data.Converters; using Marr.Data.Mapping; using NzbDrone.Common.Serializer; -using NzbDrone.Core.ThingiProvider; namespace NzbDrone.Core.Datastore.Converters { - - public class ProviderSettingConverter : EmbeddedDocumentConverter - { - public override object FromDB(ConverterContext context) - { - if (context.DbValue == DBNull.Value) - { - return DBNull.Value; - } - - var stringValue = (string)context.DbValue; - - if (string.IsNullOrWhiteSpace(stringValue)) - { - return null; - } - - var ordinal = context.DataRecord.GetOrdinal("ConfigContract"); - - var implementation = context.DataRecord.GetString(ordinal); - - - var impType = typeof(IProviderConfig).Assembly.GetTypes().Single(c => c.Name == implementation); - - return Json.Deserialize(stringValue, impType); - } - - } - - public class EmbeddedDocumentConverter : IConverter { public virtual object FromDB(ConverterContext context) diff --git a/NzbDrone.Core/Datastore/Converters/ProviderSettingConverter.cs b/NzbDrone.Core/Datastore/Converters/ProviderSettingConverter.cs new file mode 100644 index 000000000..8e83938a9 --- /dev/null +++ b/NzbDrone.Core/Datastore/Converters/ProviderSettingConverter.cs @@ -0,0 +1,36 @@ +using System; +using Marr.Data.Converters; +using NzbDrone.Common.Reflection; +using NzbDrone.Common.Serializer; +using NzbDrone.Core.ThingiProvider; + +namespace NzbDrone.Core.Datastore.Converters +{ + public class ProviderSettingConverter : EmbeddedDocumentConverter + { + public override object FromDB(ConverterContext context) + { + if (context.DbValue == DBNull.Value) + { + return NullConfig.Instance; + } + + var stringValue = (string)context.DbValue; + + if (string.IsNullOrWhiteSpace(stringValue)) + { + return NullConfig.Instance; + } + + var ordinal = context.DataRecord.GetOrdinal("ConfigContract"); + + var implementation = context.DataRecord.GetString(ordinal); + + + var impType = typeof (IProviderConfig).Assembly.FindTypeByName(implementation); + + return Json.Deserialize(stringValue, impType); + } + + } +} \ No newline at end of file diff --git a/NzbDrone.Core/Datastore/Migration/023_add_config_contract_to_indexers.cs b/NzbDrone.Core/Datastore/Migration/023_add_config_contract_to_indexers.cs new file mode 100644 index 000000000..cf2153605 --- /dev/null +++ b/NzbDrone.Core/Datastore/Migration/023_add_config_contract_to_indexers.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Data; +using FluentMigrator; +using NzbDrone.Common.Serializer; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(23)] + public class add_config_contract_to_indexers : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Update.Table("Indexers").Set(new { ConfigContract = "NewznabSettings" }).Where(new { Implementation = "Newznab" }); + Update.Table("Indexers").Set(new { ConfigContract = "OmgwtfnzbsSettings" }).Where(new { Implementation = "Omgwtfnzbs" }); + Update.Table("Indexers").Set(new { ConfigContract = "NullConfig" }).Where(new { Implementation = "Wombles" }); + Update.Table("Indexers").Set(new { ConfigContract = "NullConfig" }).Where(new { Implementation = "Eztv" }); + + Delete.FromTable("Indexers").IsNull("ConfigContract"); + } + } +} diff --git a/NzbDrone.Core/Indexers/IndexerService.cs b/NzbDrone.Core/Indexers/IndexerService.cs index dd1b9aca9..70e845747 100644 --- a/NzbDrone.Core/Indexers/IndexerService.cs +++ b/NzbDrone.Core/Indexers/IndexerService.cs @@ -10,7 +10,7 @@ public interface IIndexerService : IProviderFactory } - public class IndexerService : ProviderFactory + public class IndexerService : ProviderFactory, IIndexerService { private readonly IIndexerRepository _providerRepository; private readonly IEnumerable _providers; diff --git a/NzbDrone.Core/NzbDrone.Core.csproj b/NzbDrone.Core/NzbDrone.Core.csproj index 8cdb8a182..5956274e0 100644 --- a/NzbDrone.Core/NzbDrone.Core.csproj +++ b/NzbDrone.Core/NzbDrone.Core.csproj @@ -140,6 +140,7 @@ + @@ -172,6 +173,7 @@ + diff --git a/NzbDrone.Core/ThingiProvider/IProvider.cs b/NzbDrone.Core/ThingiProvider/IProvider.cs index 7baeb4bc7..c3308316e 100644 --- a/NzbDrone.Core/ThingiProvider/IProvider.cs +++ b/NzbDrone.Core/ThingiProvider/IProvider.cs @@ -38,23 +38,28 @@ public interface IProvider public abstract class ProviderDefinition : ModelBase { + private IProviderConfig _settings; public string Name { get; set; } public string Implementation { get; set; } public bool Enable { get; set; } - public string ConfigContract + public string ConfigContract { get; set; } + + public IProviderConfig Settings { get { - if (Settings == null) return null; - return Settings.GetType().Name; + return _settings; } set { + _settings = value; + if (value != null) + { + ConfigContract = value.GetType().Name; + } } } - - public IProviderConfig Settings { get; set; } } public interface IProviderConfig diff --git a/NzbDrone.Core/ThingiProvider/ProviderService.cs b/NzbDrone.Core/ThingiProvider/ProviderService.cs index c09a1d79c..b56f6cac3 100644 --- a/NzbDrone.Core/ThingiProvider/ProviderService.cs +++ b/NzbDrone.Core/ThingiProvider/ProviderService.cs @@ -14,7 +14,6 @@ public interface IProviderFactory List All(); List GetAvailableProviders(); TProviderDefinition Get(int id); - //List Schema(); TProviderDefinition Create(TProviderDefinition indexer); void Update(TProviderDefinition indexer); void Delete(int id); @@ -52,22 +51,6 @@ public TProviderDefinition Get(int id) return _providerRepository.Get(id); } - /* public List Schema() - { - var indexers = new List(); - - var newznab = new Indexer(); - newznab.Instance = new Newznab.Newznab(); - newznab.Id = 1; - newznab.Name = "Newznab"; - newznab.Settings = new NewznabSettings(); - newznab.Implementation = "Newznab"; - - indexers.Add(newznab); - - return indexers; - }*/ - public TProviderDefinition Create(TProviderDefinition provider) { return _providerRepository.Insert(provider); @@ -113,10 +96,10 @@ private void RemoveMissingImplementations() { var storedProvider = _providerRepository.All(); - foreach (var providerDefinition in storedProvider.Where(i => GetImplementation(i) == null)) + foreach (var invalidDefinition in storedProvider.Where(def => GetImplementation(def) == null)) { - _logger.Debug("Removing {0} ", providerDefinition.Name); - _providerRepository.Delete(providerDefinition); + _logger.Debug("Removing {0} ", invalidDefinition.Name); + _providerRepository.Delete(invalidDefinition); } } }