Skip to content

Commit

Permalink
Translate fields on the backend
Browse files Browse the repository at this point in the history
(cherry picked from commit 48b12f5b00429a7cd218d23f0544641b0da62a06)
  • Loading branch information
stevietv authored and mynameisbogdan committed Dec 31, 2023
1 parent 1400a88 commit 3c6386f
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 15 deletions.
13 changes: 13 additions & 0 deletions src/NzbDrone.Api.Test/ClientSchemaTests/SchemaBuilderFixture.cs
@@ -1,6 +1,9 @@
using System.Collections.Generic;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Localization;
using NzbDrone.Test.Common;
using Radarr.Http.ClientSchema;

Expand All @@ -9,6 +12,16 @@ namespace NzbDrone.Api.Test.ClientSchemaTests
[TestFixture]
public class SchemaBuilderFixture : TestBase
{
[SetUp]
public void Setup()
{
Mocker.GetMock<ILocalizationService>()
.Setup(s => s.GetLocalizedString(It.IsAny<string>(), It.IsAny<Dictionary<string, object>>()))
.Returns<string, Dictionary<string, object>>((s, d) => s);

SchemaBuilder.Initialize(Mocker.Container);
}

[Test]
public void should_return_field_for_every_property()
{
Expand Down
24 changes: 24 additions & 0 deletions src/NzbDrone.Core/Annotations/FieldDefinitionAttribute.cs
Expand Up @@ -41,6 +41,23 @@ public FieldOptionAttribute(string label = null, [CallerLineNumber] int order =
public string Hint { get; set; }
}

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class FieldTokenAttribute : Attribute
{
public FieldTokenAttribute(TokenField field, string label = "", string token = "", object value = null)
{
Label = label;
Field = field;
Token = token;
Value = value?.ToString();
}

public string Label { get; set; }
public TokenField Field { get; set; }
public string Token { get; set; }
public string Value { get; set; }
}

public class FieldSelectOption
{
public int Value { get; set; }
Expand Down Expand Up @@ -84,4 +101,11 @@ public enum PrivacyLevel
ApiKey,
UserName
}

public enum TokenField
{
Label,
HelpText,
HelpTextWarning
}
}
3 changes: 3 additions & 0 deletions src/NzbDrone.Host/Bootstrap.cs
Expand Up @@ -23,6 +23,7 @@
using NzbDrone.Common.Instrumentation.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Datastore.Extensions;
using Radarr.Http.ClientSchema;
using PostgresOptions = NzbDrone.Core.Datastore.PostgresOptions;

namespace NzbDrone.Host
Expand Down Expand Up @@ -146,6 +147,8 @@ public static IHostBuilder CreateConsoleHostBuilder(string[] args, StartupContex
.AddNzbDroneLogger()
.AddDatabase()
.AddStartupContext(context);
SchemaBuilder.Initialize(c);
})
.ConfigureServices(services =>
{
Expand Down
28 changes: 16 additions & 12 deletions src/NzbDrone.Integration.Test/IntegrationTest.cs
@@ -1,3 +1,5 @@
using System;
using System.Linq;
using System.Threading;
using NLog;
using NUnit.Framework;
Expand All @@ -7,7 +9,6 @@
using NzbDrone.Core.Indexers.Newznab;
using NzbDrone.Test.Common;
using NzbDrone.Test.Common.Datastore;
using Radarr.Http.ClientSchema;

namespace NzbDrone.Integration.Test
{
Expand Down Expand Up @@ -48,19 +49,22 @@ protected override void StartTestTarget()
protected override void InitializeTestTarget()
{
// Make sure tasks have been initialized so the config put below doesn't cause errors
WaitForCompletion(() => Tasks.All().SelectList(x => x.TaskName).Contains("RssSync"), 20000);
WaitForCompletion(() => Tasks.All().SelectList(x => x.TaskName).Contains("RssSync"), 30000);

Indexers.Post(new Radarr.Api.V3.Indexers.IndexerResource
var indexer = Indexers.Schema().FirstOrDefault(i => i.Implementation == nameof(Newznab));

if (indexer == null)
{
EnableRss = false,
EnableInteractiveSearch = false,
EnableAutomaticSearch = false,
ConfigContract = nameof(NewznabSettings),
Implementation = nameof(Newznab),
Name = "NewznabTest",
Protocol = Core.Indexers.DownloadProtocol.Usenet,
Fields = SchemaBuilder.ToSchema(new NewznabSettings())
});
throw new NullReferenceException("Expected valid indexer schema, found null");
}

indexer.EnableRss = false;
indexer.EnableInteractiveSearch = false;
indexer.EnableAutomaticSearch = false;
indexer.ConfigContract = nameof(NewznabSettings);
indexer.Implementation = nameof(Newznab);
indexer.Name = "NewznabTest";
indexer.Protocol = Core.Indexers.DownloadProtocol.Usenet;

// Change Console Log Level to Debug so we get more details.
var config = HostConfig.Get(1);
Expand Down
2 changes: 2 additions & 0 deletions src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs
Expand Up @@ -23,6 +23,8 @@ public AutoMoqer()
SetupAutoMoqer(CreateTestContainer(new Container()));
}

public IContainer Container => _container;

public virtual T Resolve<T>()
{
var result = _container.Resolve<T>();
Expand Down
46 changes: 43 additions & 3 deletions src/Radarr.Http/ClientSchema/SchemaBuilder.cs
Expand Up @@ -3,18 +3,26 @@
using System.Linq;
using System.Reflection;
using System.Text.Json;
using DryIoc;
using NzbDrone.Common.EnsureThat;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Reflection;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Localization;

namespace Radarr.Http.ClientSchema
{
public static class SchemaBuilder
{
private const string PRIVATE_VALUE = "********";
private static Dictionary<Type, FieldMapping[]> _mappings = new Dictionary<Type, FieldMapping[]>();
private static ILocalizationService _localizationService;

public static void Initialize(IContainer container)
{
_localizationService = container.Resolve<ILocalizationService>();
}

public static List<Field> ToSchema(object model)
{
Expand Down Expand Up @@ -107,13 +115,27 @@ private static FieldMapping[] GetFieldMapping(Type type, string prefix, Func<obj
if (propertyInfo.PropertyType.IsSimpleType())
{
var fieldAttribute = property.Item2;

var label = fieldAttribute.Label.IsNotNullOrWhiteSpace()
? _localizationService.GetLocalizedString(fieldAttribute.Label,
GetTokens(type, fieldAttribute.Label, TokenField.Label))
: fieldAttribute.Label;
var helpText = fieldAttribute.HelpText.IsNotNullOrWhiteSpace()
? _localizationService.GetLocalizedString(fieldAttribute.HelpText,
GetTokens(type, fieldAttribute.Label, TokenField.HelpText))
: fieldAttribute.HelpText;
var helpTextWarning = fieldAttribute.HelpTextWarning.IsNotNullOrWhiteSpace()
? _localizationService.GetLocalizedString(fieldAttribute.HelpTextWarning,
GetTokens(type, fieldAttribute.Label, TokenField.HelpTextWarning))
: fieldAttribute.HelpTextWarning;

var field = new Field
{
Name = prefix + GetCamelCaseName(propertyInfo.Name),
Label = fieldAttribute.Label,
Label = label,
Unit = fieldAttribute.Unit,
HelpText = fieldAttribute.HelpText,
HelpTextWarning = fieldAttribute.HelpTextWarning,
HelpText = helpText,
HelpTextWarning = helpTextWarning,
HelpLink = fieldAttribute.HelpLink,
Order = fieldAttribute.Order,
Advanced = fieldAttribute.Advanced,
Expand Down Expand Up @@ -173,6 +195,24 @@ private static FieldMapping[] GetFieldMapping(Type type, string prefix, Func<obj
.ToArray();
}

private static Dictionary<string, object> GetTokens(Type type, string label, TokenField field)
{
var tokens = new Dictionary<string, object>();

foreach (var propertyInfo in type.GetProperties())
{
foreach (var attribute in propertyInfo.GetCustomAttributes(true))
{
if (attribute is FieldTokenAttribute fieldTokenAttribute && fieldTokenAttribute.Field == field && fieldTokenAttribute.Label == label)
{
tokens.Add(fieldTokenAttribute.Token, fieldTokenAttribute.Value);
}
}
}

return tokens;
}

private static List<SelectOption> GetSelectOptions(Type selectOptions)
{
if (selectOptions.IsEnum)
Expand Down

0 comments on commit 3c6386f

Please sign in to comment.