private ShellSettings BuildShellSettings(TenantSetUpContext context) { var shellSettings = new ShellSettings() { Name = context.SiteName, Location = !string.IsNullOrEmpty(context.Location) ? context.Location : context.SiteName.ToSafeFileName(), RequestedUrlHost = context.RequestedUrlHost, RequestedUrlPrefix = context.RequestedUrlPrefix, State = context.State, OwnerId = context.OwnerId }; if (string.IsNullOrEmpty(shellSettings.DatabaseProvider)) { var tablePrefix = context.DatabaseTablePrefix; if (!tablePrefix.EndsWith(ShellHelper.TablePrefixSeparator)) { tablePrefix += ShellHelper.TablePrefixSeparator; } shellSettings.DatabaseProvider = context.DatabaseProvider; shellSettings.ConnectionString = context.DatabaseConnectionString; shellSettings.TablePrefix = tablePrefix; } shellSettings.CreatedDate = context.CreatedDate; shellSettings.ModifiedDate = context.ModifiedDate; return(shellSettings); }
public async Task <ICommandResult <TenantSetUpContext> > InstallAsync(TenantSetUpContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } var result = new CommandResult <TenantSetUpContext>(); try { // Validate tenant var shells = _shellSettingsManager.LoadSettings(); if (shells != null) { // Ensure a unique shell name var shell = shells.FirstOrDefault(s => s.Name.Equals(context.SiteName, StringComparison.OrdinalIgnoreCase)); if (shell != null) { return(result.Failed($"A tenant with the name \"{shell.Name}\" already exists! Consider renaming the tenant.")); } // Ensure a unique shell location shell = shells.FirstOrDefault(s => s.Location.Equals(context.SiteName.ToSafeFileName(), StringComparison.OrdinalIgnoreCase)); if (shell != null) { return(result.Failed($"A tenant with the same location \"{shell.Location}\" already exists! Consider renaming the tenant.")); } // Ensure a unique connection string & table prefix shell = shells.FirstOrDefault(s => s.ConnectionString.Equals(context.DatabaseConnectionString, StringComparison.OrdinalIgnoreCase) && s.TablePrefix.Equals(context.DatabaseTablePrefix, StringComparison.OrdinalIgnoreCase)); if (shell != null) { return(result.Failed($"A tenant with the same connection string and table prefix already exists! Tenant name: \"{shell.Name}\".")); } } // Install tenant return(await InstallInternalAsync(context)); } catch (Exception ex) { return(result.Failed(ex.Message)); } }
private Task <ICommandResult <TenantSetUpContext> > UpdateInternalAsync(TenantSetUpContext context) { var result = new CommandResult <TenantSetUpContext>(); var shellSettings = BuildShellSettings(context); shellSettings.ModifiedDate = DateTimeOffset.Now; // Update & recycle shell _platoHost .UpdateShell(shellSettings) .RecycleShell(shellSettings); return(Task.FromResult(result.Success(context))); }
// -------------------------- private async Task <ICommandResult <TenantSetUpContext> > InstallInternalAsync(TenantSetUpContext context) { var result = new CommandResult <TenantSetUpContext>(); var shellSettings = BuildShellSettings(context); using (var shellContext = _shellContextFactory.CreateMinimalShellContext(shellSettings)) { using (var scope = shellContext.ServiceProvider.CreateScope()) { var hasErrors = false; void ReportError(string key, string message) { hasErrors = true; context.Errors[key] = message; } // Invoke set-up event handlers var logger = scope.ServiceProvider.GetRequiredService <ILogger <TenantSetUpService> >(); var setupEventHandlers = scope.ServiceProvider.GetServices <ISetUpEventHandler>(); await setupEventHandlers.InvokeAsync(x => x.SetUp(context, ReportError), logger); // Return early if we encountered any errors if (hasErrors) { return(result.Failed(context.Errors.Select(e => e.Value).ToArray())); } // Activate message broker subscriptions for tenant var subscribers = scope.ServiceProvider.GetServices <IBrokerSubscriber>(); foreach (var subscriber in subscribers) { subscriber.Subscribe(); } // Update tenant email settings var emailSettingsManager = scope.ServiceProvider.GetService <IEmailSettingsManager>(); await emailSettingsManager.SaveAsync(context.EmailSettings); } } // Report any errors if (context.Errors.Count > 0) { return(result.Failed(context.Errors.Select(e => e.Value).ToArray())); } // Set shell defaults shellSettings.CreatedDate = DateTimeOffset.Now; shellSettings.ModifiedDate = DateTimeOffset.Now; shellSettings.State = TenantState.Running; // Update & recycle shell _platoHost .UpdateShell(shellSettings) .RecycleShell(shellSettings); return(result.Success(context)); }
public async Task <ICommandResult <TenantSetUpContext> > UpdateAsync(TenantSetUpContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } var result = new CommandResult <TenantSetUpContext>(); try { // Validate tenant var shells = _shellSettingsManager.LoadSettings(); if (shells != null) { bool connStringExists = false, hostExists = false, prefixExists = false; foreach (var shell in shells) { // Ensure we are checking other shells if (!shell.Name.Equals(context.SiteName, StringComparison.OrdinalIgnoreCase)) { if (shell.ConnectionString.Equals(context.DatabaseConnectionString, StringComparison.OrdinalIgnoreCase) && shell.TablePrefix.Equals(context.DatabaseTablePrefix, StringComparison.OrdinalIgnoreCase)) { connStringExists = true; } if (!string.IsNullOrEmpty(shell.RequestedUrlHost)) { if (shell.RequestedUrlHost.Equals(context.RequestedUrlHost, StringComparison.OrdinalIgnoreCase)) { hostExists = true; } } if (!string.IsNullOrEmpty(shell.RequestedUrlPrefix)) { if (shell.RequestedUrlPrefix.Equals(context.RequestedUrlPrefix, StringComparison.OrdinalIgnoreCase)) { prefixExists = true; } } if (connStringExists) { return(result.Failed($"A tenant with the same connection string and table prefix already exists! Tenant name: \"{shell.Name}\".")); } // If we have a host check host and prefix // Else just check the prefix if (hostExists) { if (hostExists && prefixExists) { return(result.Failed($"A tenant with the same host name and prefix already exists! Tenant name: \"{shell.Name}\".")); } } else { if (prefixExists) { return(result.Failed($"A tenant with the same prefix already exists! Tenant name: \"{shell.Name}\".")); } } } } } // Update tenant return(await UpdateInternalAsync(context)); } catch (Exception ex) { return(result.Failed(ex.Message)); } }
public async Task <IActionResult> SetUpConffirmationPost(SetUpConfirmationViewModel model) { // Ensure default shell, We cannot sign-up from tenants if (!_shellSettings.IsDefaultShell()) { return(Unauthorized()); } // Validate if (model == null) { throw new ArgumentNullException(nameof(model)); } if (string.IsNullOrEmpty(model.SessionId)) { throw new ArgumentOutOfRangeException(nameof(model.SessionId)); } if (string.IsNullOrEmpty(model.UserName)) { throw new ArgumentOutOfRangeException(nameof(model.UserName)); } if (string.IsNullOrEmpty(model.Password)) { throw new ArgumentOutOfRangeException(nameof(model.Password)); } if (!ModelState.IsValid) { return(View(model)); } // Get the sign-up var signUp = await _signUpStore.GetBySessionIdAsync(model.SessionId); // Ensure we found the sign-up if (signUp == null) { return(NotFound()); } // Email must be confirmed if (!signUp.EmailConfirmed) { return(Unauthorized()); } // Set sign-up email address as default sender for tenant emails if (_defaultTenantSettings.SmtpSettings != null) { _defaultTenantSettings.SmtpSettings.DefaultFrom = signUp.Email; } // Create tenant context var setupContext = new TenantSetUpContext() { SiteName = signUp.CompanyName, Location = $"tenant{signUp.Id.ToString()}", DatabaseProvider = "SqlClient", DatabaseConnectionString = _defaultTenantSettings.ConnectionString, DatabaseTablePrefix = $"tenant{signUp.Id.ToString()}", AdminUsername = model.UserName, AdminEmail = signUp.Email, AdminPassword = model.Password, RequestedUrlPrefix = signUp.CompanyNameAlias, OwnerId = signUp.Email, CreatedDate = DateTimeOffset.Now, EmailSettings = new EmailSettings() { SmtpSettings = _defaultTenantSettings.SmtpSettings }, Errors = new Dictionary <string, string>() }; // Attempt to create tenant var result = await _tenantSetUpService.InstallAsync(setupContext); // Report any errors if (!result.Succeeded) { foreach (var error in result.Errors) { ViewData.ModelState.AddModelError(error.Code, error.Description); } return(await SetUp(signUp.SessionId)); } // Redirect to set-up complete return(RedirectToAction(nameof(SetUpComplete), new RouteValueDictionary() { ["sessionId"] = signUp.SessionId })); }
public override async Task <IViewProviderResult> BuildUpdateAsync(ShellSettings settings, IViewProviderContext context) { var model = new EditTenantViewModel(); if (!await context.Updater.TryUpdateModelAsync(model)) { return(await BuildEditAsync(settings, context)); } if (context.Updater.ModelState.IsValid) { // Ensure password if (model.SmtpSettings != null) { if (!string.IsNullOrWhiteSpace(model.SmtpSettings.Password)) { try { model.SmtpSettings.Password = _encrypter.Encrypt(model.SmtpSettings.Password); } catch (Exception e) { if (_logger.IsEnabled(LogLevel.Error)) { _logger.LogError($"There was a problem encrypting the SMTP server password. {e.Message}"); } } } } var setupContext = new TenantSetUpContext() { SiteName = model.SiteName, Location = model.Location, DatabaseProvider = "SqlClient", DatabaseConnectionString = model.ConnectionString, AdminUsername = model.UserName, AdminEmail = model.Email, AdminPassword = model.Password, RequestedUrlHost = model.RequestedUrlHost, RequestedUrlPrefix = model.RequestedUrlPrefix, State = model.State, OwnerId = model.OwnerId, CreatedDate = model.IsNewTenant ? DateTimeOffset.Now : model.CreatedDate, ModifiedDate = model.IsNewTenant ? model.ModifiedDate : DateTimeOffset.Now, EmailSettings = new EmailSettings() { SmtpSettings = model.SmtpSettings }, Errors = new Dictionary <string, string>() }; if (!model.TablePrefixPreset) { setupContext.DatabaseTablePrefix = model.TablePrefix; } // Install or update tenant var result = model.IsNewTenant ? await _tenantSetUpService.InstallAsync(setupContext) : await _tenantSetUpService.UpdateAsync(setupContext); // Report any errors if (!result.Succeeded) { if (_logger.IsEnabled(LogLevel.Information)) { if (model.IsNewTenant) { _logger.LogInformation($"Set-up of tenant '{setupContext.SiteName}' failed with the following errors..."); } else { _logger.LogInformation($"Update of tenant '{setupContext.SiteName}' failed with the following errors..."); } } foreach (var error in result.Errors) { if (_logger.IsEnabled(LogLevel.Information)) { _logger.LogInformation(error.Code + " " + error.Description); } context.Updater.ModelState.AddModelError(error.Code, error.Description); } } } return(await BuildEditAsync(settings, context)); }