Skip to content

Commit

Permalink
Add Database Schema and options as DefaultTableNameSeparator (#12683)
Browse files Browse the repository at this point in the history
  • Loading branch information
MikeAlhayek authored Jan 4, 2023
1 parent e1c30d6 commit 960e630
Show file tree
Hide file tree
Showing 48 changed files with 853 additions and 505 deletions.
9 changes: 9 additions & 0 deletions src/OrchardCore.Cms.Web/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,16 @@
//"OrchardCore_ContentLocalization_CulturePickerOptions": {
// "CookieLifeTime": 14 // Set the culture picker cookie life time (in days).
//},
// See https://docs.orchardcore.net/en/latest/docs/reference/core/Data/#sqlite.
//"OrchardCore_Data_Sqlite": {
// "UseConnectionPooling": false
//},
// See https://docs.orchardcore.net/en/latest/docs/reference/core/Data/#database-table to configure database table presets used before a given tenant is setup.
//"OrchardCore_Data_TableOptions": {
// "DefaultDocumentTable": "Document", // Document table name, defaults to 'Document'.
// "DefaultTableNameSeparator": "_", // Table name separator, one or multiple '_', "NULL" means no separator, defaults to '_'.
// "DefaultIdentityColumnSize": "Int64" // Identity column size, 'Int32' or 'Int64', defaults to 'Int64'.
//},
// See https://docs.orchardcore.net/en/latest/docs/reference/modules/DataProtection.Azure/#configuration to configure data protection key storage in Azure Blob Storage.
//"OrchardCore_DataProtection_Azure": {
// "ConnectionString": "", // Set to your Azure Storage account connection string.
Expand Down Expand Up @@ -145,6 +152,7 @@
// "DatabaseProvider": "Sqlite",
// "DatabaseConnectionString": "",
// "DatabaseTablePrefix": "",
// "DatabaseSchema": "",
// "RecipeName": "SaaS"
// },
// {
Expand All @@ -157,6 +165,7 @@
// "DatabaseProvider": "Sqlite",
// "DatabaseConnectionString": "",
// "DatabaseTablePrefix": "tenant",
// "DatabaseSchema": "",
// "RecipeName": "Agency",
// "RequestUrlHost": "",
// "RequestUrlPrefix": "tenant"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ public async Task<ShellSettings> CreateTenantSettingsAsync(TenantSetupOptions se

shellSettings["ConnectionString"] = setupOptions.DatabaseConnectionString;
shellSettings["TablePrefix"] = setupOptions.DatabaseTablePrefix;
shellSettings["Schema"] = setupOptions.DatabaseSchema;
shellSettings["DatabaseProvider"] = setupOptions.DatabaseProvider;
shellSettings["Secret"] = Guid.NewGuid().ToString();
shellSettings["RecipeName"] = setupOptions.RecipeName;
Expand Down Expand Up @@ -250,6 +251,7 @@ private static async Task<SetupContext> GetSetupContextAsync(TenantSetupOptions
setupContext.Properties[SetupConstants.DatabaseConnectionString] = options.DatabaseConnectionString;
setupContext.Properties[SetupConstants.DatabaseProvider] = options.DatabaseProvider;
setupContext.Properties[SetupConstants.DatabaseTablePrefix] = options.DatabaseTablePrefix;
setupContext.Properties[SetupConstants.DatabaseSchema] = options.DatabaseSchema;
setupContext.Properties[SetupConstants.SiteName] = options.SiteName;
setupContext.Properties[SetupConstants.SiteTimeZone] = options.SiteTimeZone;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ public class TenantSetupOptions
/// </summary>
public string DatabaseTablePrefix { get; set; }

/// <summary>
/// Gets or sets the database's schema.
/// </summary>
public string DatabaseSchema { get; set; }

/// <summary>
/// Gets or sets the recipe name.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\OrchardCore\OrchardCore.Abstractions\OrchardCore.Abstractions.csproj" />
<ProjectReference Include="..\..\OrchardCore\OrchardCore.Setup.Abstractions\OrchardCore.Setup.Abstractions.csproj" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public async Task<ActionResult> Index(string token)
DatabaseProviders = _databaseProviders,
Recipes = recipes,
RecipeName = defaultRecipe?.Name,
Secret = token
Secret = token,
};

CopyShellSettingsValues(model);
Expand All @@ -80,6 +80,12 @@ public async Task<ActionResult> Index(string token)
model.TablePrefix = _shellSettings["TablePrefix"];
}

