Skip to content

Commit 881f06f

Browse files
authored
Merge branch 'main' into gvkries/permissions-8469
2 parents 7f31ddd + 2d49f29 commit 881f06f

File tree

27 files changed

+501
-214
lines changed

27 files changed

+501
-214
lines changed

.all-contributorsrc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3295,6 +3295,15 @@
32953295
"contributions": [
32963296
"code"
32973297
]
3298+
},
3299+
{
3300+
"login": "davidlfox",
3301+
"name": "David L. Fox",
3302+
"avatar_url": "https://avatars.githubusercontent.com/u/5315855?v=4",
3303+
"profile": "https://www.iamdavidfox.com",
3304+
"contributions": [
3305+
"code"
3306+
]
32983307
}
32993308
],
33003309
"skipCi": true,

Directory.Packages.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
<ItemGroup>
99
<PackageVersion Include="AngleSharp" Version="1.2.0" />
10-
<PackageVersion Include="AWSSDK.S3" Version="3.7.411.5" />
10+
<PackageVersion Include="AWSSDK.S3" Version="3.7.412.4" />
1111
<PackageVersion Include="AWSSDK.Extensions.NETCore.Setup" Version="3.7.301" />
1212
<PackageVersion Include="Azure.Communication.Email" Version="1.0.1" />
1313
<PackageVersion Include="Azure.Communication.Sms" Version="1.0.1" />
Lines changed: 22 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
1-
using System.Text;
21
using Microsoft.AspNetCore.Http;
32
using Microsoft.Extensions.DependencyInjection;
4-
using Microsoft.Extensions.Logging;
53
using Microsoft.Extensions.Options;
6-
using OrchardCore.Abstractions.Setup;
74
using OrchardCore.AutoSetup.Extensions;
85
using OrchardCore.AutoSetup.Options;
6+
using OrchardCore.AutoSetup.Services;
97
using OrchardCore.Environment.Shell;
108
using OrchardCore.Locking.Distributed;
11-
using OrchardCore.Setup.Services;
129

1310
namespace OrchardCore.AutoSetup;
1411

@@ -47,11 +44,6 @@ public class AutoSetupMiddleware
4744
/// </summary>
4845
private readonly AutoSetupOptions _options;
4946

50-
/// <summary>
51-
/// The logger.
52-
/// </summary>
53-
private readonly ILogger _logger;
54-
5547
/// <summary>
5648
/// The auto setup lock options.
5749
/// </summary>
@@ -70,25 +62,21 @@ public class AutoSetupMiddleware
7062
/// <param name="shellSettings">The shell settings.</param>
7163
/// <param name="shellSettingsManager">The shell settings manager.</param>
7264
/// <param name="distributedLock">The distributed lock.</param>
73-
/// <param name="options">The auto setup options.</param>
74-
/// <param name="logger">The logger.</param>
65+
/// <param name="options">The auto setup options.</param>
7566
public AutoSetupMiddleware(
7667
RequestDelegate next,
7768
IShellHost shellHost,
7869
ShellSettings shellSettings,
7970
IShellSettingsManager shellSettingsManager,
8071
IDistributedLock distributedLock,
81-
IOptions<AutoSetupOptions> options,
82-
ILogger<AutoSetupMiddleware> logger)
72+
IOptions<AutoSetupOptions> options)
8373
{
8474
_next = next;
8575
_shellHost = shellHost;
8676
_shellSettings = shellSettings;
8777
_shellSettingsManager = shellSettingsManager;
8878
_distributedLock = distributedLock;
8979
_options = options.Value;
90-
_logger = logger;
91-
9280
_lockOptions = _options.LockOptions;
9381
_setupOptions = _options.Tenants.FirstOrDefault(options => _shellSettings.Name == options.ShellName);
9482
}
@@ -124,20 +112,23 @@ public async Task InvokeAsync(HttpContext httpContext)
124112
}
125113

126114
// Check if the tenant was installed by another instance.
127-
using var settings = (await _shellSettingsManager
128-
.LoadSettingsAsync(_shellSettings.Name))
129-
.AsDisposable();
115+
using var settings = await _shellSettingsManager.LoadSettingsAsync(_shellSettings.Name);
130116

