Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Save Shell Config SubSections #14490

Merged
merged 23 commits into from
Oct 18, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Json;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OrchardCore.Environment.Shell.Configuration.Internal;

namespace OrchardCore.Environment.Shell.Configuration
{
Expand Down Expand Up @@ -35,35 +39,41 @@ public async Task SaveAsync(string tenant, IDictionary<string, string> data)
var tenantFolder = Path.Combine(_container, tenant);
var appsettings = Path.Combine(tenantFolder, "appsettings.json");

JObject config;
IDictionary<string, string> configData;
if (File.Exists(appsettings))
{
using var streamReader = File.OpenText(appsettings);
using var jsonReader = new JsonTextReader(streamReader);
config = await JObject.LoadAsync(jsonReader);
using var streamReader = File.OpenRead(appsettings);
configData = JsonConfigurationFileParser.Parse(streamReader);
}
else
{
config = new JObject();
configData = new Dictionary<string, string>();
}

foreach (var key in data.Keys)
{
if (data[key] != null)
{
config[key] = data[key];
configData[key] = data[key];
}
else
{
config.Remove(key);
configData.Remove(key);
}
}

var configuration = new ConfigurationBuilder()
.Add(new UpdatableDataProvider(configData))
.Build();

using var disposable = configuration as IDisposable;
var jConfiguration = ConfigToJObject(configuration);

Directory.CreateDirectory(tenantFolder);

using var streamWriter = File.CreateText(appsettings);
using var jsonWriter = new JsonTextWriter(streamWriter) { Formatting = Formatting.Indented };
await config.WriteToAsync(jsonWriter);
await jConfiguration.WriteToAsync(jsonWriter);
}

public Task RemoveAsync(string tenant)
Expand All @@ -87,5 +97,51 @@ public Task RemoveAsync(string tenant)

return Task.CompletedTask;
}

private static JToken ConfigToJObject(IConfiguration configuration)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might need to add this as extension method to IConfiguration, so could be used anywhere across the code-base

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I will because it will be used in our other IShellConfigurationSources for database and blob.

Work in progress

{
JArray jArray = null;
JObject jObject = null;

foreach (var child in configuration.GetChildren())
{
if (int.TryParse(child.Key, out _))
{
jArray ??= new JArray();
if (child.GetChildren().Any())
{
jArray.Add(ConfigToJObject(child));
}
else
{
jArray.Add(child.Value);
}
}
else
{
jObject ??= new JObject();
if (child.GetChildren().Any())
{
jObject.Add(child.Key, ConfigToJObject(child));
}
else
{
jObject.Add(child.Key, child.Value);
}
}
}

if (jArray is not null)
{
if (jObject is not null)
{
throw new InvalidOperationException("Can't use a numeric key inside an object.");
}

return jArray;
}

return jObject ?? new JObject();
}
}
}
22 changes: 11 additions & 11 deletions src/OrchardCore/OrchardCore/Shell/ShellSettingsManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -179,21 +179,21 @@ public async Task SaveSettingsAsync(ShellSettings settings)

await _tenantsSettingsSources.SaveAsync(settings.Name, tenantSettings.ToObject<Dictionary<string, string>>());

var tenantConfig = new JObject();

var sections = settings.ShellConfiguration.GetChildren()
.Where(s => !s.GetChildren().Any())
.ToArray();

foreach (var section in sections)
var tenantConfig = new Dictionary<string, string>();
foreach (var config in settings.ShellConfiguration.AsEnumerable())
{
if (settings[section.Key] != configuration[section.Key])
if (settings.ShellConfiguration.GetSection(config.Key).GetChildren().Any())
{
continue;
}

if (settings[config.Key] != configuration[config.Key])
{
tenantConfig[section.Key] = settings[section.Key];
tenantConfig[config.Key] = settings[config.Key];
}
else
{
tenantConfig[section.Key] = null;
tenantConfig[config.Key] = null;
}
}

Expand All @@ -202,7 +202,7 @@ public async Task SaveSettingsAsync(ShellSettings settings)
await _tenantConfigSemaphore.WaitAsync();
try
{
await _tenantConfigSources.SaveAsync(settings.Name, tenantConfig.ToObject<Dictionary<string, string>>());
await _tenantConfigSources.SaveAsync(settings.Name, tenantConfig);
}
finally
{
Expand Down