if (!String.IsNullOrEmpty(_shellSettings["Schema"]))
{
model.DatabaseConfigurationPreset = true;
model.Schema = _shellSettings["Schema"];
}

return View(model);
}

Expand Down Expand Up @@ -157,12 +163,14 @@ public async Task<ActionResult> IndexPOST(SetupViewModel model)
setupContext.Properties[SetupConstants.DatabaseProvider] = _shellSettings["DatabaseProvider"];
setupContext.Properties[SetupConstants.DatabaseConnectionString] = _shellSettings["ConnectionString"];
setupContext.Properties[SetupConstants.DatabaseTablePrefix] = _shellSettings["TablePrefix"];
setupContext.Properties[SetupConstants.DatabaseSchema] = _shellSettings["Schema"];
}
else
{
setupContext.Properties[SetupConstants.DatabaseProvider] = model.DatabaseProvider;
setupContext.Properties[SetupConstants.DatabaseConnectionString] = model.ConnectionString;
setupContext.Properties[SetupConstants.DatabaseTablePrefix] = model.TablePrefix;
setupContext.Properties[SetupConstants.DatabaseSchema] = model.Schema;
}

var executionId = await _setupService.SetupAsync(setupContext);
Expand Down Expand Up @@ -204,11 +212,6 @@ private void CopyShellSettingsValues(SetupViewModel model)
{
model.DatabaseProvider = model.DatabaseProviders.FirstOrDefault(p => p.IsDefault)?.Value;
}

if (!String.IsNullOrEmpty(_shellSettings["Description"]))
{
model.Description = _shellSettings["Description"];
}
}

private async Task<bool> ShouldProceedWithTokenAsync(string token)
Expand All @@ -228,10 +231,9 @@ private async Task<bool> ShouldProceedWithTokenAsync(string token)

