diff --git a/Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs index c5590d51..eae6ba0f 100644 --- a/Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs @@ -53,6 +53,7 @@ namespace Microsoft.Extensions.DependencyInjection services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddScoped(); // providers diff --git a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor index f993a7c1..95ecbd52 100644 --- a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor +++ b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor @@ -9,6 +9,7 @@ @inject INotificationService NotificationService @inject IFileService FileService @inject IFolderService FolderService +@inject ITimeZoneService TimeZoneService @inject IJSRuntime jsRuntime @inject IServiceProvider ServiceProvider @inject IStringLocalizer Localizer @@ -366,7 +367,6 @@ } @code { - private List _timezones; private bool _initialized = false; private string _passwordrequirements; private string _username = string.Empty; @@ -380,6 +380,7 @@ private string _displayname = string.Empty; private FileManager _filemanager; private int _folderid = -1; + private List _timezones; private string _timezoneid = string.Empty; private int _photofileid = -1; private File _photo = null; @@ -403,7 +404,7 @@ _togglepassword = SharedLocalizer["ShowPassword"]; _allowtwofactor = (SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:TwoFactor", "false") == "true"); _profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId); - _timezones = Utilities.GetTimeZones(); + _timezones = TimeZoneService.GetTimeZones(); if (PageState.User != null) { diff --git a/Oqtane.Client/Resources/TimeZoneResources.resx b/Oqtane.Client/Resources/TimeZoneResources.resx new file mode 100644 index 00000000..d736dcea --- /dev/null +++ b/Oqtane.Client/Resources/TimeZoneResources.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + (UTC) Coordinated Universal Time + + + (UTC-05:00) Eastern Time (US & Canada) + + + (UTC-08:00) Pacific Time (US & Canada) + + \ No newline at end of file diff --git a/Oqtane.Client/Services/Interfaces/ITimeZoneService.cs b/Oqtane.Client/Services/Interfaces/ITimeZoneService.cs new file mode 100644 index 00000000..de134838 --- /dev/null +++ b/Oqtane.Client/Services/Interfaces/ITimeZoneService.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using Oqtane.Models; + +namespace Oqtane.Services +{ + /// + /// Service to retrieve entries + /// + public interface ITimeZoneService + { + /// + /// Get the list of time zones + /// + /// + List GetTimeZones(); + } +} diff --git a/Oqtane.Client/Services/TimeZoneService.cs b/Oqtane.Client/Services/TimeZoneService.cs new file mode 100644 index 00000000..f6cab35b --- /dev/null +++ b/Oqtane.Client/Services/TimeZoneService.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.Localization; +using Oqtane.Documentation; +using Oqtane.Models; +using Oqtane.Shared; + +namespace Oqtane.Services +{ + [PrivateApi("Don't show in the documentation, as everything should use the Interface")] + public class TimeZoneService : ITimeZoneService + { + private readonly IStringLocalizer _TimeZoneLocalizer; + + public TimeZoneService(IStringLocalizer TimeZoneLocalizer) + { + _TimeZoneLocalizer = TimeZoneLocalizer; + } + + public List GetTimeZones() + { + var _timezones = new List(); + foreach (var timezone in Utilities.GetTimeZones()) + { + _timezones.Add(new TimeZone + { + Id = timezone.Id, + DisplayName = _TimeZoneLocalizer[timezone.Id] + }); + } + return _timezones.OrderBy(item => item.DisplayName).ToList(); + } + } +} diff --git a/Oqtane.Client/TimeZoneResources.cs b/Oqtane.Client/TimeZoneResources.cs new file mode 100644 index 00000000..cd0125fd --- /dev/null +++ b/Oqtane.Client/TimeZoneResources.cs @@ -0,0 +1,14 @@ +namespace Oqtane +{ + /// + /// Dummy class used to collect shared resource strings for this application + /// + /// + /// This class is mostly used with IStringLocalizer and IHtmlLocalizer interfaces. + /// The class must reside at the project root. + /// + public class TimeZoneResources + { + + } +} diff --git a/Oqtane.Database.MySQL/MySQLDatabase.cs b/Oqtane.Database.MySQL/MySQLDatabase.cs index a3b8d307..2f50c1d4 100644 --- a/Oqtane.Database.MySQL/MySQLDatabase.cs +++ b/Oqtane.Database.MySQL/MySQLDatabase.cs @@ -75,13 +75,9 @@ namespace Oqtane.Database.MySQL return dr; } - public override string RewriteName(string name, bool isQuery) + public override string DelimitName(string name) { - if (name.ToLower() == "rows" && isQuery) - { - name = $"`{name}`"; // escape reserved word in SQL query - } - return name; + return $"`{name}`"; } public override DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString) diff --git a/Oqtane.Database.PostgreSQL/PostgreSQLDatabase.cs b/Oqtane.Database.PostgreSQL/PostgreSQLDatabase.cs index a9e6e0d8..7e20a86d 100644 --- a/Oqtane.Database.PostgreSQL/PostgreSQLDatabase.cs +++ b/Oqtane.Database.PostgreSQL/PostgreSQLDatabase.cs @@ -87,9 +87,9 @@ namespace Oqtane.Database.PostgreSQL return _rewriter.RewriteName(name); } - public override string RewriteName(string name, bool isQuery) + public override string DelimitName(string name) { - return _rewriter.RewriteName(name); + return $"\"{name}\""; } public override string RewriteValue(string value, string type) diff --git a/Oqtane.Database.SqlServer/SqlServerDatabase.cs b/Oqtane.Database.SqlServer/SqlServerDatabase.cs index a7d8f641..7f52b8be 100644 --- a/Oqtane.Database.SqlServer/SqlServerDatabase.cs +++ b/Oqtane.Database.SqlServer/SqlServerDatabase.cs @@ -46,6 +46,11 @@ namespace Oqtane.Database.SqlServer } } + public override string DelimitName(string name) + { + return $"[{name}]"; + } + public override int ExecuteNonQuery(string connectionString, string query) { var conn = new SqlConnection(FormatConnectionString(connectionString)); diff --git a/Oqtane.Database.Sqlite/SqliteDatabase.cs b/Oqtane.Database.Sqlite/SqliteDatabase.cs index 39c6cfd3..df132079 100644 --- a/Oqtane.Database.Sqlite/SqliteDatabase.cs +++ b/Oqtane.Database.Sqlite/SqliteDatabase.cs @@ -84,6 +84,11 @@ namespace Oqtane.Database.Sqlite return dr; } + public override string DelimitName(string name) + { + return $"\"{name}\""; + } + public override DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString) { return optionsBuilder.UseSqlite(connectionString) diff --git a/Oqtane.Server/Databases/DatabaseBase.cs b/Oqtane.Server/Databases/DatabaseBase.cs index 2342874f..668fdd38 100644 --- a/Oqtane.Server/Databases/DatabaseBase.cs +++ b/Oqtane.Server/Databases/DatabaseBase.cs @@ -61,12 +61,12 @@ namespace Oqtane.Databases public abstract IDataReader ExecuteReader(string connectionString, string query); - public virtual string RewriteName(string name) + public virtual string DelimitName(string name) { return name; } - public virtual string RewriteName(string name, bool isQuery) + public virtual string RewriteName(string name) { return name; } diff --git a/Oqtane.Server/Databases/Interfaces/IDatabase.cs b/Oqtane.Server/Databases/Interfaces/IDatabase.cs index 3c68cf03..8b9e7586 100644 --- a/Oqtane.Server/Databases/Interfaces/IDatabase.cs +++ b/Oqtane.Server/Databases/Interfaces/IDatabase.cs @@ -26,9 +26,9 @@ namespace Oqtane.Databases.Interfaces public IDataReader ExecuteReader(string connectionString, string query); - public string RewriteName(string name); + public string DelimitName(string name); // only used in conjunction with method using MigrationBuilder.Sql() - public string RewriteName(string name, bool isQuery); + public string RewriteName(string name); public string RewriteValue(string value, string type); diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index 9b4b09e9..98a392cc 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -104,6 +104,7 @@ namespace Microsoft.Extensions.DependencyInjection services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); // providers services.AddScoped(); diff --git a/Oqtane.Server/Infrastructure/DatabaseManager.cs b/Oqtane.Server/Infrastructure/DatabaseManager.cs index 1ee2a138..ff06f408 100644 --- a/Oqtane.Server/Infrastructure/DatabaseManager.cs +++ b/Oqtane.Server/Infrastructure/DatabaseManager.cs @@ -738,7 +738,7 @@ namespace Oqtane.Infrastructure databases += "{ \"Name\": \"LocalDB\", \"ControlType\": \"Oqtane.Installer.Controls.LocalDBConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Database.SqlServer\" },"; databases += "{ \"Name\": \"SQL Server\", \"ControlType\": \"Oqtane.Installer.Controls.SqlServerConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Database.SqlServer\" },"; databases += "{ \"Name\": \"SQLite\", \"ControlType\": \"Oqtane.Installer.Controls.SqliteConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.Sqlite.SqliteDatabase, Oqtane.Database.Sqlite\" },"; - databases += "{ \"Name\": \"MySQL\", \"ControlType\": \"Oqtane.Installer.Controls.MySQLConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.MySQL.SqlServerDatabase, Oqtane.Database.MySQL\" },"; + databases += "{ \"Name\": \"MySQL\", \"ControlType\": \"Oqtane.Installer.Controls.MySQLConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.MySQL.MySQLDatabase, Oqtane.Database.MySQL\" },"; databases += "{ \"Name\": \"PostgreSQL\", \"ControlType\": \"Oqtane.Installer.Controls.PostgreSQLConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.PostgreSQL.PostgreSQLDatabase, Oqtane.Database.PostgreSQL\" }"; databases += "]"; _configManager.AddOrUpdateSetting(SettingKeys.AvailableDatabasesSection, databases, true); diff --git a/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs index 7202921e..430a72c6 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs @@ -33,28 +33,28 @@ namespace Oqtane.Migrations.EntityBuilders protected string Schema { get; init; } - private string RewriteSqlEntityTableName(string name) + private string AddSchema(string name) { - if (Schema == null) + if (string.IsNullOrEmpty(Schema)) { - return RewriteName(name); + return name; } else { - return $"{Schema}.{RewriteName(name)}"; + return $"{Schema}.{name}"; } } + private string DelimitName(string name) + { + return ActiveDatabase.DelimitName(name); + } + private string RewriteName(string name) { return ActiveDatabase.RewriteName(name); } - private string RewriteName(string name, bool isQuery) - { - return ActiveDatabase.RewriteName(name, isQuery); - } - private string RewriteValue(string value, string type) { return ActiveDatabase.RewriteValue(value, type); @@ -468,9 +468,10 @@ namespace Oqtane.Migrations.EntityBuilders public void DeleteFromTable(string condition = "") { - var deleteSql = $"DELETE FROM {RewriteSqlEntityTableName(EntityTableName)} "; + var deleteSql = $"DELETE FROM {AddSchema(DelimitName(RewriteName(EntityTableName)))} "; if(!string.IsNullOrEmpty(condition)) { + // note that condition values must be created using RewriteName(), DelimitName(), RewriteValue() if targeting multiple database platforms deleteSql += $"WHERE {condition}"; } _migrationBuilder.Sql(deleteSql); @@ -488,9 +489,10 @@ namespace Oqtane.Migrations.EntityBuilders public void UpdateColumn(string columnName, string value, string type, string condition) { - var updateSql = $"UPDATE {RewriteSqlEntityTableName(EntityTableName)} SET {RewriteName(columnName, true)} = {RewriteValue(value, type)} "; + var updateSql = $"UPDATE {AddSchema(DelimitName(RewriteName(EntityTableName)))} SET {DelimitName(RewriteName(columnName))} = {RewriteValue(value, type)} "; if (!string.IsNullOrEmpty(condition)) { + // note that condition values must be created using RewriteName(), DelimitName(), RewriteValue() if targeting multiple database platforms updateSql += $"WHERE {condition}"; } _migrationBuilder.Sql(updateSql); diff --git a/Oqtane.Server/Migrations/Framework/MultiDatabaseMigration.cs b/Oqtane.Server/Migrations/Framework/MultiDatabaseMigration.cs index 87fb34cc..07f8043b 100644 --- a/Oqtane.Server/Migrations/Framework/MultiDatabaseMigration.cs +++ b/Oqtane.Server/Migrations/Framework/MultiDatabaseMigration.cs @@ -12,14 +12,19 @@ namespace Oqtane.Migrations protected IDatabase ActiveDatabase { get; } - protected string RewriteName(string name) + protected string DelimitName(string name) { - return ActiveDatabase.RewriteName(name, false); + return ActiveDatabase.DelimitName(name); } - protected string RewriteName(string name, bool isQuery) + protected string RewriteName(string name) { - return ActiveDatabase.RewriteName(name, isQuery); + return ActiveDatabase.RewriteName(name); + } + + protected string RewriteValue(string value, string type) + { + return ActiveDatabase.RewriteValue(value, type); } } } diff --git a/Oqtane.Server/Migrations/Tenant/01000101_AddAdditionColumnToNotifications.cs b/Oqtane.Server/Migrations/Tenant/01000101_AddAdditionColumnToNotifications.cs index 96c56e67..3dc8e016 100644 --- a/Oqtane.Server/Migrations/Tenant/01000101_AddAdditionColumnToNotifications.cs +++ b/Oqtane.Server/Migrations/Tenant/01000101_AddAdditionColumnToNotifications.cs @@ -21,7 +21,7 @@ namespace Oqtane.Migrations.Tenant notificationEntityBuilder.AddDateTimeColumn("SendOn", true); //Update new Column - notificationEntityBuilder.UpdateColumn("SendOn", $"{ActiveDatabase.RewriteName("CreatedOn")}", $"{ActiveDatabase.RewriteName("SendOn")} IS NULL"); + notificationEntityBuilder.UpdateColumn("SendOn", $"{RewriteName("CreatedOn")}", $"{DelimitName(RewriteName("SendOn"))} IS NULL"); } protected override void Down(MigrationBuilder migrationBuilder) diff --git a/Oqtane.Server/Migrations/Tenant/02000101_UpdateIconColumnInPage.cs b/Oqtane.Server/Migrations/Tenant/02000101_UpdateIconColumnInPage.cs index 1edbadcc..d9dcf06f 100644 --- a/Oqtane.Server/Migrations/Tenant/02000101_UpdateIconColumnInPage.cs +++ b/Oqtane.Server/Migrations/Tenant/02000101_UpdateIconColumnInPage.cs @@ -18,8 +18,8 @@ namespace Oqtane.Migrations.Tenant { ///Update Icon Field in Page var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase); - var updateSql = ActiveDatabase.ConcatenateSql("'oi oi-'", $"{ActiveDatabase.RewriteName("Icon")}"); - pageEntityBuilder.UpdateColumn("Icon", updateSql, $"{ActiveDatabase.RewriteName("Icon")} <> ''" ); + var updateSql = ActiveDatabase.ConcatenateSql("'oi oi-'", $"{DelimitName(RewriteName("Icon"))}"); + pageEntityBuilder.UpdateColumn("Icon", updateSql, $"{DelimitName(RewriteName("Icon"))} <> ''" ); } } } diff --git a/Oqtane.Server/Migrations/Tenant/02000202_UpdateDefaultContainerTypeInSitePage.cs b/Oqtane.Server/Migrations/Tenant/02000202_UpdateDefaultContainerTypeInSitePage.cs index ddf30943..1c0cb5b1 100644 --- a/Oqtane.Server/Migrations/Tenant/02000202_UpdateDefaultContainerTypeInSitePage.cs +++ b/Oqtane.Server/Migrations/Tenant/02000202_UpdateDefaultContainerTypeInSitePage.cs @@ -20,18 +20,18 @@ namespace Oqtane.Migrations.Tenant { //Update DefaultContainerType In Site var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder, ActiveDatabase); - siteEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'", "DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'"); - siteEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'", "DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.NoTitle, Oqtane.Client'"); + siteEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'", $"{DelimitName(RewriteName("DefaultContainerType"))} = 'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'"); + siteEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'", $"{DelimitName(RewriteName("DefaultContainerType"))} = 'Oqtane.Themes.OqtaneTheme.NoTitle, Oqtane.Client'"); //Update DefaultContainerType in Page var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase); - pageEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'", "DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'"); - pageEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'", "DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.NoTitle, Oqtane.Client'"); + pageEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'", $"{DelimitName(RewriteName("DefaultContainerType"))} = 'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'"); + pageEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'", $"{DelimitName(RewriteName("DefaultContainerType"))} = 'Oqtane.Themes.OqtaneTheme.NoTitle, Oqtane.Client'"); //Update ContainerType in PageModule var pageModuleEntityBuilder = new PageModuleEntityBuilder(migrationBuilder, ActiveDatabase); - pageModuleEntityBuilder.UpdateColumn("ContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'", "ContainerType = 'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'"); - pageModuleEntityBuilder.UpdateColumn("ContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'", "ContainerType = 'Oqtane.Themes.OqtaneTheme.NoTitle, Oqtane.Client'"); + pageModuleEntityBuilder.UpdateColumn("ContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'", $"{DelimitName(RewriteName("ContainerType"))} = 'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'"); + pageModuleEntityBuilder.UpdateColumn("ContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'", $"{DelimitName(RewriteName("ContainerType"))} = 'Oqtane.Themes.OqtaneTheme.NoTitle, Oqtane.Client'"); } } diff --git a/Oqtane.Server/Migrations/Tenant/02000203_DropDefaultLayoutInSite.cs b/Oqtane.Server/Migrations/Tenant/02000203_DropDefaultLayoutInSite.cs index 068c938c..4e174feb 100644 --- a/Oqtane.Server/Migrations/Tenant/02000203_DropDefaultLayoutInSite.cs +++ b/Oqtane.Server/Migrations/Tenant/02000203_DropDefaultLayoutInSite.cs @@ -29,22 +29,22 @@ namespace Oqtane.Migrations.Tenant siteEntityBuilder.DropColumn("DefaultLayoutType"); //Update DefaultContainerType In Site - siteEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", "DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'"); - siteEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", "DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'"); + siteEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", $"{DelimitName(RewriteName("DefaultContainerType"))} = 'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'"); + siteEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", $"{DelimitName(RewriteName("DefaultContainerType"))} = 'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'"); //Drop Column from Page Table var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase); pageEntityBuilder.DropColumn("LayoutType"); //Update DefaultContainerType in Page - pageEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", "DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'"); - pageEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", "DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'"); + pageEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", $"{DelimitName(RewriteName("DefaultContainerType"))} = 'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'"); + pageEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", $"{DelimitName(RewriteName("DefaultContainerType"))} = 'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'"); //Update ContainerType in PageModule var pageModuleEntityBuilder = new PageModuleEntityBuilder(migrationBuilder, ActiveDatabase); - pageModuleEntityBuilder.UpdateColumn("ContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", "ContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'"); - pageModuleEntityBuilder.UpdateColumn("ContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", "ContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'"); + pageModuleEntityBuilder.UpdateColumn("ContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", $"{DelimitName(RewriteName("ContainerType"))} = 'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'"); + pageModuleEntityBuilder.UpdateColumn("ContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", $"{DelimitName(RewriteName("ContainerType"))} = 'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'"); } } diff --git a/Oqtane.Server/Migrations/Tenant/02030001_AddFolderCapacity.cs b/Oqtane.Server/Migrations/Tenant/02030001_AddFolderCapacity.cs index 3658598c..a5ed9237 100644 --- a/Oqtane.Server/Migrations/Tenant/02030001_AddFolderCapacity.cs +++ b/Oqtane.Server/Migrations/Tenant/02030001_AddFolderCapacity.cs @@ -20,7 +20,7 @@ namespace Oqtane.Migrations.Tenant var folderEntityBuilder = new FolderEntityBuilder(migrationBuilder, ActiveDatabase); folderEntityBuilder.AddIntegerColumn("Capacity", true); folderEntityBuilder.UpdateColumn("Capacity", "0"); - folderEntityBuilder.UpdateColumn("Capacity", Constants.UserFolderCapacity.ToString(), $"{ActiveDatabase.RewriteName("Name")} = 'My Folder'"); + folderEntityBuilder.UpdateColumn("Capacity", Constants.UserFolderCapacity.ToString(), $"{DelimitName(RewriteName("Name"))} = 'My Folder'"); folderEntityBuilder.AddStringColumn("ImageSizes", 512, true, true); var fileEntityBuilder = new FileEntityBuilder(migrationBuilder, ActiveDatabase); diff --git a/Oqtane.Server/Migrations/Tenant/03000201_UpdateSettingIsPublic.cs b/Oqtane.Server/Migrations/Tenant/03000201_UpdateSettingIsPublic.cs index 2f99e341..46b52150 100644 --- a/Oqtane.Server/Migrations/Tenant/03000201_UpdateSettingIsPublic.cs +++ b/Oqtane.Server/Migrations/Tenant/03000201_UpdateSettingIsPublic.cs @@ -18,13 +18,13 @@ namespace Oqtane.Migrations.Tenant protected override void Up(MigrationBuilder migrationBuilder) { var settingEntityBuilder = new SettingEntityBuilder(migrationBuilder, ActiveDatabase); - settingEntityBuilder.UpdateColumn("IsPublic", "1", "bool", $"{RewriteName("SettingName")} NOT LIKE 'SMTP%'"); + settingEntityBuilder.UpdateColumn("IsPublic", "1", "bool", $"{DelimitName(RewriteName("SettingName"))} NOT LIKE 'SMTP%'"); } protected override void Down(MigrationBuilder migrationBuilder) { var settingEntityBuilder = new SettingEntityBuilder(migrationBuilder, ActiveDatabase); - settingEntityBuilder.UpdateColumn("IsPublic", "0", "bool", $"{RewriteName("SettingName")} NOT LIKE 'SMTP%'"); + settingEntityBuilder.UpdateColumn("IsPublic", "0", "bool", $"{DelimitName(RewriteName("SettingName"))} NOT LIKE 'SMTP%'"); } } } diff --git a/Oqtane.Server/Migrations/Tenant/03000202_UpdateSettingIsPrivate.cs b/Oqtane.Server/Migrations/Tenant/03000202_UpdateSettingIsPrivate.cs index f7e73854..dae85bb4 100644 --- a/Oqtane.Server/Migrations/Tenant/03000202_UpdateSettingIsPrivate.cs +++ b/Oqtane.Server/Migrations/Tenant/03000202_UpdateSettingIsPrivate.cs @@ -20,7 +20,7 @@ namespace Oqtane.Migrations.Tenant var settingEntityBuilder = new SettingEntityBuilder(migrationBuilder, ActiveDatabase); settingEntityBuilder.AddBooleanColumn("IsPrivate", true); settingEntityBuilder.UpdateColumn("IsPrivate", "0", "bool", ""); - settingEntityBuilder.UpdateColumn("IsPrivate", "1", "bool", $"{RewriteName("EntityName")} = 'Site' AND { RewriteName("SettingName")} LIKE 'SMTP%'"); + settingEntityBuilder.UpdateColumn("IsPrivate", "1", "bool", $"{DelimitName(RewriteName("EntityName"))} = 'Site' AND { DelimitName(RewriteName("SettingName"))} LIKE 'SMTP%'"); settingEntityBuilder.DropColumn("IsPublic"); } diff --git a/Oqtane.Server/Migrations/Tenant/06010401_RemoveUniqueEmailIndex.cs b/Oqtane.Server/Migrations/Tenant/06010401_RemoveUniqueEmailIndex.cs new file mode 100644 index 00000000..ac783753 --- /dev/null +++ b/Oqtane.Server/Migrations/Tenant/06010401_RemoveUniqueEmailIndex.cs @@ -0,0 +1,30 @@ +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Oqtane.Databases.Interfaces; +using Oqtane.Migrations.EntityBuilders; +using Oqtane.Repository; + +namespace Oqtane.Migrations.Tenant +{ + [DbContext(typeof(TenantDBContext))] + [Migration("Tenant.06.01.04.01")] + public class RemoveUniqueEmailIndex : MultiDatabaseMigration + { + public RemoveUniqueEmailIndex(IDatabase database) : base(database) + { + } + + protected override void Up(MigrationBuilder migrationBuilder) + { + // framework uses RequireUniqueEmail = False in .NET Identity configuration + var aspNetUsersEntityBuilder = new AspNetUsersEntityBuilder(migrationBuilder, ActiveDatabase); + aspNetUsersEntityBuilder.DropIndex("EmailIndex"); + aspNetUsersEntityBuilder.AddIndex("EmailIndex", "NormalizedEmail", false); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + // not implemented + } + } +} diff --git a/Oqtane.Server/Migrations/Tenant/06010402_ResetTimeZone.cs b/Oqtane.Server/Migrations/Tenant/06010402_ResetTimeZone.cs new file mode 100644 index 00000000..6e614cd0 --- /dev/null +++ b/Oqtane.Server/Migrations/Tenant/06010402_ResetTimeZone.cs @@ -0,0 +1,32 @@ +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Oqtane.Databases.Interfaces; +using Oqtane.Migrations.EntityBuilders; +using Oqtane.Repository; + +namespace Oqtane.Migrations.Tenant +{ + [DbContext(typeof(TenantDBContext))] + [Migration("Tenant.06.01.04.02")] + public class ResetTimeZone : MultiDatabaseMigration + { + public ResetTimeZone(IDatabase database) : base(database) + { + } + + protected override void Up(MigrationBuilder migrationBuilder) + { + // resetting value as framework now uses IANA ID consistently for time zones + var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder, ActiveDatabase); + siteEntityBuilder.UpdateColumn("TimeZoneId", "''"); + + var userEntityBuilder = new UserEntityBuilder(migrationBuilder, ActiveDatabase); + userEntityBuilder.UpdateColumn("TimeZoneId", "''"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + // not implemented + } + } +} diff --git a/Oqtane.Shared/Shared/Utilities.cs b/Oqtane.Shared/Shared/Utilities.cs index bf2efe3e..f5faff87 100644 --- a/Oqtane.Shared/Shared/Utilities.cs +++ b/Oqtane.Shared/Shared/Utilities.cs @@ -695,11 +695,11 @@ namespace Oqtane.Shared public static List GetTimeZones() { return [.. DateTimeZoneProviders.Tzdb.GetAllZones() - .Select(tz => new TimeZone() - { - Id = tz.Id, - DisplayName = tz.ToString() - })]; + .Select(tz => new TimeZone() + { + Id = tz.Id, + DisplayName = tz.Id + })]; } public static bool IsEffectiveAndNotExpired(DateTime? effectiveDate, DateTime? expiryDate)