131-
if (!settings.IsUninitialized())
117+
if (settings != null)
132118
{
133-
await _shellHost.ReloadShellContextAsync(_shellSettings, eventSource: false);
134-
httpContext.Response.Redirect(pathBase);
135-
136-
return;
119+
settings.AsDisposable();
120+
if (!settings.IsUninitialized())
121+
{
122+
await _shellHost.ReloadShellContextAsync(_shellSettings, eventSource: false);
123+
httpContext.Response.StatusCode = StatusCodes.Status503ServiceUnavailable;
124+
await httpContext.Response.WriteAsync("The requested tenant is not initialized.");
125+
return;
126+
}
137127
}
138128

139-
var setupService = httpContext.RequestServices.GetRequiredService<ISetupService>();
140-
if (await SetupTenantAsync(setupService, _setupOptions, _shellSettings))
129+
var autoSetupService = httpContext.RequestServices.GetRequiredService<IAutoSetupService>();
130+
(var setupContext, var isSuccess) = await autoSetupService.SetupTenantAsync(_setupOptions, _shellSettings);
131+
if (isSuccess)
141132
{
142133
if (_setupOptions.IsDefault)
143134
{
@@ -146,123 +137,22 @@ public async Task InvokeAsync(HttpContext httpContext)
146137
{
147138
if (_setupOptions != setupOptions)
148139
{
149-
await CreateTenantSettingsAsync(setupOptions);
140+
await autoSetupService.CreateTenantSettingsAsync(setupOptions);
150141
}
151142
}
152143
}
153144

154145
httpContext.Response.Redirect(pathBase);
155-
146+
}
147+
else
148+
{
149+
httpContext.Response.StatusCode = StatusCodes.Status503ServiceUnavailable;
150+
await httpContext.Response.WriteAsync($"The AutoSetup failed installing the site.");
156151
return;
157152
}
158153
}
159154
}
160155