private async Task<bool> IsTokenValid(string token)
{
var result = false;
try
{
var result = false;

var shellScope = await _shellHost.GetScopeAsync(ShellHelper.DefaultShellName);

await shellScope.UsingAsync(scope =>
Expand All @@ -251,15 +253,13 @@ await shellScope.UsingAsync(scope =>
return Task.CompletedTask;
});

return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in decrypting the token");
}

return false;
return result;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public class SetupViewModel

public string TablePrefix { get; set; }

public string Schema { get; set; }

/// <summary>
/// True if the database configuration is preset and can't be changed or displayed on the Setup screen.
/// </summary>
Expand Down
19 changes: 14 additions & 5 deletions src/OrchardCore.Modules/OrchardCore.Setup/Views/Setup/Index.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@
<select asp-for="DatabaseProvider" class="form-select" required>
@foreach (var provider in Model.DatabaseProviders)
{
<option value="@provider.Value" data-connection-string="@provider.HasConnectionString" data-table-prefix="@provider.HasTablePrefix" data-connection-string-sample="@T["The connection string to your database instance. e.g., {0}", provider.SampleConnectionString]">@provider.Name</option>
<option value="@provider.Value" data-connection-string="@provider.HasConnectionString" data-table-prefix="@provider.HasTablePrefix" data-connection-string-sample="@T["The connection string to your database instance, e.g. {0}.", provider.SampleConnectionString]">@provider.Name</option>
}
</select>
<span asp-validation-for="DatabaseProvider" class="text-danger"></span>
Expand All @@ -194,6 +194,15 @@
<span id="connectionStringHint" class="text-muted form-text small"></span>
</div>
</div>

<div class="row row-cols-1 row-cols-md-2">
<div class="mb-3 col tablePrefix">
<label asp-for="Schema">@T["Table Schema"]</label>
<input asp-for="Schema" class="form-control" />
<span asp-validation-for="Schema" class="text-danger"></span>
<div class="text-muted form-text small">@T["When left blank, the default value on the server will be used."] @T["For example, '{0}' for SQL Server.", "dbo"]</div>
</div>
</div>
}
<fieldset>
<legend>@T["Super User"]</legend>
Expand Down Expand Up @@ -240,7 +249,7 @@
</form>
<script src="~/OrchardCore.Setup/Scripts/setup.min.js"></script>
<script>
$(function() {
$(function () {
$('#Password').strength({
minLength: @(options.Password.RequiredLength),
upperCase: @(options.Password.RequireUppercase ? "true" : "false"),
Expand All @@ -257,18 +266,18 @@
toggleConnectionString = document.querySelector('#toggleConnectionString');
if (toggleConnectionString) {
toggleConnectionString.addEventListener('click', function(e) {
toggleConnectionString.addEventListener('click', function (e) {
togglePasswordVisibility(document.querySelector('#ConnectionString'), document.querySelector('#toggleConnectionString'))
});
}
togglePassword = document.querySelector('#togglePassword');
togglePassword.addEventListener('click', function(e) {
togglePassword.addEventListener('click', function (e) {
togglePasswordVisibility(document.querySelector('#Password'), document.querySelector('#togglePassword'))
});
togglePasswordConfirmation = document.querySelector('#togglePasswordConfirmation');
togglePasswordConfirmation.addEventListener('click', function(e) {
togglePasswordConfirmation.addEventListener('click', function (e) {
togglePasswordVisibility(document.querySelector('#PasswordConfirmation'), document.querySelector('#togglePasswordConfirmation'))
});
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,28 +281,32 @@ public async Task<IActionResult> Create()
return Forbid();
}


var recipeCollections = await Task.WhenAll(_recipeHarvesters.Select(x => x.HarvestRecipesAsync()));
var recipes = recipeCollections.SelectMany(x => x).Where(x => x.IsSetupRecipe).OrderBy(r => r.DisplayName).ToArray();

// Creates a default shell settings based on the configuration.
var shellSettings = _shellSettingsManager.CreateDefaultSettings();

var currentFeatureProfile = shellSettings["FeatureProfile"];

var featureProfiles = await GetFeatureProfilesAsync(currentFeatureProfile);

var model = new EditTenantViewModel
{
Recipes = recipes,
RequestUrlHost = shellSettings.RequestUrlHost,
RequestUrlPrefix = shellSettings.RequestUrlPrefix,
TablePrefix = shellSettings["TablePrefix"],
RecipeName = shellSettings["RecipeName"],
DatabaseProvider = shellSettings["DatabaseProvider"],
ConnectionString = shellSettings["ConnectionString"],
TablePrefix = shellSettings["TablePrefix"],
Schema = shellSettings["Schema"],
FeatureProfile = currentFeatureProfile,
FeatureProfiles = featureProfiles
FeatureProfiles = featureProfiles,
};
SetConfigurationShellValues(model);

model.DatabaseConfigurationPreset =
!String.IsNullOrEmpty(model.ConnectionString) ||
!String.IsNullOrEmpty(model.DatabaseProvider);

model.Recipes = recipes;

Expand Down Expand Up @@ -337,11 +341,11 @@ public async Task<IActionResult> Create(EditTenantViewModel model)
shellSettings.RequestUrlPrefix = model.RequestUrlPrefix;
shellSettings.State = TenantState.Uninitialized;

SetConfigurationShellValues(model);
shellSettings["Category"] = model.Category;
shellSettings["Description"] = model.Description;
shellSettings["ConnectionString"] = model.ConnectionString;
shellSettings["TablePrefix"] = model.TablePrefix;
shellSettings["Schema"] = model.Schema;
shellSettings["DatabaseProvider"] = model.DatabaseProvider;
shellSettings["Secret"] = Guid.NewGuid().ToString();
shellSettings["RecipeName"] = model.RecipeName;
Expand Down Expand Up @@ -390,7 +394,7 @@ public async Task<IActionResult> Edit(string id)
RequestUrlHost = shellSettings.RequestUrlHost,
RequestUrlPrefix = shellSettings.RequestUrlPrefix,
FeatureProfile = currentFeatureProfile,
FeatureProfiles = featureProfiles
FeatureProfiles = featureProfiles,
};

// The user can change the 'preset' database information only if the
Expand All @@ -403,10 +407,10 @@ public async Task<IActionResult> Edit(string id)

model.DatabaseProvider = shellSettings["DatabaseProvider"];
model.TablePrefix = shellSettings["TablePrefix"];
model.Schema = shellSettings["Schema"];
model.ConnectionString = shellSettings["ConnectionString"];
model.RecipeName = shellSettings["RecipeName"];
model.CanEditDatabasePresets = true;
SetConfigurationShellValues(model);
}

return View(model);
Expand Down Expand Up @@ -447,9 +451,9 @@ public async Task<IActionResult> Edit(EditTenantViewModel model)
// tenant has not been initialized yet
if (shellSettings.State == TenantState.Uninitialized)
{
SetConfigurationShellValues(model);
shellSettings["DatabaseProvider"] = model.DatabaseProvider;
shellSettings["TablePrefix"] = model.TablePrefix;
shellSettings["Schema"] = model.Schema;
shellSettings["ConnectionString"] = model.ConnectionString;
shellSettings["RecipeName"] = model.RecipeName;
shellSettings["Secret"] = Guid.NewGuid().ToString();
Expand All @@ -460,24 +464,25 @@ public async Task<IActionResult> Edit(EditTenantViewModel model)
return RedirectToAction(nameof(Index));
}

// If we got this far, something failed. Reinitialize the model and re-display form.

// The user can change the 'preset' database information only if the
// tenant has not been initialized yet
if (shellSettings.State == TenantState.Uninitialized)
{
model.DatabaseProvider = shellSettings["DatabaseProvider"];
model.TablePrefix = shellSettings["TablePrefix"];
model.Schema = shellSettings["Schema"];
model.ConnectionString = shellSettings["ConnectionString"];
model.RecipeName = shellSettings["RecipeName"];
model.CanEditDatabasePresets = true;
SetConfigurationShellValues(model);
}

var recipeCollections = await Task.WhenAll(_recipeHarvesters.Select(x => x.HarvestRecipesAsync()));
var recipes = recipeCollections.SelectMany(x => x).Where(x => x.IsSetupRecipe).OrderBy(r => r.DisplayName).ToArray();
model.Recipes = recipes;
model.FeatureProfiles = await GetFeatureProfilesAsync(model.FeatureProfile);

// If we got this far, something failed, redisplay form
return View(model);
}

Expand Down Expand Up @@ -575,25 +580,6 @@ public async Task<IActionResult> Reload(string id)
return Redirect(redirectUrl);
}

private void SetConfigurationShellValues(EditTenantViewModel model)
{
var shellSettings = _shellSettingsManager.CreateDefaultSettings();
var configurationShellConnectionString = shellSettings["ConnectionString"];
var configurationDatabaseProvider = shellSettings["DatabaseProvider"];

model.DatabaseConfigurationPreset = !string.IsNullOrEmpty(configurationShellConnectionString) || !string.IsNullOrEmpty(configurationDatabaseProvider);

if (!string.IsNullOrEmpty(configurationShellConnectionString))
{
model.ConnectionString = configurationShellConnectionString;
}

if (!string.IsNullOrEmpty(configurationDatabaseProvider))
{
model.DatabaseProvider = configurationDatabaseProvider;
}
}

private async Task<List<SelectListItem>> GetFeatureProfilesAsync(string currentFeatureProfile)
{
var featureProfiles = (await _featureProfilesService.GetFeatureProfilesAsync())
Expand All @@ -608,9 +594,9 @@ private async Task<List<SelectListItem>> GetFeatureProfilesAsync(string currentF
return featureProfiles;
}

private async Task ValidateViewModelAsync(EditTenantViewModel model, bool newTenant)
private async Task ValidateViewModelAsync(EditTenantViewModel model, bool isNewTenant)
{
model.IsNewTenant = newTenant;
model.IsNewTenant = isNewTenant;

ModelState.AddModelErrors(await _tenantValidator.ValidateAsync(model));
}
Expand Down
Loading

0 comments on commit 960e630

Please sign in to comment.