@using System @using Oqtane.Services @using Oqtane.Models @using System.Linq @using System.Collections.Generic @using Oqtane.Shared @using Microsoft.AspNetCore.Components.Routing @inject AuthenticationStateProvider AuthenticationStateProvider @inject SiteState SiteState @inject IUriHelper UriHelper @inject INavigationInterception NavigationInterception @inject IComponentContext ComponentContext @inject IAliasService AliasService @inject ITenantService TenantService @inject ISiteService SiteService @inject IPageService PageService @inject IUserService UserService @inject IModuleService ModuleService @inject IModuleDefinitionService ModuleDefinitionService @inject IThemeService ThemeService @implements IHandleAfterRender @DynamicComponent @code { [CascadingParameter] PageState PageState { get; set; } [Parameter] Action OnStateChange { get; set; } PageState pagestate; RenderFragment DynamicComponent { get; set; } string _absoluteUri; bool _navigationInterceptionEnabled; protected override void OnInit() { _absoluteUri = UriHelper.GetAbsoluteUri(); UriHelper.OnLocationChanged += OnLocationChanged; DynamicComponent = builder => { if (PageState != null) { builder.OpenComponent(0, Type.GetType(Constants.DefaultPage)); builder.CloseComponent(); } }; } public void Dispose() { UriHelper.OnLocationChanged -= OnLocationChanged; } protected override async Task OnParametersSetAsync() { if (PageState == null) { // misconfigured api calls should not be processed through the router if (!_absoluteUri.Contains("~/api/")) { await Refresh(); } else { System.Diagnostics.Debug.WriteLine(this.GetType().FullName + ": Error: " + _absoluteUri + " is not mapped to a Controller"); } } } private async Task Refresh() { List moduledefinitions; List themes; List aliases; Alias alias; Site site; List pages; Page page; User user; List modules; int moduleid = -1; string control = ""; int reload = 0; if (PageState != null) { reload = PageState.Reload; } if (PageState == null || reload == Constants.ReloadApplication) { moduledefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(); themes = await ThemeService.GetThemesAsync(); aliases = await AliasService.GetAliasesAsync(); alias = null; } else { moduledefinitions = PageState.ModuleDefinitions; themes = PageState.Themes; aliases = PageState.Aliases; alias = PageState.Alias; } // check if site has changed if (alias == null || GetAlias(_absoluteUri, aliases).Name != alias.Name) { alias = GetAlias(_absoluteUri, aliases); SiteState.Alias = alias; // set state for services reload = Constants.ReloadSite; } if (PageState == null || reload <= Constants.ReloadSite) { site = await SiteService.GetSiteAsync(alias.SiteId); } else { site = PageState.Site; } if (site != null) { if (PageState == null || reload >= Constants.ReloadSite) { pages = await PageService.GetPagesAsync(site.SiteId); } else { pages = PageState.Pages; } // get Url path and querystring string path = new Uri(_absoluteUri).PathAndQuery.Substring(1); // parse querystring and remove Dictionary querystring = new Dictionary(); if (path.IndexOf("?") != -1) { querystring = ParseQueryString(path); path = path.Substring(0, path.IndexOf("?")); } // format path and remove alias path = path.Replace("//", "/"); if (!path.EndsWith("/")) { path += "/"; } if (alias.Path != "") { path = path.Replace(alias.Path + "/", ""); } // extract admin route elements from path string[] segments = path.Split('/'); int result; if (segments.Length >= 3 && int.TryParse(segments[segments.Length - 3], out result)) { // path has moduleid and control specification ie. page/moduleid/control/ control = segments[segments.Length - 2]; moduleid = result; path = path.Replace(moduleid.ToString() + "/" + control + "/", ""); } else { if (segments.Length >= 2 && int.TryParse(segments[segments.Length - 2], out result)) { // path has only moduleid specification ie. page/moduleid/ moduleid = result; path = path.Replace(moduleid.ToString() + "/", ""); } } // remove trailing slash so it can be used as a key for Pages if (path.EndsWith("/")) path = path.Substring(0, path.Length - 1); if (PageState == null || reload >= Constants.ReloadPage) { page = pages.Where(item => item.Path == path).FirstOrDefault(); } else { page = PageState.Page; } // check if page has changed if (page.Path != path) { page = pages.Where(item => item.Path == path).FirstOrDefault(); reload = Constants.ReloadPage; } user = null; if (PageState == null || reload >= Constants.ReloadPage) { var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync(); if (authState.User.Identity.IsAuthenticated) { user = await UserService.GetUserAsync(authState.User.Identity.Name); } } else { user = PageState.User; } if (page != null) { // check if user is authorized to view page if (UserService.IsAuthorized(user, page.ViewPermissions)) { pagestate = new PageState(); pagestate.ModuleDefinitions = moduledefinitions; pagestate.Themes = themes; pagestate.Aliases = aliases; pagestate.Alias = alias; pagestate.Site = site; pagestate.Pages = pages; pagestate.Page = page; pagestate.User = user; pagestate.Uri = new Uri(_absoluteUri, UriKind.Absolute); pagestate.QueryString = querystring; pagestate.ModuleId = moduleid; pagestate.Control = control; if (PageState != null && (PageState.ModuleId != pagestate.ModuleId || PageState.Control != pagestate.Control)) { reload = Constants.ReloadPage; } if (PageState == null || reload >= Constants.ReloadPage) { modules = await ModuleService.GetModulesAsync(page.PageId); modules = ProcessModules(modules, moduledefinitions, pagestate.Control, page.Panes); } else { modules = PageState.Modules; } pagestate.Modules = modules; pagestate.Reload = 0; OnStateChange?.Invoke(pagestate); } else { // user is not authorized to view page } } else { // page does not exist } } else { // site does not exist } } private async void OnLocationChanged(object sender, LocationChangedEventArgs args) { _absoluteUri = args.Location; await Refresh(); } Task IHandleAfterRender.OnAfterRenderAsync() { if (!_navigationInterceptionEnabled && ComponentContext.IsConnected) { _navigationInterceptionEnabled = true; return NavigationInterception.EnableNavigationInterceptionAsync(); } return Task.CompletedTask; } private Dictionary ParseQueryString(string path) { Dictionary querystring = new Dictionary(); if (path.IndexOf("?") != -1) { foreach (string kvp in path.Substring(path.IndexOf("?") + 1).Split('&')) { if (kvp != "") { if (kvp.Contains("=")) { string[] pair = kvp.Split('='); querystring.Add(pair[0], pair[1]); } else { querystring.Add(kvp, "true"); // default querystring when no value is provided } } } } return querystring; } private List ProcessModules(List modules, List moduledefinitions, string control, string panes) { ModuleDefinition moduledefinition; if (control == "") { control = Constants.DefaultControl; } Dictionary paneindex = new Dictionary(); foreach (Module module in modules) { // set the type based on the template and action moduledefinition = moduledefinitions.Where(item => item.ModuleDefinitionName == module.ModuleDefinitionName).FirstOrDefault(); if (moduledefinition != null) { string typename = moduledefinition.ControlTypeTemplate; if (moduledefinition.ControlTypeRoutes != "") { foreach (string route in moduledefinition.ControlTypeRoutes.Split(';')) { if (route.StartsWith(control + "=")) { typename = route.Replace(control + "=", ""); } } } module.ModuleType = typename.Replace("{Control}", control); } // ensure module's pane exists in current page and if not, assign it to the Admin pane if (!panes.Contains(module.Pane)) { module.Pane = Constants.AdminPane; } // calculate module position within pane if (paneindex.ContainsKey(module.Pane)) { paneindex[module.Pane] += 1; } else { paneindex.Add(module.Pane, 0); } module.PaneModuleIndex = paneindex[module.Pane]; } foreach (Module module in modules) { module.PaneModuleCount = paneindex[module.Pane] + 1; } return modules; } private Alias GetAlias(string absoluteUri, List aliases) { string aliasname; Alias alias = null; Uri uri = new Uri(absoluteUri); if (uri.Segments.Count() > 1) { // check if first path segment is an alias ( ie. a subfolder - www.domain.com/subfolder ) aliasname = uri.Authority + "/" + uri.Segments[1]; if (aliasname.EndsWith("/")) { aliasname = aliasname.Substring(0, aliasname.Length - 1); } alias = aliases.Where(item => item.Name == aliasname).FirstOrDefault(); } if (alias == null) { aliasname = uri.Authority; alias = aliases.Where(item => item.Name == aliasname).FirstOrDefault(); } if (alias == null && aliases.Count > 0) { // use first alias if Uri does not exist alias = aliases.FirstOrDefault(); } alias.Scheme = uri.Scheme; return alias; } }