mirror of https://github.com/lidarr/Lidarr
added resource mapping validation tests
This commit is contained in:
parent
1d49435675
commit
c3214a2e88
|
@ -0,0 +1,31 @@
|
||||||
|
using System.Reflection;
|
||||||
|
using FluentAssertions;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Common.Reflection;
|
||||||
|
using NzbDrone.Core.Datastore;
|
||||||
|
using NzbDrone.Test.Common;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.Test.MappingTests
|
||||||
|
{
|
||||||
|
public class ReflectionExtensionFixture : TestBase
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void should_get_properties_from_models()
|
||||||
|
{
|
||||||
|
var models = Assembly.Load("NzbDrone.Core").ImplementationsOf<ModelBase>();
|
||||||
|
|
||||||
|
foreach (var model in models)
|
||||||
|
{
|
||||||
|
model.GetSimpleProperties().Should().NotBeEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_be_able_to_get_implementations()
|
||||||
|
{
|
||||||
|
var models = Assembly.Load("NzbDrone.Core").ImplementationsOf<ModelBase>();
|
||||||
|
|
||||||
|
models.Should().NotBeEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
using System;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Api.Episodes;
|
||||||
|
using NzbDrone.Api.Mapping;
|
||||||
|
using NzbDrone.Api.Series;
|
||||||
|
using NzbDrone.Test.Common;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.Test.MappingTests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class ResourceMappingFixture : TestBase
|
||||||
|
{
|
||||||
|
[TestCase(typeof(Core.Tv.Series), typeof(SeriesResource))]
|
||||||
|
[TestCase(typeof(Core.Tv.Episode), typeof(EpisodeResource))]
|
||||||
|
public void matching_fields(Type modelType, Type resourceType)
|
||||||
|
{
|
||||||
|
MappingValidation.ValidateMapping(modelType, resourceType);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -50,9 +50,19 @@
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Reference Include="FizzWare.NBuilder">
|
||||||
|
<HintPath>..\packages\NBuilder.3.0.1.1\lib\FizzWare.NBuilder.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="FluentAssertions, Version=2.0.1.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
|
||||||
|
<SpecificVersion>False</SpecificVersion>
|
||||||
|
<HintPath>..\packages\FluentAssertions.2.0.1\lib\net40\FluentAssertions.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="nunit.framework">
|
<Reference Include="nunit.framework">
|
||||||
<HintPath>..\packages\NUnit.2.6.2\lib\nunit.framework.dll</HintPath>
|
<HintPath>..\packages\NUnit.2.6.2\lib\nunit.framework.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="Omu.ValueInjecter">
|
||||||
|
<HintPath>..\packages\valueinjecter.2.3.3\lib\net35\Omu.ValueInjecter.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
<Reference Include="System.Xml.Linq" />
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
@ -62,6 +72,8 @@
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="MappingTests\ReflectionExtensionFixture.cs" />
|
||||||
|
<Compile Include="MappingTests\ResourceMappingFixture.cs" />
|
||||||
<Compile Include="StaticResourceMapperFixture.cs" />
|
<Compile Include="StaticResourceMapperFixture.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
|
<package id="FluentAssertions" version="2.0.1" targetFramework="net40" />
|
||||||
|
<package id="NBuilder" version="3.0.1.1" targetFramework="net40" />
|
||||||
<package id="NUnit" version="2.6.2" targetFramework="net40" />
|
<package id="NUnit" version="2.6.2" targetFramework="net40" />
|
||||||
|
<package id="valueinjecter" version="2.3.3" targetFramework="net40" />
|
||||||
</packages>
|
</packages>
|
|
@ -1,10 +1,12 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using NzbDrone.Api.REST;
|
||||||
using NzbDrone.Core.MediaFiles;
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
using NzbDrone.Core.Model;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
namespace NzbDrone.Api.Episodes
|
namespace NzbDrone.Api.Episodes
|
||||||
{
|
{
|
||||||
public class EpisodeResource
|
public class EpisodeResource : RestResource
|
||||||
{
|
{
|
||||||
public Int32 Id { get; set; }
|
public Int32 Id { get; set; }
|
||||||
public Int32 SeriesId { get; set; }
|
public Int32 SeriesId { get; set; }
|
||||||
|
@ -12,9 +14,19 @@ namespace NzbDrone.Api.Episodes
|
||||||
public Int32 SeasonNumber { get; set; }
|
public Int32 SeasonNumber { get; set; }
|
||||||
public Int32 EpisodeNumber { get; set; }
|
public Int32 EpisodeNumber { get; set; }
|
||||||
public String Title { get; set; }
|
public String Title { get; set; }
|
||||||
public DateTime AirDate { get; set; }
|
public DateTime? AirDate { get; set; }
|
||||||
public Int32 Status { get; set; }
|
public EpisodeStatuses Status { get; set; }
|
||||||
public String Overview { get; set; }
|
public String Overview { get; set; }
|
||||||
public EpisodeFile EpisodeFile { get; set; }
|
public EpisodeFile EpisodeFile { get; set; }
|
||||||
|
|
||||||
|
public Boolean HasFile { get; set; }
|
||||||
|
public Boolean Ignored { get; set; }
|
||||||
|
public Int32 SceneEpisodeNumber { get; set; }
|
||||||
|
public Int32 SceneSeasonNumber { get; set; }
|
||||||
|
public Int32 TvDbEpisodeId { get; set; }
|
||||||
|
public Int32? AbsoluteEpisodeNumber { get; set; }
|
||||||
|
public DateTime? EndTime { get; set; }
|
||||||
|
public DateTime? GrabDate { get; set; }
|
||||||
|
public PostDownloadStatusType PostDownloadStatus { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using NzbDrone.Api.REST;
|
||||||
|
using NzbDrone.Common.Reflection;
|
||||||
|
using NzbDrone.Core.Datastore;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.Mapping
|
||||||
|
{
|
||||||
|
public static class MappingValidation
|
||||||
|
{
|
||||||
|
public static void ValidateMapping(Type modelType, Type resourceType)
|
||||||
|
{
|
||||||
|
var errors = modelType.GetSimpleProperties().Select(p => GetError(resourceType, p)).Where(c => c != null).ToList();
|
||||||
|
|
||||||
|
if (errors.Any())
|
||||||
|
{
|
||||||
|
throw new ResourceMappingException(errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintExtraProperties(modelType, resourceType);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void PrintExtraProperties(Type modelType, Type resourceType)
|
||||||
|
{
|
||||||
|
var resourceBaseProperties = typeof(RestResource).GetProperties().Select(c => c.Name);
|
||||||
|
var resourceProperties = resourceType.GetProperties().Select(c => c.Name).Except(resourceBaseProperties);
|
||||||
|
var modelProperties = modelType.GetProperties().Select(c => c.Name);
|
||||||
|
|
||||||
|
var extra = resourceProperties.Except(modelProperties);
|
||||||
|
|
||||||
|
foreach (var extraProp in extra)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Extra: [{0}]", extraProp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetError(Type resourceType, PropertyInfo modelProperty)
|
||||||
|
{
|
||||||
|
var resourceProperty = resourceType.GetProperties().FirstOrDefault(c => c.Name == modelProperty.Name);
|
||||||
|
|
||||||
|
if (resourceProperty == null)
|
||||||
|
{
|
||||||
|
return string.Format("public {0} {1} {{ get; set; }}", modelProperty.PropertyType.Name, modelProperty.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resourceProperty.PropertyType != modelProperty.PropertyType)
|
||||||
|
{
|
||||||
|
return string.Format("Excpected {0}.{1} to have type of {2} but found {3}", resourceType.Name, resourceProperty.Name, modelProperty.PropertyType, resourceProperty.PropertyType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.Mapping
|
||||||
|
{
|
||||||
|
public class ResourceMappingException : ApplicationException
|
||||||
|
{
|
||||||
|
public ResourceMappingException(IEnumerable<string> error)
|
||||||
|
: base(Environment.NewLine + String.Join(Environment.NewLine, error.OrderBy(c => c)))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Omu.ValueInjecter;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.Mapping
|
||||||
|
{
|
||||||
|
public static class ValueInjectorExtensions
|
||||||
|
{
|
||||||
|
public static TTarget InjectTo<TTarget>(this object source) where TTarget : new()
|
||||||
|
{
|
||||||
|
var targetType = typeof(TTarget);
|
||||||
|
|
||||||
|
if (targetType.IsGenericType &&
|
||||||
|
targetType.GetGenericTypeDefinition() != null &&
|
||||||
|
targetType.GetGenericTypeDefinition().GetInterfaces().Contains(typeof(IEnumerable)) &&
|
||||||
|
source.GetType().IsGenericType &&
|
||||||
|
source.GetType().GetGenericTypeDefinition() != null &&
|
||||||
|
source.GetType().GetGenericTypeDefinition().GetInterfaces().Contains(typeof(IEnumerable)))
|
||||||
|
{
|
||||||
|
|
||||||
|
var result = new TTarget();
|
||||||
|
|
||||||
|
var listSubType = targetType.GetGenericArguments()[0];
|
||||||
|
var listType = typeof(List<>).MakeGenericType(listSubType);
|
||||||
|
var addMethod = listType.GetMethod("Add");
|
||||||
|
|
||||||
|
foreach (var sourceItem in (IEnumerable)source)
|
||||||
|
{
|
||||||
|
var e = Activator.CreateInstance(listSubType).InjectFrom(sourceItem);
|
||||||
|
addMethod.Invoke(result, new[] { e });
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (TTarget)new TTarget().InjectFrom(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -88,6 +88,9 @@
|
||||||
<Compile Include="Frontend\IndexModule.cs" />
|
<Compile Include="Frontend\IndexModule.cs" />
|
||||||
<Compile Include="Frontend\StaticResourceProvider.cs" />
|
<Compile Include="Frontend\StaticResourceProvider.cs" />
|
||||||
<Compile Include="Frontend\StaticResourceMapper.cs" />
|
<Compile Include="Frontend\StaticResourceMapper.cs" />
|
||||||
|
<Compile Include="Mapping\MappingValidation.cs" />
|
||||||
|
<Compile Include="Mapping\ResourceMappingException.cs" />
|
||||||
|
<Compile Include="Mapping\ValueInjectorExtensions.cs" />
|
||||||
<Compile Include="Missing\MissingResource.cs" />
|
<Compile Include="Missing\MissingResource.cs" />
|
||||||
<Compile Include="Missing\MissingModule.cs" />
|
<Compile Include="Missing\MissingModule.cs" />
|
||||||
<Compile Include="NzbDroneRestModule.cs" />
|
<Compile Include="NzbDroneRestModule.cs" />
|
||||||
|
|
|
@ -40,7 +40,7 @@ namespace NzbDrone.Api.REST
|
||||||
Get[ID_ROUTE] = options =>
|
Get[ID_ROUTE] = options =>
|
||||||
{
|
{
|
||||||
EnsureImplementation(GetResourceById);
|
EnsureImplementation(GetResourceById);
|
||||||
var resource = GetResourceById(options.Id);
|
var resource = GetResourceById((int)options.Id);
|
||||||
return resource.AsResponse();
|
return resource.AsResponse();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ namespace NzbDrone.Api.REST
|
||||||
Delete[ID_ROUTE] = options =>
|
Delete[ID_ROUTE] = options =>
|
||||||
{
|
{
|
||||||
EnsureImplementation(DeleteResource);
|
EnsureImplementation(DeleteResource);
|
||||||
DeleteResource(options.Id);
|
DeleteResource((int)options.Id);
|
||||||
return new Response { StatusCode = HttpStatusCode.OK };
|
return new Response { StatusCode = HttpStatusCode.OK };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using AutoMapper;
|
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using NzbDrone.Api.Extensions;
|
using NzbDrone.Api.Extensions;
|
||||||
using NzbDrone.Common;
|
using NzbDrone.Common;
|
||||||
|
using NzbDrone.Common;
|
||||||
using NzbDrone.Core.SeriesStats;
|
using NzbDrone.Core.SeriesStats;
|
||||||
|
using NzbDrone.Api.Mapping;
|
||||||
using NzbDrone.Core.Tv;
|
using NzbDrone.Core.Tv;
|
||||||
using NzbDrone.Core.Model;
|
|
||||||
using NzbDrone.Api.Validation;
|
using NzbDrone.Api.Validation;
|
||||||
|
|
||||||
namespace NzbDrone.Api.Series
|
namespace NzbDrone.Api.Series
|
||||||
|
@ -43,7 +42,8 @@ namespace NzbDrone.Api.Series
|
||||||
{
|
{
|
||||||
var series = _seriesService.GetAllSeries().ToList();
|
var series = _seriesService.GetAllSeries().ToList();
|
||||||
var seriesStats = _seriesStatisticsService.SeriesStatistics();
|
var seriesStats = _seriesStatisticsService.SeriesStatistics();
|
||||||
var seriesModels = Mapper.Map<List<Core.Tv.Series>, List<SeriesResource>>(series);
|
|
||||||
|
var seriesModels = series.InjectTo<List<SeriesResource>>();
|
||||||
|
|
||||||
foreach (var s in seriesModels)
|
foreach (var s in seriesModels)
|
||||||
{
|
{
|
||||||
|
@ -52,7 +52,7 @@ namespace NzbDrone.Api.Series
|
||||||
|
|
||||||
s.EpisodeCount = stats.EpisodeCount;
|
s.EpisodeCount = stats.EpisodeCount;
|
||||||
s.EpisodeFileCount = stats.EpisodeFileCount;
|
s.EpisodeFileCount = stats.EpisodeFileCount;
|
||||||
s.NumberOfSeasons = stats.NumberOfSeasons;
|
s.SeasonsCount = stats.NumberOfSeasons;
|
||||||
s.NextAiring = stats.NextAiring;
|
s.NextAiring = stats.NextAiring;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,8 +62,7 @@ namespace NzbDrone.Api.Series
|
||||||
private SeriesResource GetSeries(int id)
|
private SeriesResource GetSeries(int id)
|
||||||
{
|
{
|
||||||
var series = _seriesService.GetSeries(id);
|
var series = _seriesService.GetSeries(id);
|
||||||
var seriesModels = Mapper.Map<Core.Tv.Series, SeriesResource>(series);
|
return series.InjectTo<SeriesResource>();
|
||||||
return seriesModels;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private SeriesResource AddSeries(SeriesResource seriesResource)
|
private SeriesResource AddSeries(SeriesResource seriesResource)
|
||||||
|
@ -74,9 +73,9 @@ namespace NzbDrone.Api.Series
|
||||||
//Todo: We need to create the folder if the user is adding a new series
|
//Todo: We need to create the folder if the user is adding a new series
|
||||||
//(we can just create the folder and it won't blow up if it already exists)
|
//(we can just create the folder and it won't blow up if it already exists)
|
||||||
//We also need to remove any special characters from the filename before attempting to create it
|
//We also need to remove any special characters from the filename before attempting to create it
|
||||||
var series = Mapper.Map<SeriesResource, Core.Tv.Series>(seriesResource);
|
var series = seriesResource.InjectTo<Core.Tv.Series>();
|
||||||
_seriesService.AddSeries(series);
|
_seriesService.AddSeries(series);
|
||||||
return Mapper.Map<Core.Tv.Series, SeriesResource>(series);
|
return series.InjectTo<SeriesResource>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private SeriesResource UpdateSeries(SeriesResource seriesResource)
|
private SeriesResource UpdateSeries(SeriesResource seriesResource)
|
||||||
|
@ -91,17 +90,11 @@ namespace NzbDrone.Api.Series
|
||||||
series.RootFolderId = seriesResource.RootFolderId;
|
series.RootFolderId = seriesResource.RootFolderId;
|
||||||
series.FolderName = seriesResource.FolderName;
|
series.FolderName = seriesResource.FolderName;
|
||||||
|
|
||||||
series.BacklogSetting = (BacklogSettingType)seriesResource.BacklogSetting;
|
series.BacklogSetting = seriesResource.BacklogSetting;
|
||||||
|
|
||||||
if (!String.IsNullOrWhiteSpace(seriesResource.CustomStartDate))
|
|
||||||
series.CustomStartDate = DateTime.Parse(seriesResource.CustomStartDate, null, DateTimeStyles.RoundtripKind);
|
|
||||||
|
|
||||||
else
|
|
||||||
series.CustomStartDate = null;
|
|
||||||
|
|
||||||
_seriesService.UpdateSeries(series);
|
_seriesService.UpdateSeries(series);
|
||||||
|
|
||||||
return Mapper.Map<Core.Tv.Series, SeriesResource>(series);
|
return series.InjectTo<SeriesResource>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DeleteSeries(int id)
|
private void DeleteSeries(int id)
|
||||||
|
@ -111,23 +104,4 @@ namespace NzbDrone.Api.Series
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SeriesValidator : AbstractValidator<Core.Tv.Series>
|
|
||||||
{
|
|
||||||
private readonly DiskProvider _diskProvider;
|
|
||||||
|
|
||||||
public SeriesValidator(DiskProvider diskProvider)
|
|
||||||
{
|
|
||||||
_diskProvider = diskProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SeriesValidator()
|
|
||||||
{
|
|
||||||
RuleSet("POST", () =>
|
|
||||||
{
|
|
||||||
RuleFor(s => s.Id).GreaterThan(0);
|
|
||||||
RuleFor(s => s.Path).NotEmpty().Must(_diskProvider.FolderExists);
|
|
||||||
RuleFor(s => s.QualityProfileId).GreaterThan(0);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NzbDrone.Api.REST;
|
using NzbDrone.Api.REST;
|
||||||
|
using NzbDrone.Core.Model;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
namespace NzbDrone.Api.Series
|
namespace NzbDrone.Api.Series
|
||||||
{
|
{
|
||||||
|
@ -15,21 +17,17 @@ namespace NzbDrone.Api.Series
|
||||||
public Int32 SeasonsCount { get; set; }
|
public Int32 SeasonsCount { get; set; }
|
||||||
public Int32 EpisodeCount { get; set; }
|
public Int32 EpisodeCount { get; set; }
|
||||||
public Int32 EpisodeFileCount { get; set; }
|
public Int32 EpisodeFileCount { get; set; }
|
||||||
public String Status { get; set; }
|
public SeriesStatusType Status { get; set; }
|
||||||
public String AirsDayOfWeek { get; set; }
|
|
||||||
public String QualityProfileName { get; set; }
|
public String QualityProfileName { get; set; }
|
||||||
public String Overview { get; set; }
|
public String Overview { get; set; }
|
||||||
public Int32 Episodes { get; set; }
|
|
||||||
public Boolean HasBanner { get; set; }
|
|
||||||
public DateTime? NextAiring { get; set; }
|
public DateTime? NextAiring { get; set; }
|
||||||
public String Details { get; set; }
|
|
||||||
public String Network { get; set; }
|
public String Network { get; set; }
|
||||||
public String AirTime { get; set; }
|
public String AirTime { get; set; }
|
||||||
public String Language { get; set; }
|
|
||||||
public Int32 NumberOfSeasons { get; set; }
|
|
||||||
public Int32 UtcOffset { get; set; }
|
public Int32 UtcOffset { get; set; }
|
||||||
public List<Core.MediaCover.MediaCover> Images { get; set; }
|
public List<Core.MediaCover.MediaCover> Images { get; set; }
|
||||||
|
|
||||||
|
public String Path { get; set; }
|
||||||
|
|
||||||
//View & Edit
|
//View & Edit
|
||||||
public int RootFolderId { get; set; }
|
public int RootFolderId { get; set; }
|
||||||
public string FolderName { get; set; }
|
public string FolderName { get; set; }
|
||||||
|
@ -38,7 +36,22 @@ namespace NzbDrone.Api.Series
|
||||||
//Editing Only
|
//Editing Only
|
||||||
public Boolean SeasonFolder { get; set; }
|
public Boolean SeasonFolder { get; set; }
|
||||||
public Boolean Monitored { get; set; }
|
public Boolean Monitored { get; set; }
|
||||||
public Int32 BacklogSetting { get; set; }
|
public BacklogSettingType BacklogSetting { get; set; }
|
||||||
public String CustomStartDate { get; set; }
|
public DateTime? CustomStartDate { get; set; }
|
||||||
|
|
||||||
|
public Boolean UseSceneNumbering { get; set; }
|
||||||
|
public Int32 Id { get; set; }
|
||||||
|
public Int32 Runtime { get; set; }
|
||||||
|
public Int32 TvdbId { get; set; }
|
||||||
|
public Int32 TvRageId { get; set; }
|
||||||
|
public DateTime? FirstAired { get; set; }
|
||||||
|
public DateTime? LastInfoSync { get; set; }
|
||||||
|
public SeriesTypes SeriesType { get; set; }
|
||||||
|
public String CleanTitle { get; set; }
|
||||||
|
public String ImdbId { get; set; }
|
||||||
|
public String TitleSlug { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,6 +118,7 @@
|
||||||
<Compile Include="HostController.cs" />
|
<Compile Include="HostController.cs" />
|
||||||
<Compile Include="IJsonSerializer.cs" />
|
<Compile Include="IJsonSerializer.cs" />
|
||||||
<Compile Include="Instrumentation\VersionLayoutRenderer.cs" />
|
<Compile Include="Instrumentation\VersionLayoutRenderer.cs" />
|
||||||
|
<Compile Include="Reflection\ReflectionExtensions.cs" />
|
||||||
<Compile Include="StringExtention.cs" />
|
<Compile Include="StringExtention.cs" />
|
||||||
<Compile Include="HttpProvider.cs" />
|
<Compile Include="HttpProvider.cs" />
|
||||||
<Compile Include="ConfigFileProvider.cs" />
|
<Compile Include="ConfigFileProvider.cs" />
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace NzbDrone.Common.Reflection
|
||||||
|
{
|
||||||
|
public static class ReflectionExtensions
|
||||||
|
{
|
||||||
|
public static List<PropertyInfo> GetSimpleProperties(this Type type)
|
||||||
|
{
|
||||||
|
var properties = type.GetProperties();
|
||||||
|
return properties.Where(c => c.PropertyType.IsSimpleType()).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static List<Type> ImplementationsOf<T>(this Assembly assembly)
|
||||||
|
{
|
||||||
|
return assembly.GetTypes().Where(c => typeof(T).IsAssignableFrom(c)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static bool IsSimpleType(this Type type)
|
||||||
|
{
|
||||||
|
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||||||
|
{
|
||||||
|
type = type.GetGenericArguments()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return type.IsPrimitive
|
||||||
|
|| type.IsEnum
|
||||||
|
|| type == typeof(string)
|
||||||
|
|| type == typeof(DateTime)
|
||||||
|
|| type == typeof(Decimal);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsReadable(this PropertyInfo propertyInfo)
|
||||||
|
{
|
||||||
|
return propertyInfo.CanRead && propertyInfo.GetGetMethod(false) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsWritable(this PropertyInfo propertyInfo)
|
||||||
|
{
|
||||||
|
return propertyInfo.CanWrite && propertyInfo.GetSetMethod(false) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Marr.Data;
|
using Marr.Data;
|
||||||
using Marr.Data.Mapping;
|
using Marr.Data.Mapping;
|
||||||
|
using NzbDrone.Common.Reflection;
|
||||||
using NzbDrone.Core.Tv;
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Datastore
|
namespace NzbDrone.Core.Datastore
|
||||||
|
@ -43,7 +44,7 @@ namespace NzbDrone.Core.Datastore
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsSimpleType(propertyInfo.PropertyType) || MapRepository.Instance.TypeConverters.ContainsKey(propertyInfo.PropertyType))
|
if (propertyInfo.PropertyType.IsSimpleType() || MapRepository.Instance.TypeConverters.ContainsKey(propertyInfo.PropertyType))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -51,28 +52,6 @@ namespace NzbDrone.Core.Datastore
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsSimpleType(Type type)
|
|
||||||
{
|
|
||||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
|
|
||||||
{
|
|
||||||
type = type.GetGenericArguments()[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
return type.IsPrimitive
|
|
||||||
|| type.IsEnum
|
|
||||||
|| type == typeof(string)
|
|
||||||
|| type == typeof(DateTime)
|
|
||||||
|| type == typeof(Decimal);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsReadable(this PropertyInfo propertyInfo)
|
|
||||||
{
|
|
||||||
return propertyInfo.CanRead && propertyInfo.GetGetMethod(false) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsWritable(this PropertyInfo propertyInfo)
|
|
||||||
{
|
|
||||||
return propertyInfo.CanWrite && propertyInfo.GetSetMethod(false) != null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -66,6 +66,7 @@
|
||||||
<option name="m_minLength" value="1" />
|
<option name="m_minLength" value="1" />
|
||||||
<option name="m_maxLength" value="32" />
|
<option name="m_maxLength" value="32" />
|
||||||
</inspection_tool>
|
</inspection_tool>
|
||||||
|
<inspection_tool class="LossyEncoding" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
<inspection_tool class="NestedAssignmentJS" enabled="true" level="WARNING" enabled_by_default="true" />
|
<inspection_tool class="NestedAssignmentJS" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
<inspection_tool class="NestedFunctionCallJS" enabled="false" level="ERROR" enabled_by_default="false" />
|
<inspection_tool class="NestedFunctionCallJS" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||||
<inspection_tool class="NestedSwitchStatementJS" enabled="true" level="WARNING" enabled_by_default="true" />
|
<inspection_tool class="NestedSwitchStatementJS" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
@ -85,6 +86,13 @@
|
||||||
</inspection_tool>
|
</inspection_tool>
|
||||||
<inspection_tool class="SwitchStatementWithNoDefaultBranchJS" enabled="true" level="WARNING" enabled_by_default="true" />
|
<inspection_tool class="SwitchStatementWithNoDefaultBranchJS" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
<inspection_tool class="TailRecursionJS" enabled="true" level="WARNING" enabled_by_default="true" />
|
<inspection_tool class="TailRecursionJS" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="TaskInspection" enabled="true" level="INFO" enabled_by_default="true">
|
||||||
|
<option name="suppressedTasks">
|
||||||
|
<set>
|
||||||
|
<option value="LESS" />
|
||||||
|
</set>
|
||||||
|
</option>
|
||||||
|
</inspection_tool>
|
||||||
<inspection_tool class="UnterminatedStatementJS" enabled="true" level="ERROR" enabled_by_default="true">
|
<inspection_tool class="UnterminatedStatementJS" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
<option name="ignoreSemicolonAtEndOfBlock" value="true" />
|
<option name="ignoreSemicolonAtEndOfBlock" value="true" />
|
||||||
</inspection_tool>
|
</inspection_tool>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<td>{{{formatStatus status monitored}}}</td>
|
<td>{{{formatStatus status monitored}}}</td>
|
||||||
<td><a href="/series/details/{{id}}">{{title}}</a></td>
|
<td><a href="/series/details/{{id}}">{{title}}</a></td>
|
||||||
<td name="numberOfSeasons"></td>
|
<td name="seasonCount"></td>
|
||||||
<td name="qualityProfileName"></td>
|
<td name="qualityProfileName"></td>
|
||||||
<td name="network"></td>
|
<td name="network"></td>
|
||||||
<!-- If only DT could access the backbone model -->
|
<!-- If only DT could access the backbone model -->
|
||||||
|
|
Loading…
Reference in New Issue