161156
await _next.Invoke(httpContext);
162157
}
163-
164-
/// <summary>
165-
/// Sets up a tenant.
166-
/// </summary>
167-
/// <param name="setupService">The setup service.</param>
168-
/// <param name="setupOptions">The tenant setup options.</param>
169-
/// <param name="shellSettings">The tenant shell settings.</param>
170-
/// <returns>
171-
/// Returns <c>true</c> if successfully setup.
172-
/// </returns>
173-
public async Task<bool> SetupTenantAsync(ISetupService setupService, TenantSetupOptions setupOptions, ShellSettings shellSettings)
174-
{
175-
var setupContext = await GetSetupContextAsync(setupOptions, setupService, shellSettings);
176-
177-
_logger.LogInformation("AutoSetup is initializing the site");
178-
179-
await setupService.SetupAsync(setupContext);
180-
181-
if (setupContext.Errors.Count == 0)
182-
{
183-
_logger.LogInformation("AutoSetup successfully provisioned the site '{SiteName}'.", setupOptions.SiteName);
184-
185-
return true;
186-
}
187-
188-
var stringBuilder = new StringBuilder();
189-
foreach (var error in setupContext.Errors)
190-
{
191-
stringBuilder.AppendLine($"{error.Key} : '{error.Value}'");
192-
}
193-
194-
_logger.LogError("AutoSetup failed installing the site '{SiteName}' with errors: {Errors}", setupOptions.SiteName, stringBuilder);
195-
196-
return false;
197-
}
198-
199-
/// <summary>
200-
/// Creates a tenant shell settings.
201-
/// </summary>
202-
/// <param name="setupOptions">The setup options.</param>
203-
/// <returns>The <see cref="ShellSettings"/>.</returns>
204-
public async Task<ShellSettings> CreateTenantSettingsAsync(TenantSetupOptions setupOptions)
205-
{
206-
using var shellSettings = _shellSettingsManager
207-
.CreateDefaultSettings()
208-
.AsUninitialized()
209-
.AsDisposable();
210-
211-
shellSettings.Name = setupOptions.ShellName;
212-
shellSettings.RequestUrlHost = setupOptions.RequestUrlHost;
213-
shellSettings.RequestUrlPrefix = setupOptions.RequestUrlPrefix;
214-
215-
shellSettings["ConnectionString"] = setupOptions.DatabaseConnectionString;
216-
shellSettings["TablePrefix"] = setupOptions.DatabaseTablePrefix;
217-
shellSettings["Schema"] = setupOptions.DatabaseSchema;
218-
shellSettings["DatabaseProvider"] = setupOptions.DatabaseProvider;
219-
shellSettings["Secret"] = Guid.NewGuid().ToString();
220-
shellSettings["RecipeName"] = setupOptions.RecipeName;
221-
shellSettings["FeatureProfile"] = setupOptions.FeatureProfile;
222-
223-
await _shellHost.UpdateShellSettingsAsync(shellSettings);
224-
225-
return shellSettings;
226-
}
227-
228-
/// <summary>
229-
/// Gets a setup context from the configuration.
230-
/// </summary>
231-
/// <param name="options">The tenant setup options.</param>
232-
/// <param name="setupService">The setup service.</param>
233-
/// <param name="shellSettings">The tenant shell settings.</param>
234-
/// <returns> The <see cref="SetupContext"/> used to setup the site.</returns>
235-
private static async Task<SetupContext> GetSetupContextAsync(TenantSetupOptions options, ISetupService setupService, ShellSettings shellSettings)
236-
{
237-
var recipes = await setupService.GetSetupRecipesAsync();
238-
239-
var recipe = recipes.SingleOrDefault(r => r.Name == options.RecipeName);
240-
241-
var setupContext = new SetupContext
242-
{
243-
Recipe = recipe,
244-
ShellSettings = shellSettings,
245-
Errors = new Dictionary<string, string>()
246-
};
247-
248-
if (shellSettings.IsDefaultShell())
249-
{
250-
// The 'Default' shell is first created by the infrastructure,
251-
// so the following 'Autosetup' options need to be passed.
252-
shellSettings.RequestUrlHost = options.RequestUrlHost;
253-
shellSettings.RequestUrlPrefix = options.RequestUrlPrefix;
254-
}
255-
256-
setupContext.Properties[SetupConstants.AdminEmail] = options.AdminEmail;
257-
setupContext.Properties[SetupConstants.AdminPassword] = options.AdminPassword;
258-
setupContext.Properties[SetupConstants.AdminUsername] = options.AdminUsername;
259-
setupContext.Properties[SetupConstants.DatabaseConnectionString] = options.DatabaseConnectionString;
260-
setupContext.Properties[SetupConstants.DatabaseProvider] = options.DatabaseProvider;
261-
setupContext.Properties[SetupConstants.DatabaseTablePrefix] = options.DatabaseTablePrefix;
262-
setupContext.Properties[SetupConstants.DatabaseSchema] = options.DatabaseSchema;
263-
setupContext.Properties[SetupConstants.SiteName] = options.SiteName;
264-
setupContext.Properties[SetupConstants.SiteTimeZone] = options.SiteTimeZone;
265-
266-
return setupContext;
267-
}
268158
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
using System.Text;
2+
using Microsoft.Extensions.Logging;
3+
using OrchardCore.Abstractions.Setup;
4+
using OrchardCore.AutoSetup.Options;
5+
using OrchardCore.Environment.Shell;
6+
using OrchardCore.Setup.Services;
7+
8+
namespace OrchardCore.AutoSetup.Services;
9+
10+
public class AutoSetupService : IAutoSetupService
11+
{
12+
private readonly IShellHost _shellHost;
13+
private readonly IShellSettingsManager _shellSettingsManager;
14+
private readonly ISetupService _setupService;
15+
private readonly ILogger _logger;
16+
17+
public AutoSetupService(
18+
IShellHost shellHost,
19+
IShellSettingsManager shellSettingsManager,
20+
ISetupService setupService,
21+
ILogger<AutoSetupService> logger
22+
)
23+
{
24+
_shellHost = shellHost;
25+
_shellSettingsManager = shellSettingsManager;
26+
_setupService = setupService;
27+
_logger = logger;
28+
}
29+
30+
public async Task<(SetupContext, bool)> SetupTenantAsync(TenantSetupOptions setupOptions, ShellSettings shellSettings)
31+
{
32+
var setupContext = await GetSetupContextAsync(setupOptions, shellSettings);
33+
34+
_logger.LogInformation("The AutoSetup is initializing the site.");
35+
36+
await _setupService.SetupAsync(setupContext);
37+
38+
if (setupContext.Errors.Count == 0)
39+
{
40+
_logger.LogInformation("The AutoSetup successfully provisioned the site '{SiteName}'.", setupOptions.SiteName);
41+
42+
return (setupContext, true);
43+
}
44+
45+
var stringBuilder = new StringBuilder();
46+
foreach (var error in setupContext.Errors)
47+
{
48+
stringBuilder.AppendLine($"{error.Key} : '{error.Value}'");
49+
}
50+
51+
_logger.LogError("The AutoSetup failed installing the site '{SiteName}' with errors: {Errors}.", setupOptions.SiteName, stringBuilder);
52+
53+
return (setupContext, false);
54+
}
55+
56+
public async Task<ShellSettings> CreateTenantSettingsAsync(TenantSetupOptions setupOptions)
57+
{
58+
using var shellSettings = _shellSettingsManager
59+
.CreateDefaultSettings()
60+
.AsUninitialized()
61+
.AsDisposable();
62+
63+
shellSettings.Name = setupOptions.ShellName;
64+
shellSettings.RequestUrlHost = setupOptions.RequestUrlHost;
65+
shellSettings.RequestUrlPrefix = setupOptions.RequestUrlPrefix;
66+
shellSettings["ConnectionString"] = setupOptions.DatabaseConnectionString;
67+
shellSettings["TablePrefix"] = setupOptions.DatabaseTablePrefix;
68+
shellSettings["Schema"] = setupOptions.DatabaseSchema;
69+
shellSettings["DatabaseProvider"] = setupOptions.DatabaseProvider;
70+
shellSettings["Secret"] = Guid.NewGuid().ToString();
71+
shellSettings["RecipeName"] = setupOptions.RecipeName;
72+
shellSettings["FeatureProfile"] = setupOptions.FeatureProfile;
73+
74+
await _shellHost.UpdateShellSettingsAsync(shellSettings);
75+
76+
return shellSettings;
77+
}
78+
79+
public async Task<SetupContext> GetSetupContextAsync(TenantSetupOptions options, ShellSettings shellSettings)
80+
{
81+
var recipe = (await _setupService.GetSetupRecipesAsync())
82+
.SingleOrDefault(r => r.Name == options.RecipeName);
83+
84+
var setupContext = new SetupContext
85+
{
86+
Recipe = recipe,
87+
ShellSettings = shellSettings,
88+
Errors = new Dictionary<string, string>()
89+
};
90+
91+
if (shellSettings.IsDefaultShell())
92+
{
93+
// The 'Default' shell is first created by the infrastructure,
94+
// so the following 'Autosetup' options need to be passed.
95+
shellSettings.RequestUrlHost = options.RequestUrlHost;
96+
shellSettings.RequestUrlPrefix = options.RequestUrlPrefix;
97+
}
98+
99+
setupContext.Properties[SetupConstants.AdminEmail] = options.AdminEmail;
100+
setupContext.Properties[SetupConstants.AdminPassword] = options.AdminPassword;
101+
setupContext.Properties[SetupConstants.AdminUsername] = options.AdminUsername;
102+
setupContext.Properties[SetupConstants.DatabaseConnectionString] = options.DatabaseConnectionString;
103+
setupContext.Properties[SetupConstants.DatabaseProvider] = options.DatabaseProvider;
104+
setupContext.Properties[SetupConstants.DatabaseTablePrefix] = options.DatabaseTablePrefix;
105+
setupContext.Properties[SetupConstants.DatabaseSchema] = options.DatabaseSchema;
106+
setupContext.Properties[SetupConstants.SiteName] = options.SiteName;
107+
setupContext.Properties[SetupConstants.SiteTimeZone] = options.SiteTimeZone;
108+
109+
return setupContext;
110+
}
111+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using OrchardCore.AutoSetup.Options;
2+
using OrchardCore.Environment.Shell;
3+
using OrchardCore.Setup.Services;
4+
5+
namespace OrchardCore.AutoSetup.Services;
6+
7+
public interface IAutoSetupService
8+
{
9+
/// <summary>
10+
/// Creates a tenant shell settings.
11+
/// </summary>
12+
/// <param name="setupOptions">The setup options.</param>
13+
/// <returns>The <see cref="ShellSettings"/>.</returns>
14+
Task<ShellSettings> CreateTenantSettingsAsync(TenantSetupOptions setupOptions);
15+
16+
/// <summary>
17+
/// Gets a setup context from the configuration.
18+
/// </summary>
19+
/// <param name="options">The tenant setup options.</param>
20+
/// <param name="shellSettings">The tenant shell settings.</param>
21+
/// <returns> The <see cref="SetupContext"/> used to setup the site.</returns>
22+
Task<SetupContext> GetSetupContextAsync(TenantSetupOptions options, ShellSettings shellSettings);
23+
24+
/// <summary>
25+
/// Sets up a tenant.
26+
/// </summary>
27+
/// <param name="setupOptions">The tenant setup options.</param>
28+
/// <param name="shellSettings">The tenant shell settings.</param>
29+
/// <returns>
30+
/// Returns <see langword="true" /> if successfully setup.
31+
/// </returns>
32+
Task<(SetupContext, bool)> SetupTenantAsync(TenantSetupOptions setupOptions, ShellSettings shellSettings);
33+
}

0 commit comments

Comments
 (0)