diff --git a/Oqtane.Client/Modules/Admin/Dashboard/Index.razor b/Oqtane.Client/Modules/Admin/Dashboard/Index.razor index 6ba9014e..98729f76 100644 --- a/Oqtane.Client/Modules/Admin/Dashboard/Index.razor +++ b/Oqtane.Client/Modules/Admin/Dashboard/Index.razor @@ -12,11 +12,12 @@ if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList)) { string url = NavigateUrl(p.Path); -
+

-

@SharedLocalizer[p.Name] +

+

@((MarkupString)SharedLocalizer[p.Name].ToString().Replace(" ", "
"))

-
+

} } diff --git a/Oqtane.Client/Modules/Admin/Files/Edit.razor b/Oqtane.Client/Modules/Admin/Files/Edit.razor index e69b44aa..05990fe4 100644 --- a/Oqtane.Client/Modules/Admin/Files/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Files/Edit.razor @@ -67,6 +67,7 @@ +

@if (!_isSystem) { @@ -79,8 +80,7 @@ @((MarkupString)" ") } -
-
+

@if (PageState.QueryString.ContainsKey("id")) { diff --git a/Oqtane.Client/Modules/Admin/Files/Index.razor b/Oqtane.Client/Modules/Admin/Files/Index.razor index 11684f3f..504a888f 100644 --- a/Oqtane.Client/Modules/Admin/Files/Index.razor +++ b/Oqtane.Client/Modules/Admin/Files/Index.razor @@ -8,27 +8,28 @@ @if (_files != null) { -
-
-
- -
-
+
+
+ +
+
+
+ @Localizer["Folder"]: -
-
  -   -
+
+ +
- + +
    diff --git a/Oqtane.Client/Modules/Admin/Jobs/Index.razor b/Oqtane.Client/Modules/Admin/Jobs/Index.razor index 9b217d07..ee9fb6fe 100644 --- a/Oqtane.Client/Modules/Admin/Jobs/Index.razor +++ b/Oqtane.Client/Modules/Admin/Jobs/Index.razor @@ -15,7 +15,7 @@ else

- +
    diff --git a/Oqtane.Client/Modules/Admin/Languages/Index.razor b/Oqtane.Client/Modules/Admin/Languages/Index.razor index 19b3be19..18c98317 100644 --- a/Oqtane.Client/Modules/Admin/Languages/Index.razor +++ b/Oqtane.Client/Modules/Admin/Languages/Index.razor @@ -14,7 +14,7 @@ else { - +
  @SharedLocalizer["Name"] diff --git a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Add.razor b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Add.razor index 8a4e2850..9aa03a1f 100644 --- a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Add.razor +++ b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Add.razor @@ -66,6 +66,7 @@
@SharedLocalizer["Search.Version"]: @context.Version diff --git a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Create.razor b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Create.razor index 30dda63a..94770893 100644 --- a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Create.razor +++ b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Create.razor @@ -156,7 +156,7 @@ private bool IsValidXML(string description) { // must contain letters, digits, or spaces - return Regex.IsMatch(description, "^[A-Za-z0-9 ]+$"); + return Regex.IsMatch(description, "^[A-Za-z0-9 .,!?]+$"); } private void TemplateChanged(ChangeEventArgs e) diff --git a/Oqtane.Client/Modules/Admin/Modules/Settings.razor b/Oqtane.Client/Modules/Admin/Modules/Settings.razor index 9798c2f9..7f4f35f1 100644 --- a/Oqtane.Client/Modules/Admin/Modules/Settings.razor +++ b/Oqtane.Client/Modules/Admin/Modules/Settings.razor @@ -26,6 +26,17 @@
+
+ +
+ +
+
@@ -112,6 +123,7 @@ private List _containers = new List(); private string _module; private string _title; + private string _pane; private string _containerType; private string _allPages = "false"; private string _permissionNames = ""; @@ -134,80 +146,82 @@ { _module = ModuleState.ModuleDefinition.Name; _title = ModuleState.Title; + _pane = ModuleState.Pane; _containers = ThemeService.GetContainerControls(PageState.Site.Themes, PageState.Page.ThemeType); - _containerType = ModuleState.ContainerType; - _allPages = ModuleState.AllPages.ToString(); - _permissions = ModuleState.PermissionList; - _pageId = ModuleState.PageId.ToString(); - createdby = ModuleState.CreatedBy; - createdon = ModuleState.CreatedOn; - modifiedby = ModuleState.ModifiedBy; - modifiedon = ModuleState.ModifiedOn; + _containerType = ModuleState.ContainerType; + _allPages = ModuleState.AllPages.ToString(); + _permissions = ModuleState.PermissionList; + _pageId = ModuleState.PageId.ToString(); + createdby = ModuleState.CreatedBy; + createdon = ModuleState.CreatedOn; + modifiedby = ModuleState.ModifiedBy; + modifiedon = ModuleState.ModifiedOn; - if (ModuleState.ModuleDefinition != null) - { - _permissionNames = ModuleState.ModuleDefinition?.PermissionNames; + if (ModuleState.ModuleDefinition != null) + { + _permissionNames = ModuleState.ModuleDefinition?.PermissionNames; - if (!string.IsNullOrEmpty(ModuleState.ModuleDefinition.SettingsType)) - { - // module settings type explicitly declared in IModule interface - _moduleSettingsType = Type.GetType(ModuleState.ModuleDefinition.SettingsType); - } - else - { - // legacy support - module settings type determined by convention ( ie. existence of a "Settings.razor" component in module ) - _moduleSettingsType = Type.GetType(ModuleState.ModuleDefinition.ControlTypeTemplate.Replace(Constants.ActionToken, PageState.Action), false, true); - } - if (_moduleSettingsType != null) - { - var moduleobject = Activator.CreateInstance(_moduleSettingsType) as IModuleControl; - if (!string.IsNullOrEmpty(moduleobject.Title)) - { - _moduleSettingsTitle = moduleobject.Title; - } + if (!string.IsNullOrEmpty(ModuleState.ModuleDefinition.SettingsType)) + { + // module settings type explicitly declared in IModule interface + _moduleSettingsType = Type.GetType(ModuleState.ModuleDefinition.SettingsType); + } + else + { + // legacy support - module settings type determined by convention ( ie. existence of a "Settings.razor" component in module ) + _moduleSettingsType = Type.GetType(ModuleState.ModuleDefinition.ControlTypeTemplate.Replace(Constants.ActionToken, PageState.Action), false, true); + } + if (_moduleSettingsType != null) + { + var moduleobject = Activator.CreateInstance(_moduleSettingsType) as IModuleControl; + if (!string.IsNullOrEmpty(moduleobject.Title)) + { + _moduleSettingsTitle = moduleobject.Title; + } - ModuleSettingsComponent = builder => - { - builder.OpenComponent(0, _moduleSettingsType); - builder.AddComponentReferenceCapture(1, inst => { _moduleSettings = Convert.ChangeType(inst, _moduleSettingsType); }); - builder.CloseComponent(); - }; - } - } - else - { - AddModuleMessage(string.Format(Localizer["Error.Module.Load"], ModuleState.ModuleDefinitionName), MessageType.Error); - } + ModuleSettingsComponent = builder => + { + builder.OpenComponent(0, _moduleSettingsType); + builder.AddComponentReferenceCapture(1, inst => { _moduleSettings = Convert.ChangeType(inst, _moduleSettingsType); }); + builder.CloseComponent(); + }; + } + } + else + { + AddModuleMessage(string.Format(Localizer["Error.Module.Load"], ModuleState.ModuleDefinitionName), MessageType.Error); + } var theme = PageState.Site.Themes.FirstOrDefault(item => item.Containers.Any(themecontrol => themecontrol.TypeName.Equals(_containerType))); - if (theme != null && !string.IsNullOrEmpty(theme.ContainerSettingsType)) - { - _containerSettingsType = Type.GetType(theme.ContainerSettingsType); - if (_containerSettingsType != null) - { - ContainerSettingsComponent = builder => - { - builder.OpenComponent(0, _containerSettingsType); - builder.AddComponentReferenceCapture(1, inst => { _containerSettings = Convert.ChangeType(inst, _containerSettingsType); }); - builder.CloseComponent(); - }; - } - } - } + if (theme != null && !string.IsNullOrEmpty(theme.ContainerSettingsType)) + { + _containerSettingsType = Type.GetType(theme.ContainerSettingsType); + if (_containerSettingsType != null) + { + ContainerSettingsComponent = builder => + { + builder.OpenComponent(0, _containerSettingsType); + builder.AddComponentReferenceCapture(1, inst => { _containerSettings = Convert.ChangeType(inst, _containerSettingsType); }); + builder.CloseComponent(); + }; + } + } + } - private async Task SaveModule() - { - validated = true; - var interop = new Interop(JSRuntime); - if (await interop.FormValid(form)) - { - if (!string.IsNullOrEmpty(_title)) - { - 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) + private async Task SaveModule() + { + validated = true; + var interop = new Interop(JSRuntime); + if (await interop.FormValid(form)) + { + if (!string.IsNullOrEmpty(_title)) + { + var pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId); + pagemodule.PageId = int.Parse(_pageId); + pagemodule.Title = _title; + pagemodule.Pane = _pane; + pagemodule.ContainerType = (_containerType != "-") ? _containerType : string.Empty; + if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Page.DefaultContainerType) { pagemodule.ContainerType = string.Empty; } diff --git a/Oqtane.Client/Modules/Admin/Pages/Index.razor b/Oqtane.Client/Modules/Admin/Pages/Index.razor index d71dc964..f1b9e9b4 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Index.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Index.razor @@ -9,7 +9,7 @@ { - +
    diff --git a/Oqtane.Client/Modules/Admin/Profiles/Edit.razor b/Oqtane.Client/Modules/Admin/Profiles/Edit.razor index 9620a396..33ec94b0 100644 --- a/Oqtane.Client/Modules/Admin/Profiles/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Profiles/Edit.razor @@ -22,7 +22,7 @@
- +
@@ -43,6 +43,12 @@
+
+ +
+ +
+
@@ -101,6 +107,7 @@ private string _category = string.Empty; private string _vieworder = "0"; private string _maxlength = "0"; + private string _rows = "1"; private string _defaultvalue = string.Empty; private string _options = string.Empty; private string _validation = string.Empty; @@ -131,6 +138,7 @@ _category = profile.Category; _vieworder = profile.ViewOrder.ToString(); _maxlength = profile.MaxLength.ToString(); + _rows = profile.Rows.ToString(); _defaultvalue = profile.DefaultValue; _options = profile.Options; _validation = profile.Validation; @@ -175,6 +183,7 @@ profile.Category = _category; profile.ViewOrder = int.Parse(_vieworder); profile.MaxLength = int.Parse(_maxlength); + profile.Rows = int.Parse(_rows); profile.DefaultValue = _defaultvalue; profile.Options = _options; profile.Validation = _validation; diff --git a/Oqtane.Client/Modules/Admin/Profiles/Index.razor b/Oqtane.Client/Modules/Admin/Profiles/Index.razor index f554c6c5..587fa452 100644 --- a/Oqtane.Client/Modules/Admin/Profiles/Index.razor +++ b/Oqtane.Client/Modules/Admin/Profiles/Index.razor @@ -12,7 +12,7 @@ else { - +
    diff --git a/Oqtane.Client/Modules/Admin/Roles/Index.razor b/Oqtane.Client/Modules/Admin/Roles/Index.razor index 6677548d..6b0e4610 100644 --- a/Oqtane.Client/Modules/Admin/Roles/Index.razor +++ b/Oqtane.Client/Modules/Admin/Roles/Index.razor @@ -12,7 +12,7 @@ else { - +
    diff --git a/Oqtane.Client/Modules/Admin/Sites/Index.razor b/Oqtane.Client/Modules/Admin/Sites/Index.razor index 8075d4d6..20a652ee 100644 --- a/Oqtane.Client/Modules/Admin/Sites/Index.razor +++ b/Oqtane.Client/Modules/Admin/Sites/Index.razor @@ -14,7 +14,7 @@ else { - +
    diff --git a/Oqtane.Client/Modules/Admin/Themes/Add.razor b/Oqtane.Client/Modules/Admin/Themes/Add.razor index 3b22ef3c..a7be5907 100644 --- a/Oqtane.Client/Modules/Admin/Themes/Add.razor +++ b/Oqtane.Client/Modules/Admin/Themes/Add.razor @@ -66,6 +66,7 @@
@SharedLocalizer["Search.Version"]: @context.Version diff --git a/Oqtane.Client/Modules/Admin/UrlMappings/Index.razor b/Oqtane.Client/Modules/Admin/UrlMappings/Index.razor index 28478589..6ed8c769 100644 --- a/Oqtane.Client/Modules/Admin/UrlMappings/Index.razor +++ b/Oqtane.Client/Modules/Admin/UrlMappings/Index.razor @@ -28,7 +28,7 @@ else

- +
    diff --git a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor index a10202ee..694f28aa 100644 --- a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor +++ b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor @@ -123,13 +123,27 @@ else } else { - @if (p.IsRequired) + @if (p.Rows == 1) { - + @if (p.IsRequired) + { + + } + else + { + + } } else { - + @if (p.IsRequired) + { + + } + else + { + + } } }
@@ -282,9 +296,11 @@ else private int folderid = -1; private int photofileid = -1; private File photo = null; + private List profiles; private Dictionary settings; private string category = string.Empty; + private string filter = "to"; private List notifications; private string notificationSummary = string.Empty; @@ -363,44 +379,47 @@ else { try { - if (username != string.Empty && email != string.Empty && ValidateProfiles()) + if (username != string.Empty && email != string.Empty) { if (_password == confirm) { - var user = PageState.User; - user.Username = username; - user.Password = _password; - user.TwoFactorRequired = bool.Parse(twofactor); - user.Email = email; - user.DisplayName = (displayname == string.Empty ? username : displayname); - user.PhotoFileId = filemanager.GetFileId(); - if (user.PhotoFileId == -1) + if (ValidateProfiles()) { - user.PhotoFileId = null; - } - if (user.PhotoFileId != null) - { - photofileid = user.PhotoFileId.Value; - photo = await FileService.GetFileAsync(photofileid); - } - else - { - photofileid = -1; - photo = null; - } + var user = PageState.User; + user.Username = username; + user.Password = _password; + user.TwoFactorRequired = bool.Parse(twofactor); + user.Email = email; + user.DisplayName = (displayname == string.Empty ? username : displayname); + user.PhotoFileId = filemanager.GetFileId(); + if (user.PhotoFileId == -1) + { + user.PhotoFileId = null; + } + if (user.PhotoFileId != null) + { + photofileid = user.PhotoFileId.Value; + photo = await FileService.GetFileAsync(photofileid); + } + else + { + photofileid = -1; + photo = null; + } - user = await UserService.UpdateUserAsync(user); - if (user != null) - { - await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId); - await logger.LogInformation("User Profile Saved"); + user = await UserService.UpdateUserAsync(user); + if (user != null) + { + await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId); + await logger.LogInformation("User Profile Saved"); - AddModuleMessage(Localizer["Success.Profile.Update"], MessageType.Success); - StateHasChanged(); - } - else - { - AddModuleMessage(Localizer["Message.Password.Complexity"], MessageType.Error); + AddModuleMessage(Localizer["Success.Profile.Update"], MessageType.Success); + StateHasChanged(); + } + else + { + AddModuleMessage(Localizer["Message.Password.Complexity"], MessageType.Error); + } } } else @@ -424,7 +443,6 @@ else private bool ValidateProfiles() { - bool valid = true; foreach (Profile profile in profiles) { if (string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)) && !string.IsNullOrEmpty(profile.DefaultValue)) @@ -433,18 +451,24 @@ else } if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin)) { - if (valid == true && profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty))) + if (profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty))) { - valid = false; + AddModuleMessage(string.Format(SharedLocalizer["ProfileRequired"], profile.Title), MessageType.Warning); + return false; } - if (valid == true && !string.IsNullOrEmpty(profile.Validation)) + if (!string.IsNullOrEmpty(profile.Validation)) { Regex regex = new Regex(profile.Validation); - valid = regex.Match(SettingService.GetSetting(settings, profile.Name, string.Empty)).Success; + bool valid = regex.Match(SettingService.GetSetting(settings, profile.Name, string.Empty)).Success; + if (!valid) + { + AddModuleMessage(string.Format(SharedLocalizer["ProfileInvalid"], profile.Title), MessageType.Warning); + return false; + } } } } - return valid; + return true; } private void Cancel() diff --git a/Oqtane.Client/Modules/Admin/Users/Add.razor b/Oqtane.Client/Modules/Admin/Users/Add.razor index 817bf5e1..10f24ff1 100644 --- a/Oqtane.Client/Modules/Admin/Users/Add.razor +++ b/Oqtane.Client/Modules/Admin/Users/Add.razor @@ -80,18 +80,50 @@
- @if (p.IsRequired) + @if (!string.IsNullOrEmpty(p.Options)) { - + } else { - + @if (p.Rows == 1) + { + @if (p.IsRequired) + { + + } + else + { + + } + } + else + { + @if (p.IsRequired) + { + + } + else + { + + } + } }
} -
} @@ -148,31 +180,34 @@ { try { - if (_username != string.Empty && _password != string.Empty && _confirm != string.Empty && _email != string.Empty && ValidateProfiles()) + if (_username != string.Empty && _password != string.Empty && _confirm != string.Empty && _email != string.Empty) { if (_password == _confirm) { - var user = new User(); - user.SiteId = PageState.Site.SiteId; - user.Username = _username; - user.Password = _password; - user.Email = _email; - user.DisplayName = string.IsNullOrWhiteSpace(_displayname) ? _username : _displayname; - user.PhotoFileId = null; - user.SuppressNotification = !bool.Parse(_notify); - - user = await UserService.AddUserAsync(user); - - if (user != null) + if (ValidateProfiles()) { - await SettingService.UpdateUserSettingsAsync(settings, user.UserId); - await logger.LogInformation("User Created {User}", user); - NavigationManager.NavigateTo(NavigateUrl()); - } - else - { - await logger.LogError("Error Adding User {Username} {Email}", _username, _email); - AddModuleMessage(Localizer["Error.User.AddCheckPass"], MessageType.Error); + var user = new User(); + user.SiteId = PageState.Site.SiteId; + user.Username = _username; + user.Password = _password; + user.Email = _email; + user.DisplayName = string.IsNullOrWhiteSpace(_displayname) ? _username : _displayname; + user.PhotoFileId = null; + user.SuppressNotification = !bool.Parse(_notify); + + user = await UserService.AddUserAsync(user); + + if (user != null) + { + await SettingService.UpdateUserSettingsAsync(settings, user.UserId); + await logger.LogInformation("User Created {User}", user); + NavigationManager.NavigateTo(NavigateUrl()); + } + else + { + await logger.LogError("Error Adding User {Username} {Email}", _username, _email); + AddModuleMessage(Localizer["Error.User.AddCheckPass"], MessageType.Error); + } } } else @@ -194,7 +229,6 @@ private bool ValidateProfiles() { - bool valid = true; foreach (Profile profile in profiles) { if (string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)) && !string.IsNullOrEmpty(profile.DefaultValue)) @@ -203,18 +237,24 @@ } if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin)) { - if (valid == true && profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty))) + if (profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty))) { - valid = false; + AddModuleMessage(string.Format(SharedLocalizer["ProfileRequired"], profile.Title), MessageType.Warning); + return false; } - if (valid == true && !string.IsNullOrEmpty(profile.Validation)) + if (!string.IsNullOrEmpty(profile.Validation)) { Regex regex = new Regex(profile.Validation); - valid = regex.Match(SettingService.GetSetting(settings, profile.Name, string.Empty)).Success; + bool valid = regex.Match(SettingService.GetSetting(settings, profile.Name, string.Empty)).Success; + if (!valid) + { + AddModuleMessage(string.Format(SharedLocalizer["ProfileInvalid"], profile.Title), MessageType.Warning); + return false; + } } } } - return valid; + return true; } private void ProfileChanged(ChangeEventArgs e, string SettingName) diff --git a/Oqtane.Client/Modules/Admin/Users/Edit.razor b/Oqtane.Client/Modules/Admin/Users/Edit.razor index 19fbbdd1..ea0198c9 100644 --- a/Oqtane.Client/Modules/Admin/Users/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Users/Edit.razor @@ -125,13 +125,27 @@ else } else { - @if (p.IsRequired) + @if (p.Rows == 1) { - + @if (p.IsRequired) + { + + } + else + { + + } } else { - + @if (p.IsRequired) + { + + } + else + { + + } } }
@@ -240,35 +254,38 @@ else { try { - if (username != string.Empty && email != string.Empty && ValidateProfiles()) + if (username != string.Empty && email != string.Empty) { if (_password == confirm) { - var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId); - user.SiteId = PageState.Site.SiteId; - user.Username = username; - user.Password = _password; - user.Email = email; - user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname; - user.PhotoFileId = null; - user.PhotoFileId = filemanager.GetFileId(); - if (user.PhotoFileId == -1) + if (ValidateProfiles()) { + var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId); + user.SiteId = PageState.Site.SiteId; + user.Username = username; + user.Password = _password; + user.Email = email; + user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname; user.PhotoFileId = null; - } + user.PhotoFileId = filemanager.GetFileId(); + if (user.PhotoFileId == -1) + { + user.PhotoFileId = null; + } - user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted)); + user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted)); - user = await UserService.UpdateUserAsync(user); - if (user != null) - { - await SettingService.UpdateUserSettingsAsync(settings, user.UserId); - await logger.LogInformation("User Saved {User}", user); - NavigationManager.NavigateTo(NavigateUrl()); - } - else - { - AddModuleMessage(Localizer["Message.Password.Complexity"], MessageType.Error); + user = await UserService.UpdateUserAsync(user); + if (user != null) + { + await SettingService.UpdateUserSettingsAsync(settings, user.UserId); + await logger.LogInformation("User Saved {User}", user); + NavigationManager.NavigateTo(NavigateUrl()); + } + else + { + AddModuleMessage(Localizer["Message.Password.Complexity"], MessageType.Error); + } } } else @@ -290,7 +307,6 @@ else private bool ValidateProfiles() { - bool valid = true; foreach (Profile profile in profiles) { if (string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)) && !string.IsNullOrEmpty(profile.DefaultValue)) @@ -299,18 +315,24 @@ else } if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin)) { - if (valid == true && profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty))) + if (profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty))) { - valid = false; + AddModuleMessage(string.Format(SharedLocalizer["ProfileRequired"], profile.Title), MessageType.Warning); + return false; } - if (valid == true && !string.IsNullOrEmpty(profile.Validation)) + if (!string.IsNullOrEmpty(profile.Validation)) { Regex regex = new Regex(profile.Validation); - valid = regex.Match(SettingService.GetSetting(settings, profile.Name, string.Empty)).Success; + bool valid = regex.Match(SettingService.GetSetting(settings, profile.Name, string.Empty)).Success; + if (!valid) + { + AddModuleMessage(string.Format(SharedLocalizer["ProfileInvalid"], profile.Title), MessageType.Warning); + return false; + } } } } - return valid; + return true; } private void ProfileChanged(ChangeEventArgs e, string SettingName) diff --git a/Oqtane.Client/Modules/Admin/Users/Index.razor b/Oqtane.Client/Modules/Admin/Users/Index.razor index 57f10221..4cd17e00 100644 --- a/Oqtane.Client/Modules/Admin/Users/Index.razor +++ b/Oqtane.Client/Modules/Admin/Users/Index.razor @@ -17,21 +17,10 @@ else { -
-
-
-   - -
-
- -
-
- -
-
-
- +   + + +
    @@ -262,7 +251,22 @@ else
-
+
+ +
+ +
+
+
+ } + } @if (ShowUpload && _haseditpermission) {
@@ -55,7 +62,7 @@
- @if (GetFileId() != -1) + @if (GetFileId() != -1 && !UploadMultiple) { } @@ -371,7 +378,7 @@ success = false; var filename = uploads[upload].Split(':')[0]; var size = Int64.Parse(uploads[upload].Split(':')[1]); - var maxattempts = (int)Math.Ceiling(size / 500000.0) + 1; // 30 MB takes 1 minute at 5 Mbps + var maxattempts = (int)Math.Ceiling(size / 500000.0) + 4; // 30 MB takes 1 minute at 5 Mbps (min 5 attempts) int attempts = 0; while (attempts < maxattempts && !success) diff --git a/Oqtane.Client/Modules/Controls/Pager.razor b/Oqtane.Client/Modules/Controls/Pager.razor index bf735801..79642eaa 100644 --- a/Oqtane.Client/Modules/Controls/Pager.razor +++ b/Oqtane.Client/Modules/Controls/Pager.razor @@ -1,10 +1,20 @@ @namespace Oqtane.Modules.Controls @inherits ModuleControlBase @inject IStringLocalizerFactory LocalizerFactory +@inject IStringLocalizer SharedLocalizer @typeparam TableItem @if (ItemList != null) { + @if (!string.IsNullOrEmpty(SearchProperties)) + { +
+ + + +
+ } + @if ((Toolbar == "Top" || Toolbar == "Both") && _pages > 0 && Items.Count() > _maxItems) {
    @@ -175,6 +185,9 @@ private int _startPage = 0; private int _endPage = 0; private int _columns = 0; + private string _search = ""; + + private IEnumerable AllItems; [Parameter] public string Format { get; set; } // Table or Grid @@ -221,6 +234,9 @@ [Parameter] public Action OnPageChange { get; set; } // a method to be executed in the calling component when the page changes + [Parameter] + public string SearchProperties { get; set; } // comma delimited list of property names to include in search + private IEnumerable ItemList { get; set; } protected override void OnInitialized() @@ -276,6 +292,15 @@ } } + if (!string.IsNullOrEmpty(SearchProperties)) + { + AllItems = Items; // only used in search + if (!string.IsNullOrEmpty(_search)) + { + Search(); + } + } + if (!string.IsNullOrEmpty(PageSize)) { _maxItems = int.Parse(PageSize); @@ -323,10 +348,10 @@ { _endPage = _pages; } - ItemList = Items.Skip((_page - 1) * _maxItems).Take(_maxItems); - StateHasChanged(); - OnPageChange?.Invoke(_page); - } + ItemList = Items.Skip((_page - 1) * _maxItems).Take(_maxItems); + StateHasChanged(); + OnPageChange?.Invoke(_page); + } public void UpdateList(int page) { @@ -369,4 +394,75 @@ UpdateList(_page); } + + public void Search() + { + if (!string.IsNullOrEmpty(_search)) + { + Items = AllItems.Where(item => + { + var values = SearchProperties.Split(',') + .Select(itemType => GetPropertyValue(item, itemType)) + .Where(value => value != null) + .Select(value => value.ToString().ToLower()); + + return values.Any(value => value.Contains(_search.ToLower())); + }).ToList(); + } + else + { + Items = AllItems; + } + _pages = (int)Math.Ceiling(Items.Count() / (decimal)_maxItems); + UpdateList(1); + } + + private object GetPropertyValue(object obj, string propertyName) + { + var index = propertyName.IndexOf("."); + if (index != -1) + { + var propertyInfo = obj.GetType().GetProperty(propertyName.Substring(0, index)); + if (propertyInfo != null) + { + return GetPropertyValue(propertyInfo.GetValue(obj), propertyName.Substring(index + 1)); + } + return null; + } + else + { + var propertyInfo = obj.GetType().GetProperty(propertyName); + if (propertyInfo != null) + { + return propertyInfo.GetValue(obj); + } + return null; + } + } + + public void Reset() + { + _search = ""; + Items = AllItems; + _pages = (int)Math.Ceiling(Items.Count() / (decimal)_maxItems); + UpdateList(1); + } + + private string FormatSearchProperties() + { + var properties = new List(); + foreach (var property in SearchProperties.Split(',', StringSplitOptions.RemoveEmptyEntries)) + { + var index = property.LastIndexOf("."); + if (index != -1) + { + properties.Add(property.Substring(index + 1)); + } + else + { + properties.Add(property); + } + } + return string.Join(",", properties); + } } diff --git a/Oqtane.Client/Oqtane.Client.csproj b/Oqtane.Client/Oqtane.Client.csproj index ce1fc979..26fd8912 100644 --- a/Oqtane.Client/Oqtane.Client.csproj +++ b/Oqtane.Client/Oqtane.Client.csproj @@ -4,7 +4,7 @@ net7.0 Exe Debug;Release - 4.0.5 + 4.0.6 Oqtane Shaun Walker .NET Foundation @@ -12,7 +12,7 @@ .NET Foundation https://www.oqtane.org https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE - https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.5 + https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.6 https://github.com/oqtane/oqtane.framework Git Oqtane diff --git a/Oqtane.Client/Resources/Modules/Admin/Modules/Settings.resx b/Oqtane.Client/Resources/Modules/Admin/Modules/Settings.resx index cead365f..5b7849ec 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Modules/Settings.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Modules/Settings.resx @@ -159,4 +159,10 @@ Module Settings + + The pane where the module will be displayed + + + Pane: + \ No newline at end of file diff --git a/Oqtane.Client/Resources/Modules/Admin/Users/Index.resx b/Oqtane.Client/Resources/Modules/Admin/Users/Index.resx index 19757ae8..fb932e57 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Users/Index.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Users/Index.resx @@ -408,4 +408,31 @@ Import Users + + code + + + code id_token + + + code id_token token + + + code token + + + id_token + + + id_token token + + + none + + + token + + + Authorization Response Type + \ No newline at end of file diff --git a/Oqtane.Client/Resources/Modules/Controls/Pager.resx b/Oqtane.Client/Resources/Modules/Controls/Pager.resx index 710d041d..2dfdd092 100644 --- a/Oqtane.Client/Resources/Modules/Controls/Pager.resx +++ b/Oqtane.Client/Resources/Modules/Controls/Pager.resx @@ -1,4 +1,4 @@ - + Exe - 4.0.5 + 4.0.6 Oqtane Shaun Walker .NET Foundation @@ -14,7 +14,7 @@ .NET Foundation https://www.oqtane.org https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE - https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.5 + https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.6 https://github.com/oqtane/oqtane.framework Git Oqtane.Maui @@ -31,7 +31,7 @@ 0E29FC31-1B83-48ED-B6E0-9F3C67B775D4 - 4.0.5 + 4.0.6 1 14.2 diff --git a/Oqtane.Package/Oqtane.Client.nuspec b/Oqtane.Package/Oqtane.Client.nuspec index 00a9dfbf..bdeaa36b 100644 --- a/Oqtane.Package/Oqtane.Client.nuspec +++ b/Oqtane.Package/Oqtane.Client.nuspec @@ -2,7 +2,7 @@ Oqtane.Client - 4.0.5 + 4.0.6 Shaun Walker .NET Foundation Oqtane Framework @@ -12,7 +12,7 @@ false MIT https://github.com/oqtane/oqtane.framework - https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.5 + https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.6 icon.png oqtane diff --git a/Oqtane.Package/Oqtane.Framework.nuspec b/Oqtane.Package/Oqtane.Framework.nuspec index 24d38630..9560c694 100644 --- a/Oqtane.Package/Oqtane.Framework.nuspec +++ b/Oqtane.Package/Oqtane.Framework.nuspec @@ -2,7 +2,7 @@ Oqtane.Framework - 4.0.5 + 4.0.6 Shaun Walker .NET Foundation Oqtane Framework @@ -11,8 +11,8 @@ .NET Foundation false MIT - https://github.com/oqtane/oqtane.framework/releases/download/v4.0.5/Oqtane.Framework.4.0.5.Upgrade.zip - https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.5 + https://github.com/oqtane/oqtane.framework/releases/download/v4.0.6/Oqtane.Framework.4.0.6.Upgrade.zip + https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.6 icon.png oqtane framework diff --git a/Oqtane.Package/Oqtane.Server.nuspec b/Oqtane.Package/Oqtane.Server.nuspec index dd9e4560..e50d4c6b 100644 --- a/Oqtane.Package/Oqtane.Server.nuspec +++ b/Oqtane.Package/Oqtane.Server.nuspec @@ -2,7 +2,7 @@ Oqtane.Server - 4.0.5 + 4.0.6 Shaun Walker .NET Foundation Oqtane Framework @@ -12,7 +12,7 @@ false MIT https://github.com/oqtane/oqtane.framework - https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.5 + https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.6 icon.png oqtane diff --git a/Oqtane.Package/Oqtane.Shared.nuspec b/Oqtane.Package/Oqtane.Shared.nuspec index ebd77308..3de3d700 100644 --- a/Oqtane.Package/Oqtane.Shared.nuspec +++ b/Oqtane.Package/Oqtane.Shared.nuspec @@ -2,7 +2,7 @@ Oqtane.Shared - 4.0.5 + 4.0.6 Shaun Walker .NET Foundation Oqtane Framework @@ -12,7 +12,7 @@ false MIT https://github.com/oqtane/oqtane.framework - https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.5 + https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.6 icon.png oqtane diff --git a/Oqtane.Package/Oqtane.Updater.nuspec b/Oqtane.Package/Oqtane.Updater.nuspec index 10f2b937..57bd8ac0 100644 --- a/Oqtane.Package/Oqtane.Updater.nuspec +++ b/Oqtane.Package/Oqtane.Updater.nuspec @@ -2,7 +2,7 @@ Oqtane.Updater - 4.0.5 + 4.0.6 Shaun Walker .NET Foundation Oqtane Framework @@ -12,7 +12,7 @@ false MIT https://github.com/oqtane/oqtane.framework - https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.5 + https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.6 icon.png oqtane diff --git a/Oqtane.Package/install.ps1 b/Oqtane.Package/install.ps1 index 4ec91611..6449a533 100644 --- a/Oqtane.Package/install.ps1 +++ b/Oqtane.Package/install.ps1 @@ -1 +1 @@ -Compress-Archive -Path "..\Oqtane.Server\bin\Release\net7.0\publish\*" -DestinationPath "Oqtane.Framework.4.0.5.Install.zip" -Force \ No newline at end of file +Compress-Archive -Path "..\Oqtane.Server\bin\Release\net7.0\publish\*" -DestinationPath "Oqtane.Framework.4.0.6.Install.zip" -Force \ No newline at end of file diff --git a/Oqtane.Package/upgrade.ps1 b/Oqtane.Package/upgrade.ps1 index a997b9e9..c2369c1c 100644 --- a/Oqtane.Package/upgrade.ps1 +++ b/Oqtane.Package/upgrade.ps1 @@ -1 +1 @@ -Compress-Archive -Path "..\Oqtane.Server\bin\Release\net7.0\publish\*" -DestinationPath "Oqtane.Framework.4.0.5.Upgrade.zip" -Force \ No newline at end of file +Compress-Archive -Path "..\Oqtane.Server\bin\Release\net7.0\publish\*" -DestinationPath "Oqtane.Framework.4.0.6.Upgrade.zip" -Force \ No newline at end of file diff --git a/Oqtane.Server/Extensions/OqtaneSiteAuthenticationBuilderExtensions.cs b/Oqtane.Server/Extensions/OqtaneSiteAuthenticationBuilderExtensions.cs index cad695a4..7bf5637e 100644 --- a/Oqtane.Server/Extensions/OqtaneSiteAuthenticationBuilderExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneSiteAuthenticationBuilderExtensions.cs @@ -44,7 +44,7 @@ namespace Oqtane.Extensions options.SaveTokens = false; options.GetClaimsFromUserInfoEndpoint = true; options.CallbackPath = string.IsNullOrEmpty(alias.Path) ? "/signin-" + AuthenticationProviderTypes.OpenIDConnect : "/" + alias.Path + "/signin-" + AuthenticationProviderTypes.OpenIDConnect; - options.ResponseType = OpenIdConnectResponseType.Code; // authorization code flow + options.ResponseType = sitesettings.GetValue("ExternalLogin:AuthResponseType", "code"); // authorization code flow options.ResponseMode = OpenIdConnectResponseMode.FormPost; // recommended as most secure // cookie config is required to avoid Correlation Failed errors diff --git a/Oqtane.Server/Migrations/Tenant/04000601_AddProfileRows.cs b/Oqtane.Server/Migrations/Tenant/04000601_AddProfileRows.cs new file mode 100644 index 00000000..976706ce --- /dev/null +++ b/Oqtane.Server/Migrations/Tenant/04000601_AddProfileRows.cs @@ -0,0 +1,29 @@ +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.04.00.06.01")] + public class AddProfileRows : MultiDatabaseMigration + { + public AddProfileRows(IDatabase database) : base(database) + { + } + + protected override void Up(MigrationBuilder migrationBuilder) + { + var profileEntityBuilder = new ProfileEntityBuilder(migrationBuilder, ActiveDatabase); + profileEntityBuilder.AddIntegerColumn("Rows", true); + profileEntityBuilder.UpdateColumn("Rows", "1"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + // not implemented + } + } +} diff --git a/Oqtane.Server/Oqtane.Server.csproj b/Oqtane.Server/Oqtane.Server.csproj index 1d37cd26..8109b1cb 100644 --- a/Oqtane.Server/Oqtane.Server.csproj +++ b/Oqtane.Server/Oqtane.Server.csproj @@ -3,7 +3,7 @@ net7.0 Debug;Release - 4.0.5 + 4.0.6 Oqtane Shaun Walker .NET Foundation @@ -11,7 +11,7 @@ .NET Foundation https://www.oqtane.org https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE - https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.5 + https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.6 https://github.com/oqtane/oqtane.framework Git Oqtane diff --git a/Oqtane.Server/Repository/FileRepository.cs b/Oqtane.Server/Repository/FileRepository.cs index e57ca3f1..829659e1 100644 --- a/Oqtane.Server/Repository/FileRepository.cs +++ b/Oqtane.Server/Repository/FileRepository.cs @@ -32,8 +32,9 @@ namespace Oqtane.Repository public IEnumerable GetFiles(int folderId, bool tracking) { - var alias = _tenants.GetAlias(); - IEnumerable permissions = _permissions.GetPermissions(alias.SiteId, EntityNames.Folder, folderId).ToList(); + var folder = _folderRepository.GetFolder(folderId, false); + IEnumerable permissions = _permissions.GetPermissions(folder.SiteId, EntityNames.Folder, folderId).ToList(); + IEnumerable files; if (tracking) { @@ -46,6 +47,7 @@ namespace Oqtane.Repository foreach (File file in files) { file.Folder.PermissionList = permissions.ToList(); + var alias = _tenants.GetAlias(); file.Url = GetFileUrl(file, alias); } return files; diff --git a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/[Owner].Module.[Module].Client.csproj b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/[Owner].Module.[Module].Client.csproj index 68e4160c..d0046940 100644 --- a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/[Owner].Module.[Module].Client.csproj +++ b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/[Owner].Module.[Module].Client.csproj @@ -9,6 +9,7 @@ [Owner].Module.[Module] [Owner] [Owner].Module.[Module].Client.Oqtane + true diff --git a/Oqtane.Server/wwwroot/Packages/Oqtane.Database.MySQL.nupkg.bak b/Oqtane.Server/wwwroot/Packages/Oqtane.Database.MySQL.nupkg.bak index cfd8fcd0..8b5279e1 100644 Binary files a/Oqtane.Server/wwwroot/Packages/Oqtane.Database.MySQL.nupkg.bak and b/Oqtane.Server/wwwroot/Packages/Oqtane.Database.MySQL.nupkg.bak differ diff --git a/Oqtane.Server/wwwroot/Packages/Oqtane.Database.PostgreSQL.nupkg.bak b/Oqtane.Server/wwwroot/Packages/Oqtane.Database.PostgreSQL.nupkg.bak index 870fdda5..672b26c8 100644 Binary files a/Oqtane.Server/wwwroot/Packages/Oqtane.Database.PostgreSQL.nupkg.bak and b/Oqtane.Server/wwwroot/Packages/Oqtane.Database.PostgreSQL.nupkg.bak differ diff --git a/Oqtane.Server/wwwroot/Packages/Oqtane.Database.SqlServer.nupkg.bak b/Oqtane.Server/wwwroot/Packages/Oqtane.Database.SqlServer.nupkg.bak index 48a2b204..edecee24 100644 Binary files a/Oqtane.Server/wwwroot/Packages/Oqtane.Database.SqlServer.nupkg.bak and b/Oqtane.Server/wwwroot/Packages/Oqtane.Database.SqlServer.nupkg.bak differ diff --git a/Oqtane.Server/wwwroot/Packages/Oqtane.Database.Sqlite.nupkg.bak b/Oqtane.Server/wwwroot/Packages/Oqtane.Database.Sqlite.nupkg.bak index cd2bb01f..81f02141 100644 Binary files a/Oqtane.Server/wwwroot/Packages/Oqtane.Database.Sqlite.nupkg.bak and b/Oqtane.Server/wwwroot/Packages/Oqtane.Database.Sqlite.nupkg.bak differ diff --git a/Oqtane.Shared/Models/Profile.cs b/Oqtane.Shared/Models/Profile.cs index e5586a13..336cd262 100644 --- a/Oqtane.Shared/Models/Profile.cs +++ b/Oqtane.Shared/Models/Profile.cs @@ -73,5 +73,10 @@ namespace Oqtane.Models /// Optional RegExp validation expression /// public string Validation { get; set; } + + /// + /// Optional number of rows (textarea) + /// + public int Rows { get; set; } } } diff --git a/Oqtane.Shared/Oqtane.Shared.csproj b/Oqtane.Shared/Oqtane.Shared.csproj index 4616250d..3b8dfa3d 100644 --- a/Oqtane.Shared/Oqtane.Shared.csproj +++ b/Oqtane.Shared/Oqtane.Shared.csproj @@ -3,7 +3,7 @@ net7.0 Debug;Release - 4.0.5 + 4.0.6 Oqtane Shaun Walker .NET Foundation @@ -11,7 +11,7 @@ .NET Foundation https://www.oqtane.org https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE - https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.5 + https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.6 https://github.com/oqtane/oqtane.framework Git Oqtane diff --git a/Oqtane.Shared/Shared/Constants.cs b/Oqtane.Shared/Shared/Constants.cs index 840134c1..0e0ec0d4 100644 --- a/Oqtane.Shared/Shared/Constants.cs +++ b/Oqtane.Shared/Shared/Constants.cs @@ -7,8 +7,8 @@ namespace Oqtane.Shared { public class Constants { - public static readonly string Version = "4.0.5"; - public const string ReleaseVersions = "1.0.0,1.0.1,1.0.2,1.0.3,1.0.4,2.0.0,2.0.1,2.0.2,2.1.0,2.2.0,2.3.0,2.3.1,3.0.0,3.0.1,3.0.2,3.0.3,3.1.0,3.1.1,3.1.2,3.1.3,3.1.4,3.2.0,3.2.1,3.3.0,3.3.1,3.4.0,3.4.1,3.4.2,3.4.3,4.0.0,4.0.1,4.0.2,4.0.3,4.0.4,4.0.5"; + public static readonly string Version = "4.0.6"; + public const string ReleaseVersions = "1.0.0,1.0.1,1.0.2,1.0.3,1.0.4,2.0.0,2.0.1,2.0.2,2.1.0,2.2.0,2.3.0,2.3.1,3.0.0,3.0.1,3.0.2,3.0.3,3.1.0,3.1.1,3.1.2,3.1.3,3.1.4,3.2.0,3.2.1,3.3.0,3.3.1,3.4.0,3.4.1,3.4.2,3.4.3,4.0.0,4.0.1,4.0.2,4.0.3,4.0.4,4.0.5,4.0.6"; public const string PackageId = "Oqtane.Framework"; public const string ClientId = "Oqtane.Client"; public const string UpdaterPackageId = "Oqtane.Updater"; diff --git a/Oqtane.Shared/Shared/Utilities.cs b/Oqtane.Shared/Shared/Utilities.cs index b5a7493e..82b32796 100644 --- a/Oqtane.Shared/Shared/Utilities.cs +++ b/Oqtane.Shared/Shared/Utilities.cs @@ -1,8 +1,6 @@ using Oqtane.Models; using System; -using System.Collections; using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; using System.Globalization; using System.IO; using System.Linq; @@ -389,13 +387,20 @@ namespace Oqtane.Shared } public static string UrlCombine(params string[] segments) -{ - segments = segments.Where(item => !string.IsNullOrEmpty(item) && item != "/" && item != "\\").ToArray(); - for (int i = 1; i < segments.Length; i++) + { + var url = new List(); + for (int i = 0; i < segments.Length; i++) { segments[i] = segments[i].Replace("\\", "/"); + if (!string.IsNullOrEmpty(segments[i]) && segments[i] != "/") + { + foreach (var segment in segments[i].Split('/', StringSplitOptions.RemoveEmptyEntries)) + { + url.Add(segment); + } + } } - return string.Join("/", segments); + return string.Join("/", url); } public static bool IsPathValid(this Folder folder) diff --git a/Oqtane.Updater/Oqtane.Updater.csproj b/Oqtane.Updater/Oqtane.Updater.csproj index 9b2b1f1a..8d88d00c 100644 --- a/Oqtane.Updater/Oqtane.Updater.csproj +++ b/Oqtane.Updater/Oqtane.Updater.csproj @@ -3,7 +3,7 @@ net7.0 Exe - 4.0.5 + 4.0.6 Oqtane Shaun Walker .NET Foundation @@ -11,7 +11,7 @@ .NET Foundation https://www.oqtane.org https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE - https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.5 + https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.6 https://github.com/oqtane/oqtane.framework Git Oqtane diff --git a/README.md b/README.md index fff174e7..0999800b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Latest Release -[4.0.4](https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.4) was released on Sep 25, 2023 and is primarily focused on stabilization. This release includes 53 pull requests by 4 different contributors, pushing the total number of project commits all-time to over 4100. The Oqtane framework continues to evolve at a rapid pace to meet the needs of .NET developers. +[4.0.5](https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.5) was released on Sep 26, 2023 and is primarily focused on stabilization. This release includes 53 pull requests by 4 different contributors, pushing the total number of project commits all-time to over 4100. The Oqtane framework continues to evolve at a rapid pace to meet the needs of .NET developers. [![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Foqtane%2Foqtane.framework%2Fmaster%2Fazuredeploy.json) @@ -53,6 +53,9 @@ Backlog (TBD) 5.0.0 (Q4 2023) - [ ] Migration to .NET 8 +[4.0.5](https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.5) ( Sep 26, 2023 ) +- [x] Stabilization improvements + [4.0.4](https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.4) ( Sep 25, 2023 ) - [x] Stabilization improvements - [x] User Import