From 042083c0e780142dbd03eead7c69f2177fa58031 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Mon, 4 Apr 2022 17:16:12 -0400 Subject: [PATCH] fix logic issue in url mapping, improve 404 handling, add property change component notifications --- Oqtane.Client/UI/SiteRouter.razor | 11 ++- Oqtane.Server/Pages/_Host.cshtml.cs | 10 +- Oqtane.Server/Repository/SiteRepository.cs | 26 ++++++ Oqtane.Shared/Shared/PropertyDictionary.cs | 101 +++++++++++++++++++++ Oqtane.Shared/Shared/SiteState.cs | 5 + 5 files changed, 149 insertions(+), 4 deletions(-) create mode 100644 Oqtane.Shared/Shared/PropertyDictionary.cs diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index 3946fbcb..e62db3aa 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -258,10 +258,15 @@ } else { - await LogService.Log(null, null, user.UserId, GetType().AssemblyQualifiedName, Utilities.GetTypeNameLastSegment(GetType().AssemblyQualifiedName, 1), LogFunction.Security, LogLevel.Error, null, "Page Does Not Exist Or User Is Not Authorized To View Page {Path}", route.PagePath); - if (route.PagePath != "") + if (route.PagePath != "404") { - // redirect to home page + await LogService.Log(null, null, user.UserId, "SiteRouter", "SiteRouter", LogFunction.Other, LogLevel.Information, null, "Page Path /{Path} Does Not Exist Or User Is Not Authorized To View", route.PagePath); + // redirect to 404 page + NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "404", "")); + } + else + { + // redirect to home page as a fallback NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "", "")); } } diff --git a/Oqtane.Server/Pages/_Host.cshtml.cs b/Oqtane.Server/Pages/_Host.cshtml.cs index baafc119..20770472 100644 --- a/Oqtane.Server/Pages/_Host.cshtml.cs +++ b/Oqtane.Server/Pages/_Host.cshtml.cs @@ -153,7 +153,7 @@ namespace Oqtane.Pages } var page = _pages.GetPage(route.PagePath, site.SiteId); - if (page != null & !page.IsDeleted) + if (page != null && !page.IsDeleted) { // set page title if (!string.IsNullOrEmpty(page.Title)) @@ -182,6 +182,14 @@ namespace Oqtane.Pages url = (urlMapping.MappedUrl.StartsWith("http")) ? urlMapping.MappedUrl : route.SiteUrl + "/" + urlMapping.MappedUrl; return RedirectPermanent(url); } + else + { + if (route.PagePath != "404") + { + _logger.Log(LogLevel.Information, "Host", LogFunction.Other, "Page Path /{Path} Does Not Exist", route.PagePath); + return RedirectPermanent(route.SiteUrl + "/404"); + } + } } // include global resources diff --git a/Oqtane.Server/Repository/SiteRepository.cs b/Oqtane.Server/Repository/SiteRepository.cs index 0fcf9cef..e5ca3265 100644 --- a/Oqtane.Server/Repository/SiteRepository.cs +++ b/Oqtane.Server/Repository/SiteRepository.cs @@ -390,6 +390,32 @@ namespace Oqtane.Repository } } }); + pageTemplates.Add(new PageTemplate + { + Name = "Not Found", + Parent = "", + Path = "404", + Icon = Icons.X, + IsNavigation = false, + IsPersonalizable = false, + PagePermissions = new List + { + new Permission(PermissionNames.View, RoleNames.Everyone, true), + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) + }.EncodePermissions(), + PageTemplateModules = new List + { + new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "Not Found", Pane = PaneNames.Admin, + ModulePermissions = new List { + new Permission(PermissionNames.View, RoleNames.Everyone, true), + new Permission(PermissionNames.View, RoleNames.Admin, true), + new Permission(PermissionNames.Edit, RoleNames.Admin, true) + }.EncodePermissions(), + Content = "

The page you requested does not exist.

" + } + } + }); // admin pages pageTemplates.Add(new PageTemplate diff --git a/Oqtane.Shared/Shared/PropertyDictionary.cs b/Oqtane.Shared/Shared/PropertyDictionary.cs new file mode 100644 index 00000000..c131decf --- /dev/null +++ b/Oqtane.Shared/Shared/PropertyDictionary.cs @@ -0,0 +1,101 @@ +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Dynamic; +using System.Runtime.CompilerServices; + +namespace Oqtane.Shared +{ + public class PropertyDictionary : DynamicObject, IDictionary, INotifyPropertyChanged + { + readonly IDictionary _dictionary = new Dictionary(); + + public void Add(KeyValuePair item) + { + _dictionary.Add(item.Key, item.Value); + } + + public void Clear() + { + _dictionary.Clear(); + } + + public bool Contains(KeyValuePair item) + { + return _dictionary.Contains(item); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + _dictionary.CopyTo(array, arrayIndex); + } + + public bool Remove(KeyValuePair item) + { + return _dictionary.Remove(item); + } + + public int Count => _dictionary.Count; + public bool IsReadOnly => _dictionary.IsReadOnly; + + public override bool TryGetMember(GetMemberBinder binder, out object result) + { + if (!_dictionary.TryGetValue(binder.Name, out result)) result = null; + return true; + } + + public override bool TrySetMember(SetMemberBinder binder, object value) + { + _dictionary[binder.Name] = value; + OnPropertyChanged(binder.Name); + return true; + } + + public IEnumerator> GetEnumerator() + { + return _dictionary.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)_dictionary).GetEnumerator(); + } + + public void Add(string key, object value) + { + _dictionary.Add(key, value); + } + + public bool ContainsKey(string key) + { + return _dictionary.ContainsKey(key); + } + + public bool Remove(string key) + { + return _dictionary.Remove(key); + } + + public bool TryGetValue(string key, out object value) + { + return _dictionary.TryGetValue(key, out value); + } + + public object this[string key] + { + get => _dictionary[key]; + set => _dictionary[key] = value; + } + + public ICollection Keys => _dictionary.Keys; + + public ICollection Values => _dictionary.Values; + + public event PropertyChangedEventHandler PropertyChanged; + + protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } +} diff --git a/Oqtane.Shared/Shared/SiteState.cs b/Oqtane.Shared/Shared/SiteState.cs index cee7546e..411c60ab 100644 --- a/Oqtane.Shared/Shared/SiteState.cs +++ b/Oqtane.Shared/Shared/SiteState.cs @@ -9,5 +9,10 @@ namespace Oqtane.Shared public string AntiForgeryToken { get; set; } // passed from server for use in service calls on client public string AuthorizationToken { get; set; } // passed from server for use in service calls on client public string RemoteIPAddress { get; set; } // passed from server as cannot be reliable retrieved on client + + + private dynamic _properties; + public dynamic Properties => _properties ?? (_properties = new PropertyDictionary()); + } }