diff --git a/Oqtane.Client/Installer/Installer.razor b/Oqtane.Client/Installer/Installer.razor index 4ee19850..80d91d65 100644 --- a/Oqtane.Client/Installer/Installer.razor +++ b/Oqtane.Client/Installer/Installer.razor @@ -1,11 +1,10 @@ @namespace Oqtane.Installer @using Oqtane.Interfaces -@using Oqtane.Installer.Controls - @inject NavigationManager NavigationManager @inject IInstallationService InstallationService @inject ISiteService SiteService @inject IUserService UserService +@inject IDatabaseService DatabaseService @inject IJSRuntime JSRuntime @inject IStringLocalizer Localizer @@ -22,25 +21,28 @@

@Localizer["Database Configuration"]


- - - - - @{ - if (_databaseConfigType != null) - { - @DatabaseConfigComponent; + + + + + @{ + if (_databaseConfigType != null) + { + @DatabaseConfigComponent; + } } - }
- - - -
+ + + +
@@ -95,7 +97,7 @@ @code { - private IList _databases; + private List _databases; private string _databaseName = "LocalDB"; private Type _databaseConfigType; private object _databaseConfig; @@ -108,44 +110,9 @@ private string _message = string.Empty; private string _loadingDisplay = "display: none;"; - protected override void OnInitialized() + protected override async Task OnInitializedAsync() { - base.OnInitialized(); - - _databases = new List - { - new() - { - Name = "LocalDB", - FriendlyName = "Local Database", - Type = "Oqtane.Installer.Controls.LocalDBConfig, Oqtane.Client" - }, - new() - { - Name = "SqlServer", - FriendlyName = "SQL Server", - Type = "Oqtane.Installer.Controls.SqlServerConfig, Oqtane.Client" - }, - new() - { - Name = "Sqlite", - FriendlyName = "Sqlite", - Type = "Oqtane.Installer.Controls.SqliteConfig, Oqtane.Client" - }, - new() - { - Name = "MySQL", - FriendlyName = "MySQL", - Type = "Oqtane.Installer.Controls.MySQLConfig, Oqtane.Client" - }, - new() - { - Name = "PostgreSQL", - FriendlyName = "PostgreSQL", - Type = "Oqtane.Installer.Controls.PostgreSQLConfig, Oqtane.Client" - } - }; - + _databases = await DatabaseService.GetDatabasesAsync(); LoadDatabaseConfigComponent(); } @@ -157,7 +124,7 @@ LoadDatabaseConfigComponent(); } - catch (Exception exception) + catch { _message = Localizer["Error loading Database Configuration Control"]; } diff --git a/Oqtane.Client/Modules/Admin/Languages/Add.razor b/Oqtane.Client/Modules/Admin/Languages/Add.razor index 59115679..aecb372c 100644 --- a/Oqtane.Client/Modules/Admin/Languages/Add.razor +++ b/Oqtane.Client/Modules/Admin/Languages/Add.razor @@ -5,6 +5,7 @@ @inject NavigationManager NavigationManager @inject ILocalizationService LocalizationService @inject ILanguageService LanguageService +@inject IPackageService PackageService @inject IStringLocalizer Localizer @if (_supportedCultures == null) @@ -13,57 +14,114 @@ } else { - @if (_supportedCultures?.Count() > 1) - { - - - - - - - - - -
- - - -
- - - -
- - } - @Localizer["Cancel"] + + + @if (_availableCultures.Count() == 0) + { + + } + else + { + + + + + + + + + +
+ + + +
+ + + +
+ + } + @Localizer["Cancel"] +
+ + @if (_packages != null && _packages.Count > 0) + { + + +
+ @Localizer["Name"] + @Localizer["Version"] + +
+ + @context.Name + @context.Version + + + + +
+ + @Localizer["Cancel"] + } + else + { + + } +
+ + + + + + +
+ + + +
+ + @Localizer["Cancel"] +
+
} @code { private string _code = string.Empty; private string _isDefault = "False"; + private string _message; + private IEnumerable _supportedCultures; + private IEnumerable _availableCultures; + private List _packages; public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin; - private IEnumerable _supportedCultures; - protected override async Task OnParametersSetAsync() { + var languages = await LanguageService.GetLanguagesAsync(PageState.Site.SiteId); + var languagesCodes = languages.Select(l => l.Code).ToList(); + _supportedCultures = await LocalizationService.GetCulturesAsync(); - if (_supportedCultures.Count() <= 1) + _availableCultures = _supportedCultures + .Where(c => !c.Name.Equals(Constants.DefaultCulture) && !languagesCodes.Contains(c.Name)); + _packages = await PackageService.GetPackagesAsync("language"); + + if (_supportedCultures.Count() == 1) { - AddModuleMessage(Localizer["The Only Supported Culture That Has Been Defined Is English"], MessageType.Warning); + _message = Localizer["The Only Installed Language Is English"]; } - else + else if (_availableCultures.Count() == 0) { - _supportedCultures = _supportedCultures.Where(c => !c.Name.Equals(Constants.DefaultCulture)); + _message = Localizer["All The Installed Languages Have Been Added."]; } } @@ -97,6 +155,35 @@ else } } + private async Task InstallLanguages() + { + try + { + await PackageService.InstallPackagesAsync(); + AddModuleMessage(Localizer["Language Packages Installed Successfully. You Must Restart Your Application To Apply These Changes.", NavigateUrl("admin/system")], MessageType.Success); + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Installing Language Package"); + } + } + + private async Task DownloadLanguage(string packageid, string version) + { + try + { + await PackageService.DownloadPackageAsync(packageid, version, "Packages"); + await logger.LogInformation("Language Paclage {Name} {Version} Downloaded Successfully", packageid, version); + AddModuleMessage(Localizer["Language Package Downloaded Successfully. Click Install To Complete Installation."], MessageType.Success); + StateHasChanged(); + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Downloading Language Package {Name} {Version}", packageid, version); + AddModuleMessage(Localizer["Error Downloading Language Package"], MessageType.Error); + } + } + private async Task SetCultureAsync(string culture) { if (culture != CultureInfo.CurrentUICulture.Name) diff --git a/Oqtane.Client/Modules/Admin/Languages/Index.razor b/Oqtane.Client/Modules/Admin/Languages/Index.razor index 748c875b..eef0c6af 100644 --- a/Oqtane.Client/Modules/Admin/Languages/Index.razor +++ b/Oqtane.Client/Modules/Admin/Languages/Index.razor @@ -1,6 +1,8 @@ @namespace Oqtane.Modules.Admin.Languages @inherits ModuleBase @inject ILanguageService LanguageService +@inject ILocalizationService LocalizationService +@inject IPackageService PackageService @inject IStringLocalizer Localizer @if (_languages == null) @@ -17,24 +19,43 @@ else @Localizer["Name"] @Localizer["Code"] @Localizer["Default?"] +   - + @context.Name @context.Code + + @if (UpgradeAvailable(context.Code)) + { + + } + } @code { private List _languages; + private List _packages; public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin; protected override async Task OnParametersSetAsync() { _languages = await LanguageService.GetLanguagesAsync(PageState.Site.SiteId); + + var cultures = await LocalizationService.GetCulturesAsync(); + var culture = cultures.First(c => c.Name.Equals(Constants.DefaultCulture)); + + // Adds English as default language + _languages.Insert(0, new Language { Name = culture.DisplayName, Code = culture.Name, IsDefault = !_languages.Any(l => l.IsDefault) }); + + if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) + { + _packages = await PackageService.GetPackagesAsync("language"); + } } private async Task DeleteLanguage(Language language) @@ -53,4 +74,38 @@ else AddModuleMessage(Localizer["Error Deleting Language"], MessageType.Error); } } + + private bool UpgradeAvailable(string code) + { + var upgradeavailable = false; + if (_packages != null) + { + var package = _packages.Where(item => item.PackageId == (Constants.PackageId + ".Client." + code)).FirstOrDefault(); + if (package != null) + { + upgradeavailable = (Version.Parse(package.Version).CompareTo(Version.Parse(Constants.Version)) > 0); + } + + } + return upgradeavailable; + } + + private async Task DownloadLanguage(string code) + { + try + { + if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) + { + await PackageService.DownloadPackageAsync(Constants.PackageId + ".Client." + code, Constants.Version, "Packages"); + await logger.LogInformation("Language Package Downloaded {Code} {Version}", code, Constants.Version); + await PackageService.InstallPackagesAsync(); + AddModuleMessage(Localizer["Language Package Installed Successfully. You Must Restart Your Application To Apply These Changes.", NavigateUrl("admin/system")], MessageType.Success); + } + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Downloading Language Package {Code} {Version} {Error}", code, Constants.Version, ex.Message); + AddModuleMessage(Localizer["Error Downloading Language Package"], MessageType.Error); + } + } } diff --git a/Oqtane.Client/Modules/Admin/Login/Index.razor b/Oqtane.Client/Modules/Admin/Login/Index.razor index 86ec7b0a..4ef83823 100644 --- a/Oqtane.Client/Modules/Admin/Login/Index.razor +++ b/Oqtane.Client/Modules/Admin/Login/Index.razor @@ -115,7 +115,9 @@ // complete the login on the server so that the cookies are set correctly on SignalR string antiforgerytoken = await interop.GetElementByName("__RequestVerificationToken"); var fields = new { __RequestVerificationToken = antiforgerytoken, username = _username, password = _password, remember = _remember, returnurl = _returnUrl }; - await interop.SubmitForm($"/{PageState.Alias.AliasId}/pages/login/", fields); + string url = "/pages/login/"; + if (!string.IsNullOrEmpty(PageState.Alias.Path)) url = "/" + PageState.Alias.Path + url; + await interop.SubmitForm(url, fields); } else { diff --git a/Oqtane.Client/Modules/Admin/Modules/Settings.razor b/Oqtane.Client/Modules/Admin/Modules/Settings.razor index f6e44eeb..5d75d71b 100644 --- a/Oqtane.Client/Modules/Admin/Modules/Settings.razor +++ b/Oqtane.Client/Modules/Admin/Modules/Settings.razor @@ -167,46 +167,53 @@ private async Task SaveModule() { - var pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId); - pagemodule.PageId = int.Parse(_pageId); - pagemodule.Title = _title; - pagemodule.ContainerType = (_containerType != "-") ? _containerType : string.Empty; - if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Page.DefaultContainerType) + if (!string.IsNullOrEmpty(_title)) { - pagemodule.ContainerType = string.Empty; - } - if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Site.DefaultContainerType) - { - pagemodule.ContainerType = string.Empty; - } - await PageModuleService.UpdatePageModuleAsync(pagemodule); - await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane); - - var module = ModuleState; - module.AllPages = bool.Parse(_allPages); - module.Permissions = _permissionGrid.GetPermissions(); - await ModuleService.UpdateModuleAsync(module); - - if (_moduleSettingsType != null) - { - if (_moduleSettings is ISettingsControl moduleSettingsControl) + var pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId); + pagemodule.PageId = int.Parse(_pageId); + pagemodule.Title = _title; + pagemodule.ContainerType = (_containerType != "-") ? _containerType : string.Empty; + if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Page.DefaultContainerType) { - // module settings updated using explicit interface - await moduleSettingsControl.UpdateSettings(); + pagemodule.ContainerType = string.Empty; } - else + if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Site.DefaultContainerType) { - // legacy support - module settings updated by convention ( ie. by calling a public method named "UpdateSettings" in settings component ) - _moduleSettings?.GetType().GetMethod("UpdateSettings")?.Invoke(_moduleSettings, null); + pagemodule.ContainerType = string.Empty; } - } + await PageModuleService.UpdatePageModuleAsync(pagemodule); + await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane); - if (_containerSettingsType != null && _containerSettings is ISettingsControl containerSettingsControl) + var module = ModuleState; + module.AllPages = bool.Parse(_allPages); + module.Permissions = _permissionGrid.GetPermissions(); + await ModuleService.UpdateModuleAsync(module); + + if (_moduleSettingsType != null) + { + if (_moduleSettings is ISettingsControl moduleSettingsControl) + { + // module settings updated using explicit interface + await moduleSettingsControl.UpdateSettings(); + } + else + { + // legacy support - module settings updated by convention ( ie. by calling a public method named "UpdateSettings" in settings component ) + _moduleSettings?.GetType().GetMethod("UpdateSettings")?.Invoke(_moduleSettings, null); + } + } + + if (_containerSettingsType != null && _containerSettings is ISettingsControl containerSettingsControl) + { + await containerSettingsControl.UpdateSettings(); + } + + NavigationManager.NavigateTo(NavigateUrl()); + } + else { - await containerSettingsControl.UpdateSettings(); + AddModuleMessage(Localizer["You Must Provide A Title For The Module"], MessageType.Warning); } - - NavigationManager.NavigateTo(NavigateUrl()); } } diff --git a/Oqtane.Client/Modules/Admin/Site/Index.razor b/Oqtane.Client/Modules/Admin/Site/Index.razor index 0ce94620..6146ca60 100644 --- a/Oqtane.Client/Modules/Admin/Site/Index.razor +++ b/Oqtane.Client/Modules/Admin/Site/Index.razor @@ -30,7 +30,7 @@ - + @@ -60,67 +60,67 @@
- - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - -
- - - -
- - - -
- - - -
+ + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ + + +
+ + + +
+ + + +
@@ -218,6 +218,7 @@
+

@@ -276,7 +277,7 @@ _tenant = _tenantList.Find(item => item.TenantId == site.TenantId).Name; foreach (Alias alias in _aliasList.Where(item => item.SiteId == site.SiteId && item.TenantId == site.TenantId).ToList()) { - _urls += alias.Name + "\n"; + _urls += alias.Name + ","; } if (site.LogoFileId != null) { @@ -424,7 +425,6 @@ site = await SiteService.UpdateSiteAsync(site); - _urls = _urls.Replace("\n", ","); var names = _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (Alias alias in _aliasList.Where(item => item.SiteId == site.SiteId && item.TenantId == site.TenantId).ToList()) { @@ -476,6 +476,36 @@ } } + private async Task DeleteSite() + { + try + { + var sites = await SiteService.GetSitesAsync(); + if (sites.Count > 1) + { + await SiteService.DeleteSiteAsync(PageState.Site.SiteId); + await logger.LogInformation("Site Deleted {SiteId}", PageState.Site.SiteId); + + var aliases = await AliasService.GetAliasesAsync(); + foreach (Alias a in aliases.Where(item => item.SiteId == PageState.Site.SiteId)) + { + await AliasService.DeleteAliasAsync(a.AliasId); + } + + NavigationManager.NavigateTo(NavigateUrl("admin/sites")); + } + else + { + AddModuleMessage(Localizer["You Are Not Authorized To Delete The Site"], MessageType.Warning); + } + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Deleting Site {SiteId} {Error}", PageState.Site.SiteId, ex.Message); + AddModuleMessage(Localizer["Error Deleting Site"], MessageType.Error); + } + } + private async Task SendEmail() { if (_smtphost != "" && _smtpport != "" && _smtpsender != "") diff --git a/Oqtane.Client/Modules/Admin/Sites/Add.razor b/Oqtane.Client/Modules/Admin/Sites/Add.razor index 4d49474f..c1b7cc1e 100644 --- a/Oqtane.Client/Modules/Admin/Sites/Add.razor +++ b/Oqtane.Client/Modules/Admin/Sites/Add.razor @@ -9,6 +9,7 @@ @inject ISiteTemplateService SiteTemplateService @inject IUserService UserService @inject IInstallationService InstallationService +@inject IDatabaseService DatabaseService @inject IStringLocalizer Localizer @inject IEnumerable Databases @@ -18,151 +19,151 @@ } else { -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - @if (_tenantid == "+") - { +
- - - -
- - - -
- - - -
- - - -
- - - -
- - - -
- - - -
- + - if (_databaseConfigType != null) + + + + + + + + + + + + + + + + + @if (_tenantid == "+") { - @DatabaseConfigComponent; + + + + + + + + + + + + if (_databaseConfigType != null) + { + @DatabaseConfigComponent; + } + + + + + + + + } - - - - - - - - - } -
-
+
+ + +
- + - +
- + - + + @foreach (var theme in _themes) { - + }
+ + + +
+ + + +
+ + + +
+ + + +
+
+
+ + + +
+ + + +
+ + + +
+ + + +
- - - -
- - - -
+ @Localizer["Cancel"] } @code { - private IList _databases; + private List _databases; private string _databaseName = "LocalDB"; private Type _databaseConfigType; private object _databaseConfig; @@ -177,7 +178,7 @@ else private string _tenantid = "-"; private string _tenantName = string.Empty; - + private string _hostUserName = UserNames.Host; private string _hostpassword = string.Empty; @@ -197,44 +198,10 @@ else _themeList = await ThemeService.GetThemesAsync(); _themes = ThemeService.GetThemeControls(_themeList); _siteTemplates = await SiteTemplateService.GetSiteTemplatesAsync(); - - _databases = new List - { - new() - { - Name = "LocalDB", - FriendlyName = "Local Database", - Type = "Oqtane.Installer.Controls.LocalDBConfig, Oqtane.Client" - }, - new() - { - Name = "SqlServer", - FriendlyName = "SQL Server", - Type = "Oqtane.Installer.Controls.SqlServerConfig, Oqtane.Client" - }, - new() - { - Name = "Sqlite", - FriendlyName = "Sqlite", - Type = "Oqtane.Installer.Controls.SqliteConfig, Oqtane.Client" - }, - new() - { - Name = "MySQL", - FriendlyName = "MySQL", - Type = "Oqtane.Installer.Controls.MySQLConfig, Oqtane.Client" - }, - new() - { - Name = "PostgreSQL", - FriendlyName = "PostgreSQL", - Type = "Oqtane.Installer.Controls.PostGreSQLConfig, Oqtane.Client" - } - }; - + _databases = await DatabaseService.GetDatabasesAsync(); LoadDatabaseConfigComponent(); } - + private void DatabaseChanged(ChangeEventArgs eventArgs) { try @@ -243,7 +210,7 @@ else LoadDatabaseConfigComponent(); } - catch (Exception exception) + catch { AddModuleMessage(Localizer["Error loading Database Configuration Control"], MessageType.Error); } @@ -365,15 +332,15 @@ else if (tenant != null) { config.TenantName = tenant.Name; - config.ConnectionString= tenant.DBConnectionString; + config.ConnectionString = tenant.DBConnectionString; config.IsNewTenant = false; } } - if (!string.IsNullOrEmpty(config.TenantName)) + if (!string.IsNullOrEmpty(config.TenantName)) { config.SiteName = _name; - config.Aliases = _urls.Replace("\n", ","); + config.Aliases = _urls; config.DefaultTheme = _themetype; config.DefaultContainer = _containertype; config.DefaultAdminContainer = _admincontainertype; diff --git a/Oqtane.Client/Modules/Admin/Sites/Edit.razor b/Oqtane.Client/Modules/Admin/Sites/Edit.razor deleted file mode 100644 index ca589019..00000000 --- a/Oqtane.Client/Modules/Admin/Sites/Edit.razor +++ /dev/null @@ -1,283 +0,0 @@ -@namespace Oqtane.Modules.Admin.Sites -@inherits ModuleBase -@inject NavigationManager NavigationManager -@inject ISiteService SiteService -@inject ITenantService TenantService -@inject IAliasService AliasService -@inject IThemeService ThemeService -@inject IStringLocalizer Localizer - -@if (_initialized) -{ - - - - - - - - - -
- - - -
- - - -
-
- - @Localizer["Cancel"] -
-
- -} - -@code { - private bool _initialized = false; - private List _themeList; - private List _themes = new List(); - private List _containers = new List(); - private Alias _alias; - private string _name = string.Empty; - private List _aliasList; - private string _urls = string.Empty; - private string _themetype; - private string _containertype = "-"; - private string _admincontainertype = "-"; - private string _createdby; - private DateTime _createdon; - private string _modifiedby; - private DateTime _modifiedon; - private string _deletedby; - private DateTime? _deletedon; - private string _isdeleted; - private string _tenant = string.Empty; - private string _connectionstring = string.Empty; - - public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host; - - protected override async Task OnInitializedAsync() - { - try - { - _themeList = await ThemeService.GetThemesAsync(); - _aliasList = await AliasService.GetAliasesAsync(); - - _alias = _aliasList.Find(item => item.AliasId == Int32.Parse(PageState.QueryString["id"])); - SiteService.SetAlias(_alias); - var site = await SiteService.GetSiteAsync(_alias.SiteId); - if (site != null) - { - _name = site.Name; - - foreach (Alias alias in _aliasList.Where(item => item.SiteId == site.SiteId && item.TenantId == site.TenantId).ToList()) - { - _urls += alias.Name + "\n"; - } - - _themes = ThemeService.GetThemeControls(_themeList); - _themetype = site.DefaultThemeType; - _containers = ThemeService.GetContainerControls(_themeList, _themetype); - _containertype = site.DefaultContainerType; - _admincontainertype = site.AdminContainerType; - _createdby = site.CreatedBy; - _createdon = site.CreatedOn; - _modifiedby = site.ModifiedBy; - _modifiedon = site.ModifiedOn; - _deletedby = site.DeletedBy; - _deletedon = site.DeletedOn; - _isdeleted = site.IsDeleted.ToString(); - - List tenants = await TenantService.GetTenantsAsync(); - Tenant tenant = tenants.Find(item => item.TenantId == site.TenantId); - if (tenant != null) - { - _tenant = tenant.Name; - _connectionstring = tenant.DBConnectionString; - } - - _initialized = true; - } - } - catch (Exception ex) - { - await Log(_alias, LogLevel.Error, string.Empty, ex, "Error Loading Site {SiteId} {Error}", _alias.SiteId, ex.Message); - AddModuleMessage(ex.Message, MessageType.Error); - } - } - - private async void ThemeChanged(ChangeEventArgs e) - { - try - { - _themetype = (string)e.Value; - if (_themetype != "-") - { - _containers = ThemeService.GetContainerControls(_themeList, _themetype); - } - else - { - _containers = new List(); - } - _containertype = "-"; - _admincontainertype = ""; - StateHasChanged(); - } - catch (Exception ex) - { - await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", _themetype, ex.Message); - AddModuleMessage(Localizer["Error Loading Pane Layouts For Theme"], MessageType.Error); - } - } - - private async Task SaveSite() - { - try - { - if (_name != string.Empty && _urls != string.Empty && _themetype != "-" && _containertype != "-") - { - var unique = true; - foreach (string name in _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) - { - if (_aliasList.Exists(item => item.Name == name && item.SiteId != _alias.SiteId && item.TenantId != _alias.TenantId)) - { - unique = false; - } - } - - if (unique) - { - SiteService.SetAlias(_alias); - var site = await SiteService.GetSiteAsync(_alias.SiteId); - if (site != null) - { - site.Name = _name; - site.LogoFileId = null; - site.DefaultThemeType = _themetype; - site.DefaultContainerType = _containertype; - site.AdminContainerType = _admincontainertype; - site.IsDeleted = (_isdeleted == null || Boolean.Parse(_isdeleted)); - - site = await SiteService.UpdateSiteAsync(site); - - _urls = _urls.Replace("\n", ","); - var names = _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - - foreach (Alias alias in _aliasList.Where(item => item.SiteId == site.SiteId && item.TenantId == site.TenantId).ToList()) - { - if (!names.Contains(alias.Name)) - { - await AliasService.DeleteAliasAsync(alias.AliasId); - } - } - - foreach (string name in names) - { - if (!_aliasList.Exists(item => item.Name == name)) - { - Alias alias = new Alias - { - Name = name, - TenantId = site.TenantId, - SiteId = site.SiteId - }; - await AliasService.AddAliasAsync(alias); - } - } - - await Log(_alias, LogLevel.Information, PermissionNames.Edit, null, "Site Saved {Site}", site); - - NavigationManager.NavigateTo(NavigateUrl()); - } - } - else - { - AddModuleMessage(Localizer["An Alias Specified Has Already Been Used For Another Site"], MessageType.Warning); - } - } - else - { - AddModuleMessage(Localizer["You Must Provide A Site Name, Alias, And Default Theme/Container"], MessageType.Warning); - } - } - catch (Exception ex) - { - await Log(_alias, LogLevel.Error, string.Empty, ex, "Error Saving Site {SiteId} {Error}", _alias.SiteId, ex.Message); - AddModuleMessage(Localizer["Error Saving Site"], MessageType.Error); - } - } -} diff --git a/Oqtane.Client/Modules/Admin/Sites/Index.razor b/Oqtane.Client/Modules/Admin/Sites/Index.razor index 9d028e1d..f0927b1a 100644 --- a/Oqtane.Client/Modules/Admin/Sites/Index.razor +++ b/Oqtane.Client/Modules/Admin/Sites/Index.razor @@ -15,13 +15,11 @@ else
-     @Localizer["Name"]
- - + @Localizer["Edit"] @context.Name
@@ -48,34 +46,4 @@ else } } } - - private async Task DeleteSite(Alias alias) - { - try - { - if (alias.SiteId != PageState.Site.SiteId || alias.TenantId != PageState.Site.TenantId) - { - SiteService.SetAlias(alias); - await SiteService.DeleteSiteAsync(alias.SiteId); - await Log(alias, LogLevel.Information, "", null, "Site Deleted {SiteId}", alias.SiteId); - - var aliases = await AliasService.GetAliasesAsync(); - foreach (Alias a in aliases.Where(item => item.SiteId == alias.SiteId && item.TenantId == alias.TenantId)) - { - await AliasService.DeleteAliasAsync(a.AliasId); - } - - NavigationManager.NavigateTo(NavigateUrl()); - } - else - { - AddModuleMessage(Localizer["You Can Not Delete The Current Site"], MessageType.Warning); - } - } - catch (Exception ex) - { - await Log(alias, LogLevel.Error, "", ex, "Error Deleting Site {SiteId} {Error}", alias.SiteId, ex.Message); - AddModuleMessage(Localizer["Error Deleting Site"], MessageType.Error); - } - } } diff --git a/Oqtane.Client/Modules/HtmlText/Edit.razor b/Oqtane.Client/Modules/HtmlText/Edit.razor index f2e1b154..269bb022 100644 --- a/Oqtane.Client/Modules/HtmlText/Edit.razor +++ b/Oqtane.Client/Modules/HtmlText/Edit.razor @@ -51,7 +51,7 @@ if (htmltext != null) { _content = htmltext.Content; - _content = _content.Replace(Constants.ContentUrl, "/" + PageState.Alias.AliasId.ToString() + Constants.ContentUrl); + _content = _content.Replace(Constants.ContentUrl, "/" + PageState.Alias.Path + Constants.ContentUrl); _createdby = htmltext.CreatedBy; _createdon = htmltext.CreatedOn; _modifiedby = htmltext.ModifiedBy; @@ -72,7 +72,7 @@ private async Task SaveContent() { string content = await RichTextEditorHtml.GetHtml(); - content = content.Replace("/" + PageState.Alias.AliasId.ToString() + Constants.ContentUrl, Constants.ContentUrl); + content = content.Replace("/" + PageState.Alias.Path + Constants.ContentUrl, Constants.ContentUrl); try { diff --git a/Oqtane.Client/Modules/HtmlText/Index.razor b/Oqtane.Client/Modules/HtmlText/Index.razor index c38009c5..57094850 100644 --- a/Oqtane.Client/Modules/HtmlText/Index.razor +++ b/Oqtane.Client/Modules/HtmlText/Index.razor @@ -26,7 +26,7 @@ if (htmltext != null) { content = htmltext.Content; - content = content.Replace(Constants.ContentUrl, "/" + PageState.Alias.AliasId.ToString() + Constants.ContentUrl); + content = content.Replace(Constants.ContentUrl, "/" + PageState.Alias.Path + Constants.ContentUrl); } } catch (Exception ex) diff --git a/Oqtane.Client/Modules/HtmlText/Services/HtmlTextService.cs b/Oqtane.Client/Modules/HtmlText/Services/HtmlTextService.cs index af0063bb..90dfcdde 100644 --- a/Oqtane.Client/Modules/HtmlText/Services/HtmlTextService.cs +++ b/Oqtane.Client/Modules/HtmlText/Services/HtmlTextService.cs @@ -17,7 +17,7 @@ namespace Oqtane.Modules.HtmlText.Services _siteState = siteState; } - private string ApiUrl => CreateApiUrl(_siteState.Alias, "HtmlText"); + private string ApiUrl => CreateApiUrl("HtmlText", _siteState.Alias); public async Task GetHtmlTextAsync(int moduleId) { diff --git a/Oqtane.Client/Services/AliasService.cs b/Oqtane.Client/Services/AliasService.cs index 21df7dd0..b88e533f 100644 --- a/Oqtane.Client/Services/AliasService.cs +++ b/Oqtane.Client/Services/AliasService.cs @@ -1,4 +1,4 @@ -using Oqtane.Models; +using Oqtane.Models; using System.Threading.Tasks; using System.Net.Http; using System.Linq; @@ -19,7 +19,7 @@ namespace Oqtane.Services _siteState = siteState; } - private string Apiurl => CreateApiUrl(_siteState.Alias, "Alias"); + private string Apiurl => CreateApiUrl("Alias", _siteState.Alias); public async Task> GetAliasesAsync() { @@ -32,10 +32,9 @@ namespace Oqtane.Services return await GetJsonAsync($"{Apiurl}/{aliasId}"); } - public async Task GetAliasAsync(string name, DateTime lastSyncDate) + public async Task GetAliasAsync(string path, DateTime lastSyncDate) { - name = (string.IsNullOrEmpty(name)) ? "~" : name; - return await GetJsonAsync($"{Apiurl}/name/{WebUtility.UrlEncode(name)}?sync={lastSyncDate.ToString("yyyyMMddHHmmssfff")}"); + return await GetJsonAsync($"{Apiurl}/name/?path={WebUtility.UrlEncode(path)}&sync={lastSyncDate.ToString("yyyyMMddHHmmssfff")}"); } public async Task AddAliasAsync(Alias alias) diff --git a/Oqtane.Client/Services/DatabaseService.cs b/Oqtane.Client/Services/DatabaseService.cs new file mode 100644 index 00000000..db108d74 --- /dev/null +++ b/Oqtane.Client/Services/DatabaseService.cs @@ -0,0 +1,28 @@ +using Oqtane.Models; +using System.Threading.Tasks; +using System.Net.Http; +using System.Linq; +using System.Collections.Generic; +using Oqtane.Shared; + +namespace Oqtane.Services +{ + public class DatabaseService : ServiceBase, IDatabaseService + { + + private readonly SiteState _siteState; + + public DatabaseService(HttpClient http, SiteState siteState) : base(http) + { + _siteState = siteState; + } + + private string Apiurl => CreateApiUrl("Database", _siteState.Alias); + + public async Task> GetDatabasesAsync() + { + List databases = await GetJsonAsync>(Apiurl); + return databases.OrderBy(item => item.FriendlyName).ToList(); + } + } +} diff --git a/Oqtane.Client/Services/FileService.cs b/Oqtane.Client/Services/FileService.cs index d4508168..3bcf4b20 100644 --- a/Oqtane.Client/Services/FileService.cs +++ b/Oqtane.Client/Services/FileService.cs @@ -21,7 +21,7 @@ namespace Oqtane.Services _jsRuntime = jsRuntime; } - private string Apiurl => CreateApiUrl(_siteState.Alias, "File"); + private string Apiurl => CreateApiUrl("File", _siteState.Alias); public async Task> GetFilesAsync(int folderId) { diff --git a/Oqtane.Client/Services/FolderService.cs b/Oqtane.Client/Services/FolderService.cs index 19f07946..ffb05c8e 100644 --- a/Oqtane.Client/Services/FolderService.cs +++ b/Oqtane.Client/Services/FolderService.cs @@ -19,7 +19,7 @@ namespace Oqtane.Services _siteState = siteState; } - private string ApiUrl => CreateApiUrl(_siteState.Alias, "Folder"); + private string ApiUrl => CreateApiUrl("Folder", _siteState.Alias); public async Task> GetFoldersAsync(int siteId) { diff --git a/Oqtane.Client/Services/InstallationService.cs b/Oqtane.Client/Services/InstallationService.cs index c6900c59..b56444d7 100644 --- a/Oqtane.Client/Services/InstallationService.cs +++ b/Oqtane.Client/Services/InstallationService.cs @@ -7,9 +7,14 @@ namespace Oqtane.Services { public class InstallationService : ServiceBase, IInstallationService { - public InstallationService(HttpClient http):base(http) { } + private readonly SiteState _siteState; - private string ApiUrl => CreateApiUrl("Installation"); + public InstallationService(HttpClient http, SiteState siteState) : base(http) + { + _siteState = siteState; + } + + private string ApiUrl => CreateApiUrl("Installation", _siteState.Alias); public async Task IsInstalled() { diff --git a/Oqtane.Client/Services/Interfaces/IDatabaseService.cs b/Oqtane.Client/Services/Interfaces/IDatabaseService.cs new file mode 100644 index 00000000..9d6b8bf0 --- /dev/null +++ b/Oqtane.Client/Services/Interfaces/IDatabaseService.cs @@ -0,0 +1,11 @@ +using Oqtane.Models; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Oqtane.Services +{ + public interface IDatabaseService + { + Task> GetDatabasesAsync(); + } +} diff --git a/Oqtane.Client/Services/Interfaces/IPackageService.cs b/Oqtane.Client/Services/Interfaces/IPackageService.cs index eeb243c1..4c5f24b1 100644 --- a/Oqtane.Client/Services/Interfaces/IPackageService.cs +++ b/Oqtane.Client/Services/Interfaces/IPackageService.cs @@ -1,4 +1,4 @@ -using Oqtane.Models; +using Oqtane.Models; using System.Collections.Generic; using System.Threading.Tasks; @@ -8,5 +8,6 @@ namespace Oqtane.Services { Task> GetPackagesAsync(string tag); Task DownloadPackageAsync(string packageId, string version, string folder); + Task InstallPackagesAsync(); } } diff --git a/Oqtane.Client/Services/Interfaces/ISiteService.cs b/Oqtane.Client/Services/Interfaces/ISiteService.cs index a87a26c4..669d5554 100644 --- a/Oqtane.Client/Services/Interfaces/ISiteService.cs +++ b/Oqtane.Client/Services/Interfaces/ISiteService.cs @@ -1,4 +1,5 @@ -using Oqtane.Models; +using Oqtane.Models; +using System; using System.Collections.Generic; using System.Threading.Tasks; @@ -6,8 +7,6 @@ namespace Oqtane.Services { public interface ISiteService { - void SetAlias(Alias alias); - Task> GetSitesAsync(); Task GetSiteAsync(int siteId); @@ -17,5 +16,8 @@ namespace Oqtane.Services Task UpdateSiteAsync(Site site); Task DeleteSiteAsync(int siteId); + + [Obsolete("This method is deprecated.", false)] + void SetAlias(Alias alias); } } diff --git a/Oqtane.Client/Services/JobLogService.cs b/Oqtane.Client/Services/JobLogService.cs index aa518771..260d77eb 100644 --- a/Oqtane.Client/Services/JobLogService.cs +++ b/Oqtane.Client/Services/JobLogService.cs @@ -1,4 +1,4 @@ -using Oqtane.Models; +using Oqtane.Models; using System.Threading.Tasks; using System.Net.Http; using System.Linq; @@ -16,7 +16,7 @@ namespace Oqtane.Services _siteState = siteState; } - private string Apiurl => CreateApiUrl(_siteState.Alias, "JobLog"); + private string Apiurl => CreateApiUrl("JobLog", _siteState.Alias); public async Task> GetJobLogsAsync() { diff --git a/Oqtane.Client/Services/JobService.cs b/Oqtane.Client/Services/JobService.cs index 3161cd90..40a23339 100644 --- a/Oqtane.Client/Services/JobService.cs +++ b/Oqtane.Client/Services/JobService.cs @@ -1,4 +1,4 @@ -using Oqtane.Models; +using Oqtane.Models; using System.Threading.Tasks; using System.Net.Http; using System.Linq; @@ -16,7 +16,7 @@ namespace Oqtane.Services _siteState = siteState; } - private string Apiurl => CreateApiUrl(_siteState.Alias, "Job"); + private string Apiurl => CreateApiUrl("Job", _siteState.Alias); public async Task> GetJobsAsync() { diff --git a/Oqtane.Client/Services/LanguageService.cs b/Oqtane.Client/Services/LanguageService.cs index 5f5d29cb..77286be5 100644 --- a/Oqtane.Client/Services/LanguageService.cs +++ b/Oqtane.Client/Services/LanguageService.cs @@ -17,7 +17,7 @@ namespace Oqtane.Services _siteState = siteState; } - private string Apiurl => CreateApiUrl(_siteState.Alias, "Language"); + private string Apiurl => CreateApiUrl("Language", _siteState.Alias); public async Task> GetLanguagesAsync(int siteId) { diff --git a/Oqtane.Client/Services/LocalizationService.cs b/Oqtane.Client/Services/LocalizationService.cs index b6c56bca..9b1b4b61 100644 --- a/Oqtane.Client/Services/LocalizationService.cs +++ b/Oqtane.Client/Services/LocalizationService.cs @@ -15,7 +15,7 @@ namespace Oqtane.Services _siteState = siteState; } - private string Apiurl => CreateApiUrl(_siteState.Alias, "Localization"); + private string Apiurl => CreateApiUrl("Localization", _siteState.Alias); public async Task> GetCulturesAsync() => await GetJsonAsync>(Apiurl); } diff --git a/Oqtane.Client/Services/LogService.cs b/Oqtane.Client/Services/LogService.cs index f882e530..6d787341 100644 --- a/Oqtane.Client/Services/LogService.cs +++ b/Oqtane.Client/Services/LogService.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Net.Http; using System.Text.Json; @@ -23,7 +23,7 @@ namespace Oqtane.Services _navigationManager = navigationManager; } - private string Apiurl => CreateApiUrl(_siteState.Alias, "Log"); + private string Apiurl => CreateApiUrl("Log", _siteState.Alias); public async Task> GetLogsAsync(int siteId, string level, string function, int rows) { @@ -49,7 +49,6 @@ namespace Oqtane.Services } else { - base.Alias = alias; log.SiteId = alias.SiteId; } log.PageId = pageId; diff --git a/Oqtane.Client/Services/ModuleDefinitionService.cs b/Oqtane.Client/Services/ModuleDefinitionService.cs index 9f8984c0..a097c6ff 100644 --- a/Oqtane.Client/Services/ModuleDefinitionService.cs +++ b/Oqtane.Client/Services/ModuleDefinitionService.cs @@ -21,7 +21,7 @@ namespace Oqtane.Services _siteState = siteState; } - private string Apiurl => CreateApiUrl(_siteState.Alias, "ModuleDefinition"); + private string Apiurl => CreateApiUrl("ModuleDefinition", _siteState.Alias); public async Task> GetModuleDefinitionsAsync(int siteId) { diff --git a/Oqtane.Client/Services/ModuleService.cs b/Oqtane.Client/Services/ModuleService.cs index ce1d9978..00b88a82 100644 --- a/Oqtane.Client/Services/ModuleService.cs +++ b/Oqtane.Client/Services/ModuleService.cs @@ -1,4 +1,4 @@ -using Oqtane.Models; +using Oqtane.Models; using System.Collections.Generic; using System.Linq; using System.Net.Http; @@ -17,7 +17,7 @@ namespace Oqtane.Services _siteState = siteState; } - private string Apiurl => CreateApiUrl(_siteState.Alias, "Module"); + private string Apiurl => CreateApiUrl("Module", _siteState.Alias); public async Task> GetModulesAsync(int siteId) { diff --git a/Oqtane.Client/Services/NotificationService.cs b/Oqtane.Client/Services/NotificationService.cs index dbce9f8f..5bbd8606 100644 --- a/Oqtane.Client/Services/NotificationService.cs +++ b/Oqtane.Client/Services/NotificationService.cs @@ -1,4 +1,4 @@ -using Oqtane.Models; +using Oqtane.Models; using System.Threading.Tasks; using System.Net.Http; using Oqtane.Shared; @@ -16,7 +16,7 @@ namespace Oqtane.Services _siteState = siteState; } - private string Apiurl => CreateApiUrl(_siteState.Alias, "Notification"); + private string Apiurl => CreateApiUrl("Notification", _siteState.Alias); public async Task> GetNotificationsAsync(int siteId, string direction, int userId) { diff --git a/Oqtane.Client/Services/PackageService.cs b/Oqtane.Client/Services/PackageService.cs index 0fa6123b..c101b5f3 100644 --- a/Oqtane.Client/Services/PackageService.cs +++ b/Oqtane.Client/Services/PackageService.cs @@ -1,16 +1,21 @@ -using Oqtane.Models; +using Oqtane.Models; using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; using System.Linq; +using Oqtane.Shared; namespace Oqtane.Services { public class PackageService : ServiceBase, IPackageService - { - public PackageService(HttpClient http) : base(http) { } + { + private readonly SiteState _siteState; - private string Apiurl => CreateApiUrl("Package"); + public PackageService(HttpClient http, SiteState siteState) : base(http) + { + _siteState = siteState; + } + private string Apiurl => CreateApiUrl("Package", _siteState.Alias); public async Task> GetPackagesAsync(string tag) { @@ -22,5 +27,10 @@ namespace Oqtane.Services { await PostAsync($"{Apiurl}?packageid={packageId}&version={version}&folder={folder}"); } + + public async Task InstallPackagesAsync() + { + await GetJsonAsync>($"{Apiurl}/install"); + } } } diff --git a/Oqtane.Client/Services/PageModuleService.cs b/Oqtane.Client/Services/PageModuleService.cs index 588a4a6b..63e871d4 100644 --- a/Oqtane.Client/Services/PageModuleService.cs +++ b/Oqtane.Client/Services/PageModuleService.cs @@ -1,4 +1,4 @@ -using Oqtane.Models; +using Oqtane.Models; using System.Net.Http; using System.Threading.Tasks; using Oqtane.Shared; @@ -15,7 +15,7 @@ namespace Oqtane.Services _siteState = siteState; } - private string Apiurl => CreateApiUrl(_siteState.Alias, "PageModule"); + private string Apiurl => CreateApiUrl("PageModule", _siteState.Alias); public async Task GetPageModuleAsync(int pageModuleId) { diff --git a/Oqtane.Client/Services/PageService.cs b/Oqtane.Client/Services/PageService.cs index c22e4985..a4922d0a 100644 --- a/Oqtane.Client/Services/PageService.cs +++ b/Oqtane.Client/Services/PageService.cs @@ -1,4 +1,4 @@ -using Oqtane.Models; +using Oqtane.Models; using System.Threading.Tasks; using System.Linq; using System.Net.Http; @@ -20,7 +20,7 @@ namespace Oqtane.Services _siteState = siteState; } - private string Apiurl => CreateApiUrl(_siteState.Alias, "Page"); + private string Apiurl => CreateApiUrl("Page", _siteState.Alias); public async Task> GetPagesAsync(int siteId) { diff --git a/Oqtane.Client/Services/ProfileService.cs b/Oqtane.Client/Services/ProfileService.cs index 100d1870..b4a80b89 100644 --- a/Oqtane.Client/Services/ProfileService.cs +++ b/Oqtane.Client/Services/ProfileService.cs @@ -1,4 +1,4 @@ -using Oqtane.Models; +using Oqtane.Models; using System.Threading.Tasks; using System.Net.Http; using System.Linq; @@ -17,7 +17,7 @@ namespace Oqtane.Services _siteState = siteState; } - private string Apiurl => CreateApiUrl(_siteState.Alias, "Profile"); + private string Apiurl => CreateApiUrl("Profile", _siteState.Alias); public async Task> GetProfilesAsync(int siteId) { diff --git a/Oqtane.Client/Services/RoleService.cs b/Oqtane.Client/Services/RoleService.cs index 5d29dcd3..83b34d68 100644 --- a/Oqtane.Client/Services/RoleService.cs +++ b/Oqtane.Client/Services/RoleService.cs @@ -18,7 +18,7 @@ namespace Oqtane.Services _siteState = siteState; } - private string Apiurl => CreateApiUrl(_siteState.Alias, "Role"); + private string Apiurl => CreateApiUrl("Role", _siteState.Alias); public async Task> GetRolesAsync(int siteId) { diff --git a/Oqtane.Client/Services/ServiceBase.cs b/Oqtane.Client/Services/ServiceBase.cs index 71e1ad78..798621f3 100644 --- a/Oqtane.Client/Services/ServiceBase.cs +++ b/Oqtane.Client/Services/ServiceBase.cs @@ -5,6 +5,7 @@ using System.Net.Http.Json; using System.Threading; using System.Threading.Tasks; using Oqtane.Models; +using Oqtane.Shared; namespace Oqtane.Services { @@ -17,6 +18,55 @@ namespace Oqtane.Services _http = client; } + public string CreateApiUrl(string serviceName, Alias alias) + { + return CreateApiUrl(serviceName, alias, ControllerRoutes.ApiRoute); + } + + public string CreateApiUrl(string serviceName, Alias alias, string routeTemplate) + { + string apiurl = "/"; + if (routeTemplate == ControllerRoutes.ApiRoute) + { + if (alias != null && !string.IsNullOrEmpty(alias.Path)) + { + // include the alias path for multi-tenant context + apiurl += alias.Path + "/"; + } + } + else + { + // legacy support for ControllerRoutes.Default + if (alias != null) + { + // include the alias for multi-tenant context + apiurl += $"{alias.AliasId}/"; + } + else + { + // tenant agnostic + apiurl += "~/"; + } + } + apiurl += $"api/{serviceName}"; + return apiurl; + } + + // add entityid parameter to url for custom authorization policy + public string CreateAuthorizationPolicyUrl(string url, int entityId) + { + string qs = "entityid=" + entityId.ToString(); + + if (url.Contains("?")) + { + return url + "&" + qs; + } + else + { + return url + "?" + qs; + } + } + protected async Task GetAsync(string uri) { var response = await _http.GetAsync(uri); @@ -135,61 +185,26 @@ namespace Oqtane.Services //TODO Missing content JSON validation } - // create an API Url which is tenant agnostic ( for use during installation ) - public string CreateApiUrl(string serviceName) - { - return CreateApiUrl(null, serviceName); - } - - // create an API Url which is tenant aware ( for use with repositories ) - public string CreateApiUrl(Alias alias, string serviceName) - { - string apiurl = "/"; - - if (Alias != null) - { - alias = Alias; // override the default alias ( for cross-tenant service calls ) - } - - if (alias != null) - { - // include the alias for multi-tenant context - apiurl += $"{alias.AliasId}/"; - } - else - { - // tenant agnostic - apiurl += "~/"; - } - - apiurl += $"api/{serviceName}"; - - return apiurl; - } - - // can be used to override the default alias - public Alias Alias { get; set; } - - // add entityid parameter to url for custom authorization policy - public string CreateAuthorizationPolicyUrl(string url, int entityId) - { - string qs = "entityid=" + entityId.ToString(); - - if (url.Contains("?")) - { - return url + "&" + qs; - } - else - { - return url + "?" + qs; - } - } - [Obsolete("This method is obsolete. Use CreateApiUrl(Alias alias, string serviceName) instead.", false)] public string CreateApiUrl(Alias alias, string absoluteUri, string serviceName) { // only retained for short term backward compatibility return CreateApiUrl(alias, serviceName); } + + [Obsolete("This method is obsolete. Use CreateApiUrl(string serviceName, Alias alias) instead.", false)] + public string CreateApiUrl(string serviceName) + { + return CreateApiUrl(serviceName, null, ControllerRoutes.Default); + } + + [Obsolete("This method is deprecated.", false)] + public Alias Alias { get; set; } + + [Obsolete("This method is obsolete. Use CreateApiUrl(string serviceName, Alias alias) instead.", false)] + public string CreateApiUrl(Alias alias, string serviceName) + { + return CreateApiUrl(serviceName, alias, ControllerRoutes.Default); + } } } diff --git a/Oqtane.Client/Services/SettingService.cs b/Oqtane.Client/Services/SettingService.cs index 97d52054..e252c3ea 100644 --- a/Oqtane.Client/Services/SettingService.cs +++ b/Oqtane.Client/Services/SettingService.cs @@ -1,4 +1,4 @@ -using System; +using System; using Oqtane.Models; using System.Threading.Tasks; using System.Net.Http; @@ -18,7 +18,7 @@ namespace Oqtane.Services _siteState = siteState; } - private string Apiurl => CreateApiUrl(_siteState.Alias, "Setting"); + private string Apiurl => CreateApiUrl("Setting", _siteState.Alias); public async Task> GetTenantSettingsAsync() { return await GetSettingsAsync(EntityNames.Tenant, -1); diff --git a/Oqtane.Client/Services/SiteService.cs b/Oqtane.Client/Services/SiteService.cs index 29e43e73..b4116312 100644 --- a/Oqtane.Client/Services/SiteService.cs +++ b/Oqtane.Client/Services/SiteService.cs @@ -1,9 +1,10 @@ -using Oqtane.Models; +using Oqtane.Models; using System.Threading.Tasks; using System.Net.Http; using System.Linq; using System.Collections.Generic; using Oqtane.Shared; +using System; namespace Oqtane.Services { @@ -18,12 +19,7 @@ namespace Oqtane.Services _siteState = siteState; } - private string Apiurl => CreateApiUrl(_siteState.Alias, "Site"); - - public void SetAlias(Alias alias) - { - base.Alias = alias; - } + private string Apiurl => CreateApiUrl("Site", _siteState.Alias); public async Task> GetSitesAsync() { @@ -50,5 +46,11 @@ namespace Oqtane.Services { await DeleteAsync($"{Apiurl}/{siteId}"); } + + [Obsolete("This method is deprecated.", false)] + public void SetAlias(Alias alias) + { + base.Alias = alias; + } } } diff --git a/Oqtane.Client/Services/SiteTemplateService.cs b/Oqtane.Client/Services/SiteTemplateService.cs index 8697108b..383fb6f6 100644 --- a/Oqtane.Client/Services/SiteTemplateService.cs +++ b/Oqtane.Client/Services/SiteTemplateService.cs @@ -1,4 +1,5 @@ -using Oqtane.Models; +using Oqtane.Models; +using Oqtane.Shared; using System.Collections.Generic; using System.Linq; using System.Net.Http; @@ -8,9 +9,13 @@ namespace Oqtane.Services { public class SiteTemplateService : ServiceBase, ISiteTemplateService { - public SiteTemplateService(HttpClient http) : base(http) { } + private readonly SiteState _siteState; - private string Apiurl => CreateApiUrl("SiteTemplate"); + public SiteTemplateService(HttpClient http, SiteState siteState) : base(http) + { + _siteState = siteState; + } + private string Apiurl => CreateApiUrl("SiteTemplate", _siteState.Alias); public async Task> GetSiteTemplatesAsync() { diff --git a/Oqtane.Client/Services/SqlService.cs b/Oqtane.Client/Services/SqlService.cs index 719156b2..d43a8198 100644 --- a/Oqtane.Client/Services/SqlService.cs +++ b/Oqtane.Client/Services/SqlService.cs @@ -1,4 +1,4 @@ -using Oqtane.Models; +using Oqtane.Models; using Oqtane.Shared; using System.Net.Http; using System.Threading.Tasks; @@ -14,7 +14,7 @@ namespace Oqtane.Services _siteState = siteState; } - private string Apiurl => CreateApiUrl(_siteState.Alias, "Sql"); + private string Apiurl => CreateApiUrl("Sql", _siteState.Alias); public async Task ExecuteQueryAsync(SqlQuery sqlquery) { diff --git a/Oqtane.Client/Services/SystemService.cs b/Oqtane.Client/Services/SystemService.cs index c8b1388b..cade0ed0 100644 --- a/Oqtane.Client/Services/SystemService.cs +++ b/Oqtane.Client/Services/SystemService.cs @@ -1,14 +1,20 @@ -using System.Net.Http; +using System.Net.Http; using System.Threading.Tasks; using System.Collections.Generic; +using Oqtane.Shared; namespace Oqtane.Services { public class SystemService : ServiceBase, ISystemService { - public SystemService(HttpClient http) : base(http) { } + private readonly SiteState _siteState; - private string Apiurl => CreateApiUrl("System"); + public SystemService(HttpClient http, SiteState siteState) : base(http) + { + _siteState = siteState; + } + + private string Apiurl => CreateApiUrl("System", _siteState.Alias); public async Task> GetSystemInfoAsync() { diff --git a/Oqtane.Client/Services/TenantService.cs b/Oqtane.Client/Services/TenantService.cs index d644348e..f09d91d2 100644 --- a/Oqtane.Client/Services/TenantService.cs +++ b/Oqtane.Client/Services/TenantService.cs @@ -1,4 +1,4 @@ -using Oqtane.Models; +using Oqtane.Models; using System.Net.Http; using System.Threading.Tasks; using System.Collections.Generic; @@ -16,7 +16,7 @@ namespace Oqtane.Services _siteState = siteState; } - private string Apiurl => CreateApiUrl(_siteState.Alias, "Tenant"); + private string Apiurl => CreateApiUrl("Tenant", _siteState.Alias); public async Task> GetTenantsAsync() { diff --git a/Oqtane.Client/Services/ThemeService.cs b/Oqtane.Client/Services/ThemeService.cs index ac79ad88..529c1a3b 100644 --- a/Oqtane.Client/Services/ThemeService.cs +++ b/Oqtane.Client/Services/ThemeService.cs @@ -16,7 +16,7 @@ namespace Oqtane.Services _siteState = siteState; } - private string ApiUrl => CreateApiUrl(_siteState.Alias, "Theme"); + private string ApiUrl => CreateApiUrl("Theme", _siteState.Alias); public async Task> GetThemesAsync() { diff --git a/Oqtane.Client/Services/UserRoleService.cs b/Oqtane.Client/Services/UserRoleService.cs index e1666df0..a69eaa10 100644 --- a/Oqtane.Client/Services/UserRoleService.cs +++ b/Oqtane.Client/Services/UserRoleService.cs @@ -1,4 +1,4 @@ -using Oqtane.Models; +using Oqtane.Models; using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; @@ -16,7 +16,7 @@ namespace Oqtane.Services _siteState = siteState; } - private string Apiurl => CreateApiUrl(_siteState.Alias, "UserRole"); + private string Apiurl => CreateApiUrl("UserRole", _siteState.Alias); public async Task> GetUserRolesAsync(int siteId) { diff --git a/Oqtane.Client/Services/UserService.cs b/Oqtane.Client/Services/UserService.cs index 3538ecb7..3fb73cc5 100644 --- a/Oqtane.Client/Services/UserService.cs +++ b/Oqtane.Client/Services/UserService.cs @@ -14,7 +14,7 @@ namespace Oqtane.Services _siteState = siteState; } - private string Apiurl => CreateApiUrl(_siteState.Alias, "User"); + private string Apiurl => CreateApiUrl("User", _siteState.Alias); public async Task GetUserAsync(int userId, int siteId) { diff --git a/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs b/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs index 01907321..dfa86f01 100644 --- a/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs +++ b/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs @@ -39,7 +39,9 @@ namespace Oqtane.Themes.Controls var interop = new Interop(jsRuntime); string antiforgerytoken = await interop.GetElementByName("__RequestVerificationToken"); var fields = new { __RequestVerificationToken = antiforgerytoken, returnurl = !authorizedtoviewpage ? PageState.Alias.Path : PageState.Alias.Path + "/" + PageState.Page.Path }; - await interop.SubmitForm($"/{PageState.Alias.AliasId}/pages/logout/", fields); + string url = "/pages/logout/"; + if (!string.IsNullOrEmpty(PageState.Alias.Path)) url = "/" + PageState.Alias.Path + url; + await interop.SubmitForm(url, fields); } else { diff --git a/Oqtane.Server/Controllers/AliasController.cs b/Oqtane.Server/Controllers/AliasController.cs index 4d8dac8d..9edea4dd 100644 --- a/Oqtane.Server/Controllers/AliasController.cs +++ b/Oqtane.Server/Controllers/AliasController.cs @@ -14,7 +14,7 @@ using Microsoft.AspNetCore.Http; namespace Oqtane.Controllers { - [Route(ControllerRoutes.Default)] + [Route(ControllerRoutes.ApiRoute)] public class AliasController : Controller { private readonly IAliasRepository _aliases; @@ -46,17 +46,16 @@ namespace Oqtane.Controllers return _aliases.GetAlias(id); } - // GET api//name/xxx?sync=yyyyMMddHHmmssfff - [HttpGet("name/{**name}")] - public Alias Get(string name, string sync) + // GET api//name/?path=xxx&sync=yyyyMMddHHmmssfff + [HttpGet("name")] + public Alias Get(string path, string sync) { Alias alias = null; if (_accessor.HttpContext != null) { - name = (name == "~") ? "" : name; - name = _accessor.HttpContext.Request.Host.Value + "/" + WebUtility.UrlDecode(name); - alias = _aliases.GetAlias(name); + path = _accessor.HttpContext.Request.Host.Value + "/" + WebUtility.UrlDecode(path); + alias = _aliases.GetAlias(path); } // get sync events diff --git a/Oqtane.Server/Controllers/DatabaseController.cs b/Oqtane.Server/Controllers/DatabaseController.cs new file mode 100644 index 00000000..418a5885 --- /dev/null +++ b/Oqtane.Server/Controllers/DatabaseController.cs @@ -0,0 +1,52 @@ +using System.Collections.Generic; +using Microsoft.AspNetCore.Mvc; +using Oqtane.Shared; + +namespace Oqtane.Controllers +{ + [Route(ControllerRoutes.ApiRoute)] + public class DatabaseController : Controller + { + public DatabaseController() { } + + // GET: api/ + [HttpGet] + public IEnumerable Get() + { + var databases = new List + { + new() + { + Name = "LocalDB", + FriendlyName = "Local Database", + Type = "Oqtane.Installer.Controls.LocalDBConfig, Oqtane.Client" + }, + new() + { + Name = "SqlServer", + FriendlyName = "SQL Server", + Type = "Oqtane.Installer.Controls.SqlServerConfig, Oqtane.Client" + }, + new() + { + Name = "Sqlite", + FriendlyName = "Sqlite", + Type = "Oqtane.Installer.Controls.SqliteConfig, Oqtane.Client" + }, + new() + { + Name = "MySQL", + FriendlyName = "MySQL", + Type = "Oqtane.Installer.Controls.MySQLConfig, Oqtane.Client" + }, + new() + { + Name = "PostgreSQL", + FriendlyName = "PostgreSQL", + Type = "Oqtane.Installer.Controls.PostGreSQLConfig, Oqtane.Client" + } + }; + return databases; + } + } +} diff --git a/Oqtane.Server/Controllers/FileController.cs b/Oqtane.Server/Controllers/FileController.cs index ce36dae2..84dc4281 100644 --- a/Oqtane.Server/Controllers/FileController.cs +++ b/Oqtane.Server/Controllers/FileController.cs @@ -16,30 +16,27 @@ using System.Net; using Oqtane.Enums; using Oqtane.Infrastructure; using Oqtane.Repository; -using Microsoft.AspNetCore.Routing.Constraints; using Oqtane.Extensions; // ReSharper disable StringIndexOfIsCultureSpecific.1 namespace Oqtane.Controllers { - [Route(ControllerRoutes.Default)] + [Route(ControllerRoutes.ApiRoute)] public class FileController : Controller { private readonly IWebHostEnvironment _environment; private readonly IFileRepository _files; private readonly IFolderRepository _folders; private readonly IUserPermissions _userPermissions; - private readonly ITenantResolver _tenants; private readonly ILogManager _logger; - public FileController(IWebHostEnvironment environment, IFileRepository files, IFolderRepository folders, IUserPermissions userPermissions, ITenantResolver tenants, ILogManager logger) + public FileController(IWebHostEnvironment environment, IFileRepository files, IFolderRepository folders, IUserPermissions userPermissions, ILogManager logger) { _environment = environment; _files = files; _folders = folders; _userPermissions = userPermissions; - _tenants = tenants; _logger = logger; } diff --git a/Oqtane.Server/Controllers/FolderController.cs b/Oqtane.Server/Controllers/FolderController.cs index a3fcb03a..9093631f 100644 --- a/Oqtane.Server/Controllers/FolderController.cs +++ b/Oqtane.Server/Controllers/FolderController.cs @@ -15,21 +15,21 @@ using Microsoft.AspNetCore.Hosting; namespace Oqtane.Controllers { - [Route(ControllerRoutes.Default)] + [Route(ControllerRoutes.ApiRoute)] public class FolderController : Controller { private readonly IWebHostEnvironment _environment; private readonly IFolderRepository _folders; private readonly IUserPermissions _userPermissions; - private readonly ITenantResolver _tenants; + private readonly ITenantManager _tenantManager; private readonly ILogManager _logger; - public FolderController(IWebHostEnvironment environment, IFolderRepository folders, IUserPermissions userPermissions, ITenantResolver tenants, ILogManager logger) + public FolderController(IWebHostEnvironment environment, IFolderRepository folders, IUserPermissions userPermissions, ITenantManager tenantManager, ILogManager logger) { _environment = environment; _folders = folders; _userPermissions = userPermissions; - _tenants = tenants; + _tenantManager = tenantManager; _logger = logger; } @@ -235,7 +235,7 @@ namespace Oqtane.Controllers private string GetFolderPath(Folder folder) { - return Utilities.PathCombine(_environment.ContentRootPath, "Content", "Tenants", _tenants.GetTenant().TenantId.ToString(), "Sites", folder.SiteId.ToString(), folder.Path); + return Utilities.PathCombine(_environment.ContentRootPath, "Content", "Tenants", _tenantManager.GetTenant().TenantId.ToString(), "Sites", folder.SiteId.ToString(), folder.Path); } } } diff --git a/Oqtane.Server/Controllers/InstallationController.cs b/Oqtane.Server/Controllers/InstallationController.cs index 46c4106f..dc23374f 100644 --- a/Oqtane.Server/Controllers/InstallationController.cs +++ b/Oqtane.Server/Controllers/InstallationController.cs @@ -12,11 +12,10 @@ using Oqtane.Modules; using Oqtane.Shared; using Oqtane.Themes; using Microsoft.Extensions.Caching.Memory; -using System.Collections.Generic; namespace Oqtane.Controllers { - [Route(ControllerRoutes.Default)] + [Route(ControllerRoutes.ApiRoute)] public class InstallationController : Controller { private readonly IConfigurationRoot _config; diff --git a/Oqtane.Server/Controllers/JobController.cs b/Oqtane.Server/Controllers/JobController.cs index 03cf4e3b..db4f4bfb 100644 --- a/Oqtane.Server/Controllers/JobController.cs +++ b/Oqtane.Server/Controllers/JobController.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization; using Oqtane.Models; @@ -12,7 +12,7 @@ using Oqtane.Repository; namespace Oqtane.Controllers { - [Route(ControllerRoutes.Default)] + [Route(ControllerRoutes.ApiRoute)] public class JobController : Controller { private readonly IJobRepository _jobs; diff --git a/Oqtane.Server/Controllers/JobLogController.cs b/Oqtane.Server/Controllers/JobLogController.cs index 055e90a0..39fd8ac9 100644 --- a/Oqtane.Server/Controllers/JobLogController.cs +++ b/Oqtane.Server/Controllers/JobLogController.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization; using Oqtane.Enums; @@ -9,7 +9,7 @@ using Oqtane.Repository; namespace Oqtane.Controllers { - [Route(ControllerRoutes.Default)] + [Route(ControllerRoutes.ApiRoute)] public class JobLogController : Controller { private readonly IJobLogRepository _jobLogs; diff --git a/Oqtane.Server/Controllers/LanguageController.cs b/Oqtane.Server/Controllers/LanguageController.cs index 71f160d9..b55f4bff 100644 --- a/Oqtane.Server/Controllers/LanguageController.cs +++ b/Oqtane.Server/Controllers/LanguageController.cs @@ -9,7 +9,7 @@ using Oqtane.Shared; namespace Oqtane.Controllers { - [Route(ControllerRoutes.Default)] + [Route(ControllerRoutes.ApiRoute)] public class LanguageController : Controller { private readonly ILanguageRepository _languages; diff --git a/Oqtane.Server/Controllers/LocalizationController.cs b/Oqtane.Server/Controllers/LocalizationController.cs index 84b54862..ace825a0 100644 --- a/Oqtane.Server/Controllers/LocalizationController.cs +++ b/Oqtane.Server/Controllers/LocalizationController.cs @@ -9,7 +9,7 @@ using Oqtane.Shared; namespace Oqtane.Controllers { - [Route(ControllerRoutes.Default)] + [Route(ControllerRoutes.ApiRoute)] public class LocalizationController : Controller { private readonly ILocalizationManager _localizationManager; diff --git a/Oqtane.Server/Controllers/LogController.cs b/Oqtane.Server/Controllers/LogController.cs index 4de0abcb..244a2a60 100644 --- a/Oqtane.Server/Controllers/LogController.cs +++ b/Oqtane.Server/Controllers/LogController.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc; using Oqtane.Models; using System.Collections.Generic; using Microsoft.AspNetCore.Authorization; @@ -9,7 +9,7 @@ using Oqtane.Shared; namespace Oqtane.Controllers { - [Route(ControllerRoutes.Default)] + [Route(ControllerRoutes.ApiRoute)] public class LogController : Controller { private readonly ILogManager _logger; diff --git a/Oqtane.Server/Controllers/ModuleController.cs b/Oqtane.Server/Controllers/ModuleController.cs index 4fe6c846..0faba825 100644 --- a/Oqtane.Server/Controllers/ModuleController.cs +++ b/Oqtane.Server/Controllers/ModuleController.cs @@ -11,7 +11,7 @@ using Oqtane.Security; namespace Oqtane.Controllers { - [Route(ControllerRoutes.Default)] + [Route(ControllerRoutes.ApiRoute)] public class ModuleController : Controller { private readonly IModuleRepository _modules; @@ -20,11 +20,11 @@ namespace Oqtane.Controllers private readonly IModuleDefinitionRepository _moduleDefinitions; private readonly ISettingRepository _settings; private readonly IUserPermissions _userPermissions; - private readonly ITenantResolver _tenants; private readonly ISyncManager _syncManager; private readonly ILogManager _logger; + private readonly Alias _alias; - public ModuleController(IModuleRepository modules, IPageModuleRepository pageModules, IPageRepository pages, IModuleDefinitionRepository moduleDefinitions, ISettingRepository settings, IUserPermissions userPermissions, ITenantResolver tenants, ISyncManager syncManager, ILogManager logger) + public ModuleController(IModuleRepository modules, IPageModuleRepository pageModules, IPageRepository pages, IModuleDefinitionRepository moduleDefinitions, ISettingRepository settings, IUserPermissions userPermissions, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger) { _modules = modules; _pageModules = pageModules; @@ -32,9 +32,9 @@ namespace Oqtane.Controllers _moduleDefinitions = moduleDefinitions; _settings = settings; _userPermissions = userPermissions; - _tenants = tenants; _syncManager = syncManager; _logger = logger; + _alias = tenantManager.GetAlias(); } // GET: api/?siteid=x @@ -108,7 +108,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Page, module.PageId, PermissionNames.Edit)) { module = _modules.AddModule(module); - _syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, _tenants.GetAlias().SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId); _logger.Log(LogLevel.Information, this, LogFunction.Create, "Module Added {Module}", module); } else @@ -142,7 +142,7 @@ namespace Oqtane.Controllers } } } - _syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, _tenants.GetAlias().SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId); } else { @@ -161,7 +161,7 @@ namespace Oqtane.Controllers if (_userPermissions.IsAuthorized(User, EntityNames.Module, id, PermissionNames.Edit)) { _modules.DeleteModule(id); - _syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, _tenants.GetAlias().SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Deleted {ModuleId}", id); } else diff --git a/Oqtane.Server/Controllers/ModuleDefinitionController.cs b/Oqtane.Server/Controllers/ModuleDefinitionController.cs index b9d7d47f..30d73d66 100644 --- a/Oqtane.Server/Controllers/ModuleDefinitionController.cs +++ b/Oqtane.Server/Controllers/ModuleDefinitionController.cs @@ -17,7 +17,7 @@ using System.Text.Json; namespace Oqtane.Controllers { - [Route(ControllerRoutes.Default)] + [Route(ControllerRoutes.ApiRoute)] public class ModuleDefinitionController : Controller { private readonly IModuleDefinitionRepository _moduleDefinitions; diff --git a/Oqtane.Server/Controllers/NotificationController.cs b/Oqtane.Server/Controllers/NotificationController.cs index 8fbb4872..fe721479 100644 --- a/Oqtane.Server/Controllers/NotificationController.cs +++ b/Oqtane.Server/Controllers/NotificationController.cs @@ -10,7 +10,7 @@ using Oqtane.Security; namespace Oqtane.Controllers { - [Route(ControllerRoutes.Default)] + [Route(ControllerRoutes.ApiRoute)] public class NotificationController : Controller { private readonly INotificationRepository _notifications; diff --git a/Oqtane.Server/Controllers/PackageController.cs b/Oqtane.Server/Controllers/PackageController.cs index 96af1346..b61585b5 100644 --- a/Oqtane.Server/Controllers/PackageController.cs +++ b/Oqtane.Server/Controllers/PackageController.cs @@ -1,28 +1,33 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using Oqtane.Models; using Newtonsoft.Json; using System; using System.Net.Http; using System.Threading.Tasks; -using System.Threading; using System.IO; using System.Linq; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Authorization; using Oqtane.Shared; +using Oqtane.Infrastructure; +using Oqtane.Enums; // ReSharper disable PartialTypeWithSinglePart namespace Oqtane.Controllers { - [Route(ControllerRoutes.Default)] + [Route(ControllerRoutes.ApiRoute)] public class PackageController : Controller { + private readonly IInstallationManager _installationManager; private readonly IWebHostEnvironment _environment; + private readonly ILogManager _logger; - public PackageController(IWebHostEnvironment environment) + public PackageController(IInstallationManager installationManager, IWebHostEnvironment environment, ILogManager logger) { + _installationManager = installationManager; _environment = environment; + _logger = logger; } // GET: api/?tag=x @@ -86,6 +91,14 @@ namespace Oqtane.Controllers } } } + + [HttpGet("install")] + [Authorize(Roles = RoleNames.Host)] + public void InstallPackages() + { + _logger.Log(LogLevel.Information, this, LogFunction.Create, "Packages Installed"); + _installationManager.InstallPackages("Packages"); + } } public partial class SearchResult diff --git a/Oqtane.Server/Controllers/PageController.cs b/Oqtane.Server/Controllers/PageController.cs index 81d3018b..3c9edaef 100644 --- a/Oqtane.Server/Controllers/PageController.cs +++ b/Oqtane.Server/Controllers/PageController.cs @@ -13,7 +13,7 @@ using Oqtane.Repository; namespace Oqtane.Controllers { - [Route(ControllerRoutes.Default)] + [Route(ControllerRoutes.ApiRoute)] public class PageController : Controller { private readonly IPageRepository _pages; @@ -21,20 +21,20 @@ namespace Oqtane.Controllers private readonly IPageModuleRepository _pageModules; private readonly ISettingRepository _settings; private readonly IUserPermissions _userPermissions; - private readonly ITenantResolver _tenants; private readonly ISyncManager _syncManager; private readonly ILogManager _logger; + private readonly Alias _alias; - public PageController(IPageRepository pages, IModuleRepository modules, IPageModuleRepository pageModules, ISettingRepository settings, IUserPermissions userPermissions, ITenantResolver tenants, ISyncManager syncManager, ILogManager logger) + public PageController(IPageRepository pages, IModuleRepository modules, IPageModuleRepository pageModules, ISettingRepository settings, IUserPermissions userPermissions, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger) { _pages = pages; _modules = modules; _pageModules = pageModules; _settings = settings; _userPermissions = userPermissions; - _tenants = tenants; _syncManager = syncManager; _logger = logger; + _alias = tenantManager.GetAlias(); } // GET: api/?siteid=x @@ -132,7 +132,7 @@ namespace Oqtane.Controllers if (_userPermissions.IsAuthorized(User,PermissionNames.Edit, permissions)) { page = _pages.AddPage(page); - _syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, page.SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, page.SiteId); _logger.Log(LogLevel.Information, this, LogFunction.Create, "Page Added {Page}", page); if (!page.Path.StartsWith("admin/")) @@ -183,7 +183,7 @@ namespace Oqtane.Controllers page.IsPersonalizable = false; page.UserId = int.Parse(userid); page = _pages.AddPage(page); - _syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, page.SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, page.SiteId); // copy modules List pagemodules = _pageModules.GetPageModules(page.SiteId).ToList(); @@ -228,7 +228,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Page, page.PageId, PermissionNames.Edit)) { page = _pages.UpdatePage(page); - _syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, page.SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, page.SiteId); _logger.Log(LogLevel.Information, this, LogFunction.Update, "Page Updated {Page}", page); } else @@ -258,7 +258,7 @@ namespace Oqtane.Controllers } order += 2; } - _syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, siteid); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, siteid); _logger.Log(LogLevel.Information, this, LogFunction.Update, "Page Order Updated {SiteId} {PageId} {ParentId}", siteid, pageid, parentid); } else @@ -277,7 +277,7 @@ namespace Oqtane.Controllers if (_userPermissions.IsAuthorized(User, EntityNames.Page, page.PageId, PermissionNames.Edit)) { _pages.DeletePage(page.PageId); - _syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, page.SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, page.SiteId); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Page Deleted {PageId}", page.PageId); } else diff --git a/Oqtane.Server/Controllers/PageModuleController.cs b/Oqtane.Server/Controllers/PageModuleController.cs index e9cabfba..ffb35623 100644 --- a/Oqtane.Server/Controllers/PageModuleController.cs +++ b/Oqtane.Server/Controllers/PageModuleController.cs @@ -11,22 +11,22 @@ using Oqtane.Security; namespace Oqtane.Controllers { - [Route(ControllerRoutes.Default)] + [Route(ControllerRoutes.ApiRoute)] public class PageModuleController : Controller { private readonly IPageModuleRepository _pageModules; private readonly IUserPermissions _userPermissions; - private readonly ITenantResolver _tenants; private readonly ISyncManager _syncManager; private readonly ILogManager _logger; + private readonly Alias _alias; - public PageModuleController(IPageModuleRepository pageModules, IUserPermissions userPermissions, ITenantResolver tenants, ISyncManager syncManager, ILogManager logger) + public PageModuleController(IPageModuleRepository pageModules, IUserPermissions userPermissions, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger) { _pageModules = pageModules; _userPermissions = userPermissions; - _tenants = tenants; _syncManager = syncManager; _logger = logger; + _alias = tenantManager.GetAlias(); } // GET api//5 @@ -71,7 +71,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Page, pageModule.PageId, PermissionNames.Edit)) { pageModule = _pageModules.AddPageModule(pageModule); - _syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, _tenants.GetAlias().SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId); _logger.Log(LogLevel.Information, this, LogFunction.Create, "Page Module Added {PageModule}", pageModule); } else @@ -91,7 +91,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Module, pageModule.ModuleId, PermissionNames.Edit)) { pageModule = _pageModules.UpdatePageModule(pageModule); - _syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, _tenants.GetAlias().SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId); _logger.Log(LogLevel.Information, this, LogFunction.Update, "Page Module Updated {PageModule}", pageModule); } else @@ -121,7 +121,7 @@ namespace Oqtane.Controllers } order += 2; } - _syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, _tenants.GetAlias().SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId); _logger.Log(LogLevel.Information, this, LogFunction.Update, "Page Module Order Updated {PageId} {Pane}", pageid, pane); } else @@ -140,7 +140,7 @@ namespace Oqtane.Controllers if (_userPermissions.IsAuthorized(User, EntityNames.Page, pagemodule.PageId, PermissionNames.Edit)) { _pageModules.DeletePageModule(id); - _syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, _tenants.GetAlias().SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Page Module Deleted {PageModuleId}", id); } else diff --git a/Oqtane.Server/Controllers/ProfileController.cs b/Oqtane.Server/Controllers/ProfileController.cs index 19411487..60b1de2d 100644 --- a/Oqtane.Server/Controllers/ProfileController.cs +++ b/Oqtane.Server/Controllers/ProfileController.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization; using Oqtane.Enums; @@ -9,7 +9,7 @@ using Oqtane.Repository; namespace Oqtane.Controllers { - [Route(ControllerRoutes.Default)] + [Route(ControllerRoutes.ApiRoute)] public class ProfileController : Controller { private readonly IProfileRepository _profiles; diff --git a/Oqtane.Server/Controllers/RoleController.cs b/Oqtane.Server/Controllers/RoleController.cs index 0e842509..1b6d9112 100644 --- a/Oqtane.Server/Controllers/RoleController.cs +++ b/Oqtane.Server/Controllers/RoleController.cs @@ -9,7 +9,7 @@ using Oqtane.Repository; namespace Oqtane.Controllers { - [Route(ControllerRoutes.Default)] + [Route(ControllerRoutes.ApiRoute)] public class RoleController : Controller { private readonly IRoleRepository _roles; diff --git a/Oqtane.Server/Controllers/SettingController.cs b/Oqtane.Server/Controllers/SettingController.cs index 71645a1b..b10a1534 100644 --- a/Oqtane.Server/Controllers/SettingController.cs +++ b/Oqtane.Server/Controllers/SettingController.cs @@ -10,24 +10,24 @@ using Oqtane.Repository; namespace Oqtane.Controllers { - [Route(ControllerRoutes.Default)] + [Route(ControllerRoutes.ApiRoute)] public class SettingController : Controller { private readonly ISettingRepository _settings; private readonly IPageModuleRepository _pageModules; private readonly IUserPermissions _userPermissions; - private readonly ITenantResolver _tenants; private readonly ISyncManager _syncManager; private readonly ILogManager _logger; + private readonly Alias _alias; - public SettingController(ISettingRepository settings, IPageModuleRepository pageModules, IUserPermissions userPermissions, ITenantResolver tenants, ISyncManager syncManager, ILogManager logger) + public SettingController(ISettingRepository settings, IPageModuleRepository pageModules, IUserPermissions userPermissions, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger) { _settings = settings; _pageModules = pageModules; _userPermissions = userPermissions; - _tenants = tenants; _syncManager = syncManager; _logger = logger; + _alias = tenantManager.GetAlias(); } // GET: api/ @@ -73,7 +73,7 @@ namespace Oqtane.Controllers setting = _settings.AddSetting(setting); if (setting.EntityName == EntityNames.Module) { - _syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, _tenants.GetAlias().SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId); } _logger.Log(LogLevel.Information, this, LogFunction.Create, "Setting Added {Setting}", setting); } @@ -95,7 +95,7 @@ namespace Oqtane.Controllers setting = _settings.UpdateSetting(setting); if (setting.EntityName == EntityNames.Module) { - _syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, _tenants.GetAlias().SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId); } _logger.Log(LogLevel.Information, this, LogFunction.Update, "Setting Updated {Setting}", setting); } @@ -118,7 +118,7 @@ namespace Oqtane.Controllers _settings.DeleteSetting(id); if (setting.EntityName == EntityNames.Module) { - _syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, _tenants.GetAlias().SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId); } _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Setting Deleted {Setting}", setting); } diff --git a/Oqtane.Server/Controllers/SiteController.cs b/Oqtane.Server/Controllers/SiteController.cs index 43a10dd1..e40e9065 100644 --- a/Oqtane.Server/Controllers/SiteController.cs +++ b/Oqtane.Server/Controllers/SiteController.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization; using Oqtane.Models; @@ -10,20 +10,20 @@ using Oqtane.Repository; namespace Oqtane.Controllers { - [Route(ControllerRoutes.Default)] + [Route(ControllerRoutes.ApiRoute)] public class SiteController : Controller { private readonly ISiteRepository _sites; - private readonly ITenantResolver _tenants; private readonly ISyncManager _syncManager; private readonly ILogManager _logger; + private readonly Alias _alias; - public SiteController(ISiteRepository sites, ITenantResolver tenants, ISyncManager syncManager, ILogManager logger) + public SiteController(ISiteRepository sites, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger) { _sites = sites; - _tenants = tenants; _syncManager = syncManager; _logger = logger; + _alias = tenantManager.GetAlias(); } // GET: api/ @@ -52,8 +52,7 @@ namespace Oqtane.Controllers { // provision initial site during installation authorized = true; - Tenant tenant = _tenants.GetTenant(); - site.TenantId = tenant.TenantId; + site.TenantId = _alias.TenantId; } else { @@ -76,7 +75,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid) { site = _sites.UpdateSite(site); - _syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.Site, site.SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, site.SiteId); _logger.Log(site.SiteId, LogLevel.Information, this, LogFunction.Update, "Site Updated {Site}", site); } return site; diff --git a/Oqtane.Server/Controllers/SiteTemplateController.cs b/Oqtane.Server/Controllers/SiteTemplateController.cs index abb9e19b..489541d0 100644 --- a/Oqtane.Server/Controllers/SiteTemplateController.cs +++ b/Oqtane.Server/Controllers/SiteTemplateController.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Oqtane.Models; @@ -7,7 +7,7 @@ using Oqtane.Shared; namespace Oqtane.Controllers { - [Route(ControllerRoutes.Default)] + [Route(ControllerRoutes.ApiRoute)] public class SiteTemplateController : Controller { private readonly ISiteTemplateRepository _siteTemplates; diff --git a/Oqtane.Server/Controllers/SqlController.cs b/Oqtane.Server/Controllers/SqlController.cs index d2a13078..7e24f041 100644 --- a/Oqtane.Server/Controllers/SqlController.cs +++ b/Oqtane.Server/Controllers/SqlController.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization; using Oqtane.Models; using System.Collections.Generic; @@ -11,7 +11,7 @@ using Microsoft.Data.SqlClient; namespace Oqtane.Controllers { - [Route(ControllerRoutes.Default)] + [Route(ControllerRoutes.ApiRoute)] public class SqlController : Controller { private readonly ITenantRepository _tenants; diff --git a/Oqtane.Server/Controllers/SystemController.cs b/Oqtane.Server/Controllers/SystemController.cs index 61c5593b..23658faa 100644 --- a/Oqtane.Server/Controllers/SystemController.cs +++ b/Oqtane.Server/Controllers/SystemController.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization; using System.Collections.Generic; using Oqtane.Shared; @@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Hosting; namespace Oqtane.Controllers { - [Route(ControllerRoutes.Default)] + [Route(ControllerRoutes.ApiRoute)] public class SystemController : Controller { private readonly IWebHostEnvironment _environment; diff --git a/Oqtane.Server/Controllers/TenantController.cs b/Oqtane.Server/Controllers/TenantController.cs index 6670d4dd..b6ef064d 100644 --- a/Oqtane.Server/Controllers/TenantController.cs +++ b/Oqtane.Server/Controllers/TenantController.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization; using Oqtane.Models; using System.Collections.Generic; @@ -9,7 +9,7 @@ using Oqtane.Repository; namespace Oqtane.Controllers { - [Route(ControllerRoutes.Default)] + [Route(ControllerRoutes.ApiRoute)] public class TenantController : Controller { private readonly ITenantRepository _tenants; diff --git a/Oqtane.Server/Controllers/ThemeController.cs b/Oqtane.Server/Controllers/ThemeController.cs index 6b2f7892..5bf8a2f3 100644 --- a/Oqtane.Server/Controllers/ThemeController.cs +++ b/Oqtane.Server/Controllers/ThemeController.cs @@ -16,7 +16,7 @@ using System.Text.Json; namespace Oqtane.Controllers { - [Route(ControllerRoutes.Default)] + [Route(ControllerRoutes.ApiRoute)] public class ThemeController : Controller { private readonly IThemeRepository _themes; diff --git a/Oqtane.Server/Controllers/UserController.cs b/Oqtane.Server/Controllers/UserController.cs index 4d3f1abc..cc1972c0 100644 --- a/Oqtane.Server/Controllers/UserController.cs +++ b/Oqtane.Server/Controllers/UserController.cs @@ -18,7 +18,7 @@ using Oqtane.Extensions; namespace Oqtane.Controllers { - [Route(ControllerRoutes.Default)] + [Route(ControllerRoutes.ApiRoute)] public class UserController : Controller { private readonly IUserRepository _users; @@ -26,26 +26,26 @@ namespace Oqtane.Controllers private readonly IUserRoleRepository _userRoles; private readonly UserManager _identityUserManager; private readonly SignInManager _identitySignInManager; - private readonly ITenantResolver _tenants; private readonly INotificationRepository _notifications; private readonly IFolderRepository _folders; private readonly ISyncManager _syncManager; private readonly ISiteRepository _sites; private readonly ILogManager _logger; + private readonly Alias _alias; - public UserController(IUserRepository users, IRoleRepository roles, IUserRoleRepository userRoles, UserManager identityUserManager, SignInManager identitySignInManager, ITenantResolver tenants, INotificationRepository notifications, IFolderRepository folders, ISyncManager syncManager, ISiteRepository sites, ILogManager logger) + public UserController(IUserRepository users, IRoleRepository roles, IUserRoleRepository userRoles, UserManager identityUserManager, SignInManager identitySignInManager, ITenantManager tenantManager, INotificationRepository notifications, IFolderRepository folders, ISyncManager syncManager, ISiteRepository sites, ILogManager logger) { _users = users; _roles = roles; _userRoles = userRoles; _identityUserManager = identityUserManager; _identitySignInManager = identitySignInManager; - _tenants = tenants; _folders = folders; _notifications = notifications; _syncManager = syncManager; _sites = sites; _logger = logger; + _alias = tenantManager.GetAlias(); } // GET api//5?siteid=x @@ -146,7 +146,7 @@ namespace Oqtane.Controllers if (!verified) { string token = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser); - string url = HttpContext.Request.Scheme + "://" + _tenants.GetAlias().Name + "/login?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token); + string url = HttpContext.Request.Scheme + "://" + _alias.Name + "/login?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token); string body = "Dear " + user.DisplayName + ",\n\nIn Order To Complete The Registration Of Your User Account Please Click The Link Displayed Below:\n\n" + url + "\n\nThank You!"; var notification = new Notification(user.SiteId, null, newUser, "User Account Verification", body, null); _notifications.AddNotification(notification); @@ -243,7 +243,7 @@ namespace Oqtane.Controllers } } user = _users.UpdateUser(user); - _syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.User, user.UserId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, user.UserId); user.Password = ""; // remove sensitive information _logger.Log(LogLevel.Information, this, LogFunction.Update, "User Updated {User}", user); } @@ -401,7 +401,7 @@ namespace Oqtane.Controllers if (identityuser != null) { string token = await _identityUserManager.GeneratePasswordResetTokenAsync(identityuser); - string url = HttpContext.Request.Scheme + "://" + _tenants.GetAlias().Name + "/reset?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token); + string url = HttpContext.Request.Scheme + "://" + _alias.Name + "/reset?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token); string body = "Dear " + user.DisplayName + ",\n\nPlease Click The Link Displayed Below To Reset Your Password:\n\n" + url + "\n\nThank You!"; var notification = new Notification(user.SiteId, null, user, "User Password Reset", body, null); _notifications.AddNotification(notification); diff --git a/Oqtane.Server/Controllers/UserRoleController.cs b/Oqtane.Server/Controllers/UserRoleController.cs index f7d9059d..99b1253f 100644 --- a/Oqtane.Server/Controllers/UserRoleController.cs +++ b/Oqtane.Server/Controllers/UserRoleController.cs @@ -10,22 +10,22 @@ using System.Linq; namespace Oqtane.Controllers { - [Route(ControllerRoutes.Default)] + [Route(ControllerRoutes.ApiRoute)] public class UserRoleController : Controller { private readonly IUserRoleRepository _userRoles; private readonly IRoleRepository _roles; - private readonly ITenantResolver _tenants; private readonly ISyncManager _syncManager; private readonly ILogManager _logger; + private readonly Alias _alias; - public UserRoleController(IUserRoleRepository userRoles, IRoleRepository roles, ITenantResolver tenants, ISyncManager syncManager, ILogManager logger) + public UserRoleController(IUserRoleRepository userRoles, IRoleRepository roles, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger) { _userRoles = userRoles; _roles = roles; _syncManager = syncManager; - _tenants = tenants; _logger = logger; + _alias = tenantManager.GetAlias(); } // GET: api/?siteid=x @@ -62,7 +62,7 @@ namespace Oqtane.Controllers userRole = _userRoles.AddUserRole(userRole); _logger.Log(LogLevel.Information, this, LogFunction.Create, "User Role Added {UserRole}", userRole); - _syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.User, userRole.UserId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, userRole.UserId); } return userRole; } @@ -76,7 +76,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid && (User.IsInRole(RoleNames.Host) || role.Name != RoleNames.Host)) { userRole = _userRoles.UpdateUserRole(userRole); - _syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.User, userRole.UserId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, userRole.UserId); _logger.Log(LogLevel.Information, this, LogFunction.Update, "User Role Updated {UserRole}", userRole); } return userRole; @@ -96,15 +96,15 @@ namespace Oqtane.Controllers if (userRole.Role.Name == RoleNames.Host) { // add site specific user roles to preserve user access - var role = _roles.GetRoles(_tenants.GetAlias().SiteId).FirstOrDefault(item => item.Name == RoleNames.Registered); + var role = _roles.GetRoles(_alias.SiteId).FirstOrDefault(item => item.Name == RoleNames.Registered); userRole = _userRoles.AddUserRole(new UserRole { UserId = userRole.UserId, RoleId = role.RoleId, EffectiveDate = null, ExpiryDate = null }); _logger.Log(LogLevel.Information, this, LogFunction.Create, "User Role Added {UserRole}", userRole); - role = _roles.GetRoles(_tenants.GetAlias().SiteId).FirstOrDefault(item => item.Name == RoleNames.Admin); + role = _roles.GetRoles(_alias.SiteId).FirstOrDefault(item => item.Name == RoleNames.Admin); userRole = _userRoles.AddUserRole(new UserRole { UserId = userRole.UserId, RoleId = role.RoleId, EffectiveDate = null, ExpiryDate = null }); _logger.Log(LogLevel.Information, this, LogFunction.Create, "User Role Added {UserRole}", userRole); } - _syncManager.AddSyncEvent(_tenants.GetTenant().TenantId, EntityNames.User, userRole.UserId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, userRole.UserId); } } } diff --git a/Oqtane.Server/Extensions/ApplicationBuilderExtensions.cs b/Oqtane.Server/Extensions/ApplicationBuilderExtensions.cs index 4f43068e..ea17e391 100644 --- a/Oqtane.Server/Extensions/ApplicationBuilderExtensions.cs +++ b/Oqtane.Server/Extensions/ApplicationBuilderExtensions.cs @@ -38,5 +38,8 @@ namespace Oqtane.Extensions return app; } + + public static IApplicationBuilder UseTenantResolution(this IApplicationBuilder builder) + => builder.UseMiddleware(); } } diff --git a/Oqtane.Server/Infrastructure/DatabaseManager.cs b/Oqtane.Server/Infrastructure/DatabaseManager.cs index e1f5606e..e70826ad 100644 --- a/Oqtane.Server/Infrastructure/DatabaseManager.cs +++ b/Oqtane.Server/Infrastructure/DatabaseManager.cs @@ -464,12 +464,12 @@ namespace Oqtane.Infrastructure { using (var scope = _serviceScopeFactory.CreateScope()) { - // use the SiteState to set the Alias explicitly so the tenant can be resolved + // set the alias explicitly so the tenant can be resolved var aliases = scope.ServiceProvider.GetRequiredService(); var firstAlias = install.Aliases.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)[0]; var alias = aliases.GetAliases().FirstOrDefault(item => item.Name == firstAlias); - var siteState = scope.ServiceProvider.GetRequiredService(); - siteState.Alias = alias; + var tenantManager = scope.ServiceProvider.GetRequiredService(); + tenantManager.SetAlias(alias); var sites = scope.ServiceProvider.GetRequiredService(); var site = sites.GetSites().FirstOrDefault(item => item.Name == install.SiteName); diff --git a/Oqtane.Server/Infrastructure/Interfaces/ITenantManager.cs b/Oqtane.Server/Infrastructure/Interfaces/ITenantManager.cs new file mode 100644 index 00000000..b1a4892b --- /dev/null +++ b/Oqtane.Server/Infrastructure/Interfaces/ITenantManager.cs @@ -0,0 +1,12 @@ +using Oqtane.Models; + +namespace Oqtane.Infrastructure +{ + public interface ITenantManager + { + Alias GetAlias(); + Tenant GetTenant(); + void SetAlias(Alias alias); + void SetTenant(int tenantId); + } +} diff --git a/Oqtane.Server/Infrastructure/Jobs/HostedServiceBase.cs b/Oqtane.Server/Infrastructure/Jobs/HostedServiceBase.cs index 449f7ae3..9e01968a 100644 --- a/Oqtane.Server/Infrastructure/Jobs/HostedServiceBase.cs +++ b/Oqtane.Server/Infrastructure/Jobs/HostedServiceBase.cs @@ -92,11 +92,12 @@ namespace Oqtane.Infrastructure try { var notes = ""; - var tenants = scope.ServiceProvider.GetRequiredService(); - var siteState = scope.ServiceProvider.GetRequiredService(); - foreach (var tenant in tenants.GetTenants()) + var tenantRepository = scope.ServiceProvider.GetRequiredService(); + var tenantManager = scope.ServiceProvider.GetRequiredService(); + foreach (var tenant in tenantRepository.GetTenants()) { - siteState.Alias = new Alias { TenantId = tenant.TenantId }; + // set tenant and execute job + tenantManager.SetTenant(tenant.TenantId); notes += ExecuteJob(scope.ServiceProvider); } log.Notes = notes; diff --git a/Oqtane.Server/Infrastructure/LogManager.cs b/Oqtane.Server/Infrastructure/LogManager.cs index 648f873f..7ee8cf4a 100644 --- a/Oqtane.Server/Infrastructure/LogManager.cs +++ b/Oqtane.Server/Infrastructure/LogManager.cs @@ -14,18 +14,18 @@ namespace Oqtane.Infrastructure public class LogManager : ILogManager { private readonly ILogRepository _logs; - private readonly ITenantResolver _tenantResolver; private readonly IConfigurationRoot _config; private readonly IUserPermissions _userPermissions; private readonly IHttpContextAccessor _accessor; + private readonly Alias _alias; - public LogManager(ILogRepository logs, ITenantResolver tenantResolver, IConfigurationRoot config, IUserPermissions userPermissions, IHttpContextAccessor accessor) + public LogManager(ILogRepository logs, ITenantManager tenantManager, IConfigurationRoot config, IUserPermissions userPermissions, IHttpContextAccessor accessor) { _logs = logs; - _tenantResolver = tenantResolver; _config = config; _userPermissions = userPermissions; _accessor = accessor; + _alias = tenantManager.GetAlias(); } public void Log(LogLevel level, object @class, LogFunction function, string message, params object[] args) @@ -49,10 +49,9 @@ namespace Oqtane.Infrastructure if (siteId == -1) { log.SiteId = null; - Alias alias = _tenantResolver.GetAlias(); - if (alias != null) + if (_alias != null) { - log.SiteId = alias.SiteId; + log.SiteId = _alias.SiteId; } } else diff --git a/Oqtane.Server/Infrastructure/Middleware/TenantMiddleware.cs b/Oqtane.Server/Infrastructure/Middleware/TenantMiddleware.cs new file mode 100644 index 00000000..189a44c9 --- /dev/null +++ b/Oqtane.Server/Infrastructure/Middleware/TenantMiddleware.cs @@ -0,0 +1,41 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; + +namespace Oqtane.Infrastructure +{ + internal class TenantMiddleware + { + private readonly RequestDelegate next; + + public TenantMiddleware(RequestDelegate next) + { + this.next = next; + } + + public async Task Invoke(HttpContext context) + { + // check if framework is installed + var config = context.RequestServices.GetService(typeof(IConfiguration)) as IConfiguration; + if (!string.IsNullOrEmpty(config.GetConnectionString("DefaultConnection"))) + { + // get alias + var tenantManager = context.RequestServices.GetService(typeof(ITenantManager)) as ITenantManager; + var alias = tenantManager.GetAlias(); + + // rewrite path by removing alias path prefix from api and pages requests + if (alias != null && !string.IsNullOrEmpty(alias.Path)) + { + string path = context.Request.Path.ToString(); + if (path.StartsWith("/" + alias.Path) && (path.Contains("/api/") || path.Contains("/pages/"))) + { + context.Request.Path = path.Replace("/" + alias.Path, ""); + } + } + } + + // continue processing + if (next != null) await next(context); + } + } +} diff --git a/Oqtane.Server/Infrastructure/TenantManager.cs b/Oqtane.Server/Infrastructure/TenantManager.cs new file mode 100644 index 00000000..7f0470f8 --- /dev/null +++ b/Oqtane.Server/Infrastructure/TenantManager.cs @@ -0,0 +1,87 @@ +using System; +using System.Linq; +using Microsoft.AspNetCore.Http; +using Oqtane.Models; +using Oqtane.Repository; +using Oqtane.Shared; + +namespace Oqtane.Infrastructure +{ + public class TenantManager : ITenantManager + { + private readonly IHttpContextAccessor _httpContextAccessor; + private readonly IAliasRepository _aliasRepository; + private readonly ITenantRepository _tenantRepository; + private readonly SiteState _siteState; + + public TenantManager(IHttpContextAccessor httpContextAccessor, IAliasRepository aliasRepository, ITenantRepository tenantRepository, SiteState siteState) + { + _httpContextAccessor = httpContextAccessor; + _aliasRepository = aliasRepository; + _tenantRepository = tenantRepository; + _siteState = siteState; + } + + public Alias GetAlias() + { + Alias alias = null; + + if (_siteState != null && _siteState.Alias != null) + { + alias = _siteState.Alias; + } + else + { + // if there is http context + if (_httpContextAccessor.HttpContext != null) + { + // legacy support for client api requests which would include the alias as a path prefix ( ie. {alias}/api/[controller] ) + int aliasId; + string[] segments = _httpContextAccessor.HttpContext.Request.Path.Value.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); + if (segments.Length > 1 && (segments[1] == "api" || segments[1] == "pages") && int.TryParse(segments[0], out aliasId)) + { + alias = _aliasRepository.GetAliases().ToList().FirstOrDefault(item => item.AliasId == aliasId); + } + + // resolve alias based on host name and path + if (alias == null) + { + string name = _httpContextAccessor.HttpContext.Request.Host.Value + _httpContextAccessor.HttpContext.Request.Path; + alias = _aliasRepository.GetAlias(name); + } + + // if there is a match save it + if (alias != null) + { + _siteState.Alias = alias; + } + } + } + + return alias; + } + + public Tenant GetTenant() + { + var alias = GetAlias(); + if (alias != null) + { + // return tenant details + return _tenantRepository.GetTenants().ToList().FirstOrDefault(item => item.TenantId == alias.TenantId); + } + return null; + } + + public void SetAlias(Alias alias) + { + // background processes can set the alias using the SiteState service + _siteState.Alias = alias; + } + + public void SetTenant(int tenantId) + { + // background processes can set the alias using the SiteState service + _siteState.Alias = new Alias { TenantId = tenantId }; + } + } +} diff --git a/Oqtane.Server/Infrastructure/UpgradeManager.cs b/Oqtane.Server/Infrastructure/UpgradeManager.cs index 5919be0b..184abd3d 100644 --- a/Oqtane.Server/Infrastructure/UpgradeManager.cs +++ b/Oqtane.Server/Infrastructure/UpgradeManager.cs @@ -27,9 +27,9 @@ namespace Oqtane.Infrastructure // core framework upgrade logic - executed for every tenant using (var scope = _serviceScopeFactory.CreateScope()) { - // set SiteState based on tenant - var siteState = scope.ServiceProvider.GetRequiredService(); - siteState.Alias = new Alias { TenantId = tenant.TenantId }; + // set tenant + var tenantManager = scope.ServiceProvider.GetRequiredService(); + tenantManager.SetTenant(tenant.TenantId); switch (version) { diff --git a/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs b/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs index eeabff6d..e321b76b 100644 --- a/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs +++ b/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs @@ -1,6 +1,5 @@ -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization; -using Oqtane.Modules.HtmlText.Models; using Oqtane.Modules.HtmlText.Repository; using Microsoft.AspNetCore.Http; using Oqtane.Shared; @@ -12,7 +11,7 @@ using Oqtane.Controllers; namespace Oqtane.Modules.HtmlText.Controllers { - [Route(ControllerRoutes.Default)] + [Route(ControllerRoutes.ApiRoute)] public class HtmlTextController : ModuleControllerBase { private readonly IHtmlTextRepository _htmlText; diff --git a/Oqtane.Server/Modules/HtmlText/Repository/HtmlTextContext.cs b/Oqtane.Server/Modules/HtmlText/Repository/HtmlTextContext.cs index cd62722f..10199b8d 100644 --- a/Oqtane.Server/Modules/HtmlText/Repository/HtmlTextContext.cs +++ b/Oqtane.Server/Modules/HtmlText/Repository/HtmlTextContext.cs @@ -1,8 +1,6 @@ -using System.Collections.Generic; using Microsoft.EntityFrameworkCore; -using Oqtane.Modules.HtmlText.Models; +using Oqtane.Infrastructure; using Oqtane.Repository; -using Oqtane.Interfaces; using Oqtane.Repository.Databases.Interfaces; // ReSharper disable MemberCanBePrivate.Global @@ -12,7 +10,7 @@ namespace Oqtane.Modules.HtmlText.Repository { public class HtmlTextContext : DBContextBase, IService, IMultiDatabase { - public HtmlTextContext(IDbConfig dbConfig, ITenantResolver tenantResolver) : base(dbConfig, tenantResolver) + public HtmlTextContext(IDbConfig dbConfig, ITenantManager tenantManager) : base(dbConfig, tenantManager) { } diff --git a/Oqtane.Server/Pages/Login.cshtml b/Oqtane.Server/Pages/Login.cshtml index 92433015..c533e32d 100644 --- a/Oqtane.Server/Pages/Login.cshtml +++ b/Oqtane.Server/Pages/Login.cshtml @@ -1,3 +1,3 @@ -@page "/{alias}/pages/login" +@page "/pages/login" @namespace Oqtane.Pages @model Oqtane.Pages.LoginModel diff --git a/Oqtane.Server/Pages/Logout.cshtml b/Oqtane.Server/Pages/Logout.cshtml index d477046c..eaf983cc 100644 --- a/Oqtane.Server/Pages/Logout.cshtml +++ b/Oqtane.Server/Pages/Logout.cshtml @@ -1,3 +1,3 @@ -@page "/{alias}/pages/logout" +@page "/pages/logout" @namespace Oqtane.Pages @model Oqtane.Pages.LogoutModel diff --git a/Oqtane.Server/Pages/_Host.cshtml b/Oqtane.Server/Pages/_Host.cshtml index 74b13c99..df1d7a3a 100644 --- a/Oqtane.Server/Pages/_Host.cshtml +++ b/Oqtane.Server/Pages/_Host.cshtml @@ -22,7 +22,7 @@ @(Html.AntiForgeryToken()) - +
diff --git a/Oqtane.Server/Pages/_Host.cshtml.cs b/Oqtane.Server/Pages/_Host.cshtml.cs index 156b5fac..5bec6d08 100644 --- a/Oqtane.Server/Pages/_Host.cshtml.cs +++ b/Oqtane.Server/Pages/_Host.cshtml.cs @@ -8,7 +8,6 @@ using System; using System.Globalization; using System.Linq; using System.Reflection; -using Microsoft.AspNetCore.Http.Extensions; using Oqtane.Repository; using Microsoft.AspNetCore.Localization; using Microsoft.Extensions.Configuration; @@ -18,21 +17,18 @@ namespace Oqtane.Pages public class HostModel : PageModel { private IConfiguration _configuration; - private readonly SiteState _state; - private readonly IAliasRepository _aliases; + private readonly ITenantManager _tenantManager; private readonly ILocalizationManager _localizationManager; private readonly ILanguageRepository _languages; public HostModel( IConfiguration configuration, - SiteState state, - IAliasRepository aliases, + ITenantManager tenantManager, ILocalizationManager localizationManager, ILanguageRepository languages) { _configuration = configuration; - _state = state; - _aliases = aliases; + _tenantManager = tenantManager; _localizationManager = localizationManager; _languages = languages; } @@ -54,19 +50,14 @@ namespace Oqtane.Pages // if culture not specified and framework is installed if (HttpContext.Request.Cookies[CookieRequestCultureProvider.DefaultCookieName] == null && !string.IsNullOrEmpty(_configuration.GetConnectionString("DefaultConnection"))) { - var uri = new Uri(Request.GetDisplayUrl()); - var hostname = uri.Authority + "/" + uri.LocalPath.Substring(1); - var alias = _aliases.GetAlias(hostname); + var alias = _tenantManager.GetAlias(); if (alias != null) { - _state.Alias = alias; - // set default language for site if the culture is not supported var languages = _languages.GetLanguages(alias.SiteId); if (languages.Any() && languages.All(l => l.Code != CultureInfo.CurrentUICulture.Name)) { var defaultLanguage = languages.Where(l => l.IsDefault).SingleOrDefault() ?? languages.First(); - SetLocalizationCookie(defaultLanguage.Code); } else @@ -74,10 +65,6 @@ namespace Oqtane.Pages SetLocalizationCookie(_localizationManager.GetDefaultCulture()); } } - else - { - Message = $"No Matching Alias For Host Name {hostname}"; - } } } diff --git a/Oqtane.Server/Repository/AliasRepository.cs b/Oqtane.Server/Repository/AliasRepository.cs index cbec2452..619724dc 100644 --- a/Oqtane.Server/Repository/AliasRepository.cs +++ b/Oqtane.Server/Repository/AliasRepository.cs @@ -55,17 +55,28 @@ namespace Oqtane.Repository List aliases = GetAliases().ToList(); var segments = name.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); - // iterate segments in reverse order - for (int i = segments.Length; i > 0; i--) + // iterate segments to find keywords + int start = segments.Length; + for (int i = 0; i < segments.Length; i++) { - name = string.Join("/", segments, 0, i); - alias = aliases.Find(item => item.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); + if (segments[i] == "api" || segments[i] == "pages" || segments[i] == "*") + { + start = i; + break; + } + } + + // iterate segments in reverse order to find alias match + for (int i = start; i > 0; i--) + { + alias = aliases.Find(item => item.Name.Equals(string.Join("/", segments, 0, i), StringComparison.OrdinalIgnoreCase)); if (alias != null) { break; // found a matching alias } } - // return fallback alias + + // return fallback alias if none found return alias ?? aliases.Find(item => item.Name.Equals("*")); } diff --git a/Oqtane.Server/Repository/Context/DBContextBase.cs b/Oqtane.Server/Repository/Context/DBContextBase.cs index d3066502..1a5a536c 100644 --- a/Oqtane.Server/Repository/Context/DBContextBase.cs +++ b/Oqtane.Server/Repository/Context/DBContextBase.cs @@ -8,9 +8,10 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.Extensions.Configuration; using Oqtane.Extensions; +using Oqtane.Infrastructure; using Oqtane.Interfaces; using Oqtane.Migrations.Framework; -using Oqtane.Repository.Databases.Interfaces; +using Oqtane.Models; using Oqtane.Shared; // ReSharper disable BuiltInTypeReferenceStyleForMemberAccess @@ -20,26 +21,27 @@ namespace Oqtane.Repository public class DBContextBase : IdentityUserContext { private readonly ITenantResolver _tenantResolver; + private readonly ITenantManager _tenantManager; private readonly IHttpContextAccessor _accessor; private readonly IConfiguration _configuration; private string _connectionString; private string _databaseType; - public DBContextBase(ITenantResolver tenantResolver, IHttpContextAccessor httpContextAccessor) + public DBContextBase(ITenantManager tenantManager, IHttpContextAccessor httpContextAccessor) { _connectionString = String.Empty; - _tenantResolver = tenantResolver; + _tenantManager = tenantManager; _accessor = httpContextAccessor; } - public DBContextBase(IDbConfig dbConfig, ITenantResolver tenantResolver) + public DBContextBase(IDbConfig dbConfig, ITenantManager tenantManager) { _accessor = dbConfig.Accessor; _configuration = dbConfig.Configuration; _connectionString = dbConfig.ConnectionString; _databaseType = dbConfig.DatabaseType; Databases = dbConfig.Databases; - _tenantResolver = tenantResolver; + _tenantManager = tenantManager; } public IEnumerable Databases { get; } @@ -48,9 +50,18 @@ namespace Oqtane.Repository { optionsBuilder.ReplaceService(); - if (string.IsNullOrEmpty(_connectionString) && _tenantResolver != null) + if (string.IsNullOrEmpty(_connectionString)) { - var tenant = _tenantResolver.GetTenant(); + + Tenant tenant; + if (_tenantResolver != null) + { + tenant = _tenantResolver.GetTenant(); + } + else + { + tenant = _tenantManager.GetTenant(); + } if (tenant != null) { @@ -103,5 +114,25 @@ namespace Oqtane.Repository return base.SaveChanges(); } + + [Obsolete("This constructor is obsolete. Use DBContextBase(ITenantManager tenantManager, IHttpContextAccessor httpContextAccessor) instead.", false)] + public DBContextBase(ITenantResolver tenantResolver, IHttpContextAccessor httpContextAccessor) + { + _connectionString = String.Empty; + _tenantResolver = tenantResolver; + _accessor = httpContextAccessor; + } + + [Obsolete("This constructor is obsolete. Use DBContextBase(IDbConfig dbConfig, ITenantManager tenantManager) instead.", false)] + public DBContextBase(IDbConfig dbConfig, ITenantResolver tenantResolver) + { + _accessor = dbConfig.Accessor; + _configuration = dbConfig.Configuration; + _connectionString = dbConfig.ConnectionString; + _databaseType = dbConfig.DatabaseType; + Databases = dbConfig.Databases; + _tenantResolver = tenantResolver; + } + } } diff --git a/Oqtane.Server/Repository/Context/TenantDBContext.cs b/Oqtane.Server/Repository/Context/TenantDBContext.cs index 8aa6ccc2..f4d554c0 100644 --- a/Oqtane.Server/Repository/Context/TenantDBContext.cs +++ b/Oqtane.Server/Repository/Context/TenantDBContext.cs @@ -1,6 +1,5 @@ -using System.Collections.Generic; using Microsoft.EntityFrameworkCore; -using Oqtane.Interfaces; +using Oqtane.Infrastructure; using Oqtane.Models; using Oqtane.Repository.Databases.Interfaces; @@ -12,7 +11,7 @@ namespace Oqtane.Repository { public class TenantDBContext : DBContextBase, IMultiDatabase { - public TenantDBContext(IDbConfig dbConfig, ITenantResolver tenantResolver) : base(dbConfig, tenantResolver) { } + public TenantDBContext(IDbConfig dbConfig, ITenantManager tenantManager) : base(dbConfig, tenantManager) { } public virtual DbSet Site { get; set; } public virtual DbSet Page { get; set; } diff --git a/Oqtane.Server/Repository/Interfaces/ITenantResolver.cs b/Oqtane.Server/Repository/Interfaces/ITenantResolver.cs index 95e916f7..bc3a48eb 100644 --- a/Oqtane.Server/Repository/Interfaces/ITenantResolver.cs +++ b/Oqtane.Server/Repository/Interfaces/ITenantResolver.cs @@ -1,7 +1,8 @@ -using Oqtane.Models; +using Oqtane.Models; namespace Oqtane.Repository { + // class deprecated and replaced by ITenantManager public interface ITenantResolver { Alias GetAlias(); diff --git a/Oqtane.Server/Repository/TenantResolver.cs b/Oqtane.Server/Repository/TenantResolver.cs index 815a8c55..793006d3 100644 --- a/Oqtane.Server/Repository/TenantResolver.cs +++ b/Oqtane.Server/Repository/TenantResolver.cs @@ -1,78 +1,26 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.AspNetCore.Http; +using Oqtane.Infrastructure; using Oqtane.Models; -using Oqtane.Shared; namespace Oqtane.Repository { + // class deprecated and replaced by ITenantManager public class TenantResolver : ITenantResolver { - private readonly IHttpContextAccessor _accessor; - private readonly IAliasRepository _aliasRepository; - private readonly ITenantRepository _tenantRepository; - private readonly SiteState _siteState; + private readonly ITenantManager _tenantManager; - private Alias _alias; - private Tenant _tenant; - - public TenantResolver(IHttpContextAccessor accessor, IAliasRepository aliasRepository, ITenantRepository tenantRepository, SiteState siteState) + public TenantResolver(ITenantManager tenantManager) { - _accessor = accessor; - _aliasRepository = aliasRepository; - _tenantRepository = tenantRepository; - _siteState = siteState; + _tenantManager = tenantManager; } public Alias GetAlias() { - if (_alias == null) ResolveTenant(); - return _alias; + return _tenantManager.GetAlias(); } public Tenant GetTenant() { - if (_tenant == null) ResolveTenant(); - return _tenant; - } - - private void ResolveTenant() - { - if (_siteState != null && _siteState.Alias != null) - { - // background processes can pass in an alias using the SiteState service - _alias = _siteState.Alias; - } - else - { - int aliasId = -1; - - // get aliasid identifier based on request - if (_accessor.HttpContext != null) - { - string[] segments = _accessor.HttpContext.Request.Path.Value.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); - if (segments.Length > 1 && (segments[1] == "api" || segments[1] == "pages") && segments[0] != "~") - { - aliasId = int.Parse(segments[0]); - } - } - - // get the alias - IEnumerable aliases = _aliasRepository.GetAliases().ToList(); // cached - if (aliasId != -1) - { - _alias = aliases.FirstOrDefault(item => item.AliasId == aliasId); - } - } - - if (_alias != null) - { - // get the tenant - IEnumerable tenants = _tenantRepository.GetTenants(); // cached - _tenant = tenants.FirstOrDefault(item => item.TenantId == _alias.TenantId); - } - + return _tenantManager.GetTenant(); } } } diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index 881d3e91..f33a6e91 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -1,5 +1,4 @@ using System; -using System.Collections; using System.IO; using System.Linq; using System.Net.Http; @@ -10,7 +9,6 @@ using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; -using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -126,6 +124,7 @@ namespace Oqtane services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddSingleton(); @@ -175,13 +174,13 @@ namespace Oqtane services.AddSingleton(); // install any modules or themes ( this needs to occur BEFORE the assemblies are loaded into the app domain ) - InstallationManager.InstallPackages("Modules,Themes", _env.WebRootPath, _env.ContentRootPath); + InstallationManager.InstallPackages("Modules,Themes,Packages", _env.WebRootPath, _env.ContentRootPath); // register transient scoped core services + services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); - services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); @@ -206,6 +205,8 @@ namespace Oqtane services.AddTransient(); services.AddTransient(); services.AddTransient(); + // obsolete - replaced by ITenantManager + services.AddTransient(); // load the external assemblies into the app domain, install services services.AddOqtane(_runtime, _supportedCultures); @@ -240,7 +241,8 @@ namespace Oqtane // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } - // to allow install middleware it should be moved up + + // execute any IServerStartup logic app.ConfigureOqtaneAssemblies(env); // Allow oqtane localization middleware @@ -248,6 +250,7 @@ namespace Oqtane app.UseHttpsRedirection(); app.UseStaticFiles(); + app.UseTenantResolution(); // must be declared directly after static files app.UseBlazorFrameworkFiles(); app.UseRouting(); app.UseAuthentication(); @@ -255,7 +258,7 @@ namespace Oqtane if (_useSwagger) { app.UseSwagger(); - app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "Oqtane V1"); }); + app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "Oqtane " + Constants.Version); }); } app.UseEndpoints(endpoints => diff --git a/Oqtane.Server/wwwroot/Modules/Oqtane.Blogs/Module.css b/Oqtane.Server/wwwroot/Modules/Oqtane.Blogs/Module.css deleted file mode 100644 index 0856a263..00000000 --- a/Oqtane.Server/wwwroot/Modules/Oqtane.Blogs/Module.css +++ /dev/null @@ -1 +0,0 @@ -/* Module Custom Styles */ \ No newline at end of file diff --git a/Oqtane.Server/wwwroot/Modules/Oqtane.Blogs/Module.js b/Oqtane.Server/wwwroot/Modules/Oqtane.Blogs/Module.js deleted file mode 100644 index 1b415a08..00000000 --- a/Oqtane.Server/wwwroot/Modules/Oqtane.Blogs/Module.js +++ /dev/null @@ -1 +0,0 @@ -/* Module Script */ \ No newline at end of file diff --git a/Oqtane.Server/wwwroot/Modules/Oqtane.Blogs/assets.json b/Oqtane.Server/wwwroot/Modules/Oqtane.Blogs/assets.json deleted file mode 100644 index 72f421fc..00000000 --- a/Oqtane.Server/wwwroot/Modules/Oqtane.Blogs/assets.json +++ /dev/null @@ -1 +0,0 @@ -["\\bin\\Debug\\net5.0\\Oqtane.Blogs.Client.Oqtane.dll","\\bin\\Debug\\net5.0\\Oqtane.Blogs.Client.Oqtane.pdb","\\bin\\Debug\\net5.0\\Oqtane.Blogs.Server.Oqtane.dll","\\bin\\Debug\\net5.0\\Oqtane.Blogs.Server.Oqtane.pdb","\\bin\\Debug\\net5.0\\Oqtane.Blogs.Shared.Oqtane.dll","\\bin\\Debug\\net5.0\\Oqtane.Blogs.Shared.Oqtane.pdb","\\wwwroot\\Modules\\Oqtane.Blogs\\Module.css","\\wwwroot\\Modules\\Oqtane.Blogs\\Module.js"] \ No newline at end of file diff --git a/Oqtane.Shared/Shared/ControllerRoutes.cs b/Oqtane.Shared/Shared/ControllerRoutes.cs index 07e170f3..aa5bbe6b 100644 --- a/Oqtane.Shared/Shared/ControllerRoutes.cs +++ b/Oqtane.Shared/Shared/ControllerRoutes.cs @@ -1,9 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Oqtane.Shared { +namespace Oqtane.Shared { public class ControllerRoutes { public const string Default = "{alias}/api/[controller]"; + public const string ApiRoute = "api/[controller]"; } } diff --git a/Oqtane.Shared/Shared/Utilities.cs b/Oqtane.Shared/Shared/Utilities.cs index 3de29f59..ec7e2d4a 100644 --- a/Oqtane.Shared/Shared/Utilities.cs +++ b/Oqtane.Shared/Shared/Utilities.cs @@ -1,4 +1,4 @@ -using Oqtane.Models; +using Oqtane.Models; using System; using System.Collections.Generic; using System.Globalization; @@ -102,7 +102,7 @@ namespace Oqtane.Shared public static string ContentUrl(Alias alias, int fileId, bool asAttachment) { - var aliasUrl = (alias == null) ? "/~" : "/" + alias.AliasId; + var aliasUrl = (alias != null && !string.IsNullOrEmpty(alias.Path)) ? "/" + alias.Path : ""; var method = asAttachment ? "/attach":""; return $"{aliasUrl}{Constants.ContentUrl}{fileId}{method}"; diff --git a/README.md b/README.md index 19073205..55bf873c 100644 --- a/README.md +++ b/README.md @@ -49,9 +49,16 @@ There is a separate [Documentation repository](https://github.com/oqtane/oqtane. # Roadmap This project is a work in progress and the schedule for implementing enhancements is dependent upon the availability of community members who are willing/able to assist. +V.3.0.0 ( Nov 2021 ) +- [ ] Migration to .NET 6 + +V.2.2.0 ( Aug 2021 ) +- [ ] Alternate Authentication Providers ( ie. Azure B2C, Social logins, etc... ) +- [ ] Configurable password complexity for local authentication + V.2.1.0 ( May 2021 ) -- [ ] Cross Platform Database Support ( ie. SQLite ) - see [#964](https://github.com/oqtane/oqtane.framework/discussions/964) -- [ ] EF Core Migrations for Database Installation/Upgrade - see [#964](https://github.com/oqtane/oqtane.framework/discussions/964) +- [ ] Cross Platform Database Support ( ie. SQLite, MySQL, PostreSQL ) - see [#964](https://github.com/oqtane/oqtane.framework/discussions/964) +- [ ] EF Core Migrations - see [#964](https://github.com/oqtane/oqtane.framework/discussions/964) V.2.0.2 ( Apr 19, 2021 ) - [x] Assorted fixes and user experience improvements