This repository has been archived on 2025-05-14. You can view files and clone it, but cannot push or open issues or pull requests.
Pavel Vesely cf6643aef3 Client fixes
Client is partially done.
227 warnings left out of 1500
I like Rider
2020-03-15 15:19:35 +01:00

462 lines
17 KiB
Plaintext

@namespace Oqtane.UI
@inject AuthenticationStateProvider AuthenticationStateProvider
@inject SiteState SiteState
@inject NavigationManager NavigationManager
@inject INavigationInterception NavigationInterception
@inject IAliasService AliasService
@inject ITenantService TenantService
@inject ISiteService SiteService
@inject IPageService PageService
@inject IUserService UserService
@inject IModuleService ModuleService
@inject IModuleDefinitionService ModuleDefinitionService
@inject ILogService LogService
@using System.Diagnostics.CodeAnalysis
@using Oqtane.Enums
@implements IHandleAfterRender
@DynamicComponent
@code {
[CascadingParameter]
PageState PageState { get; set; }
[Parameter]
public Action<PageState> OnStateChange { get; set; }
PageState _pagestate;
RenderFragment DynamicComponent { get; set; }
string _absoluteUri;
bool _navigationInterceptionEnabled;
protected override void OnInitialized()
{
_absoluteUri = NavigationManager.Uri;
NavigationManager.LocationChanged += LocationChanged;
DynamicComponent = builder =>
{
if (PageState != null)
{
builder.OpenComponent(0, Type.GetType(Constants.PageComponent));
builder.CloseComponent();
}
};
}
public void Dispose()
{
NavigationManager.LocationChanged -= LocationChanged;
}
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(GetType().FullName + ": Error: API call to " + _absoluteUri + " is not mapped to a Controller");
}
}
}
[SuppressMessage("ReSharper", "StringIndexOfIsCultureSpecific.1")]
private async Task Refresh()
{
Alias alias = null;
Site site;
List<Page> pages;
Page page;
User user = null;
List<Module> modules;
int moduleid = -1;
string action = "";
bool editmode = false;
Reload reload = Reload.None;
DateTime lastsyncdate = DateTime.UtcNow;
// get Url path and querystring ( and remove anchors )
string path = new Uri(_absoluteUri).PathAndQuery.Substring(1);
if (path.IndexOf("#") != -1)
{
path = path.Substring(0, path.IndexOf("#"));
}
// parse querystring and remove
Dictionary<string, string> querystring = new Dictionary<string, string>();
if (path.IndexOf("?") != -1)
{
querystring = ParseQueryString(path);
path = path.Substring(0, path.IndexOf("?"));
}
// the reload parameter is used during user login/logout
if (querystring.ContainsKey("reload"))
{
reload = Reload.Site;
}
if (PageState != null)
{
editmode = PageState.EditMode;
lastsyncdate = PageState.LastSyncDate;
}
alias = await AliasService.GetAliasAsync(_absoluteUri, lastsyncdate);
SiteState.Alias = alias; // set state for services
lastsyncdate = alias.SyncDate;
// process any sync events for site or page
if (reload != Reload.Site && alias.SyncEvents.Any())
{
if (PageState != null && alias.SyncEvents.Exists(item => item.EntityName == "Page" && item.EntityId == PageState.Page.PageId))
{
reload = Reload.Page;
}
if (alias.SyncEvents.Exists(item => item.EntityName == "Site" && item.EntityId == alias.SiteId))
{
reload = Reload.Site;
}
}
if (reload == Reload.Site || PageState == null || alias.SiteId != PageState.Alias.SiteId)
{
site = await SiteService.GetSiteAsync(alias.SiteId, alias);
reload = Reload.Site;
}
else
{
site = PageState.Site;
}
if (site != null)
{
if (PageState == null || reload == Reload.Site)
{
// get user
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
if (authState.User.Identity.IsAuthenticated)
{
user = await UserService.GetUserAsync(authState.User.Identity.Name, site.SiteId);
}
}
else
{
user = PageState.User;
}
// process any sync events for user
if (reload != Reload.Site && user != null && alias.SyncEvents.Any())
{
if (alias.SyncEvents.Exists(item => item.EntityName == "User" && item.EntityId == user.UserId))
{
reload = Reload.Site;
}
}
if (PageState == null || reload >= Reload.Site)
{
await ModuleDefinitionService.LoadModuleDefinitionsAsync(site.SiteId);
pages = await PageService.GetPagesAsync(site.SiteId);
}
else
{
pages = PageState.Pages;
}
// 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(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
int result;
// check if path has moduleid and control specification ie. page/moduleid/control/
if (segments.Length >= 2 && int.TryParse(segments[segments.Length - 2], out result))
{
action = segments[segments.Length - 1];
moduleid = result;
path = path.Replace(moduleid.ToString() + "/" + action + "/", "");
}
else
{
// check if path has only moduleid specification ie. page/moduleid/
if (segments.Length >= 1 && int.TryParse(segments[segments.Length - 1], out result))
{
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 >= Reload.Page)
{
page = pages.Where(item => item.Path == path).FirstOrDefault();
}
else
{
page = PageState.Page;
}
// failsafe in case router cannot locate the home page for the site
if (page == null && path == "")
{
page = pages.FirstOrDefault();
path = page.Path;
}
// check if page has changed
if (page != null && page.Path != path)
{
page = pages.Where(item => item.Path == path).FirstOrDefault();
reload = Reload.Page;
if (page != null)
{
editmode = page.EditMode;
}
}
if (page != null)
{
if (PageState == null)
{
editmode = page.EditMode;
}
// check if user is authorized to view page
if (UserSecurity.IsAuthorized(user,PermissionNames.View, page.Permissions))
{
page = await ProcessPage(page, site, user);
_pagestate = new PageState
{
Alias = alias,
Site = site,
Pages = pages,
Page = page,
User = user,
Uri = new Uri(_absoluteUri, UriKind.Absolute),
QueryString = querystring,
ModuleId = moduleid,
Action = action
};
if (PageState != null && (PageState.ModuleId != _pagestate.ModuleId || PageState.Action != _pagestate.Action))
{
reload = Reload.Page;
}
if (PageState == null || reload >= Reload.Page)
{
modules = await ModuleService.GetModulesAsync(site.SiteId);
modules = ProcessModules(modules, page.PageId, _pagestate.ModuleId, _pagestate.Action, page.Panes, site.DefaultContainerType);
}
else
{
modules = PageState.Modules;
}
_pagestate.Modules = modules;
_pagestate.EditMode = editmode;
_pagestate.LastSyncDate = lastsyncdate;
OnStateChange?.Invoke(_pagestate);
}
}
else
{
if (user == null)
{
await LogService.Log(null, null, null, 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}", path);
// redirect to login page
NavigationManager.NavigateTo(Utilities.NavigateUrl(alias.Path, "login", "returnurl=" + path));
}
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}", path);
if (path != "")
{
// redirect to home page
NavigationManager.NavigateTo(Utilities.NavigateUrl(alias.Path, "", ""));
}
}
}
}
else
{
// site does not exist
}
}
private async void LocationChanged(object sender, LocationChangedEventArgs args)
{
_absoluteUri = args.Location;
await Refresh();
}
Task IHandleAfterRender.OnAfterRenderAsync()
{
if (!_navigationInterceptionEnabled)
{
_navigationInterceptionEnabled = true;
return NavigationInterception.EnableNavigationInterceptionAsync();
}
return Task.CompletedTask;
}
private Dictionary<string, string> ParseQueryString(string path)
{
Dictionary<string, string> querystring = new Dictionary<string, string>();
if (path.IndexOf("?") != -1)
{
foreach (string kvp in path.Substring(path.IndexOf("?") + 1).Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries))
{
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 async Task<Page> ProcessPage(Page page, Site site, User user)
{
try
{
if (page.IsPersonalizable && user != null)
{
// load the personalized page
page = await PageService.GetPageAsync(page.PageId, user.UserId);
}
if (string.IsNullOrEmpty(page.ThemeType))
{
page.ThemeType = site.DefaultThemeType;
page.LayoutType = site.DefaultLayoutType;
}
Type type;
if (!string.IsNullOrEmpty(page.LayoutType))
{
type = Type.GetType(page.LayoutType);
}
else
{
type = Type.GetType(page.ThemeType);
}
System.Reflection.PropertyInfo property = type.GetProperty("Panes");
page.Panes = (string)property.GetValue(Activator.CreateInstance(type), null);
}
catch
{
// error loading theme or layout
}
return page;
}
private List<Module> ProcessModules(List<Module> modules, int pageid, int moduleid, string control, string panes, string defaultcontainertype)
{
Dictionary<string, int> paneindex = new Dictionary<string, int>();
foreach (Module module in modules)
{
if (module.PageId == pageid || module.ModuleId == moduleid)
{
string typename = "";
if (module.ModuleDefinition != null)
{
typename = module.ModuleDefinition.ControlTypeTemplate;
}
else
{
typename = Constants.ErrorModule;
}
if (module.ModuleId == moduleid && control != "")
{
// check if the module defines custom routes
if (module.ModuleDefinition.ControlTypeRoutes != "")
{
foreach (string route in module.ModuleDefinition.ControlTypeRoutes.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
{
if (route.StartsWith(control + "="))
{
typename = route.Replace(control + "=", "");
}
}
}
module.ModuleType = typename.Replace(Constants.ActionToken, control);
// admin controls need to load additional metadata from the IModuleControl interface
if (moduleid == module.ModuleId)
{
typename = module.ModuleType;
// check for core module actions component
if (Constants.DefaultModuleActions.Contains(control))
{
typename = Constants.DefaultModuleActionsTemplate.Replace(Constants.ActionToken, control);
}
Type moduletype = Type.GetType(typename);
if (moduletype != null)
{
var moduleobject = Activator.CreateInstance(moduletype);
module.SecurityAccessLevel = (SecurityAccessLevel)moduletype.GetProperty("SecurityAccessLevel").GetValue(moduleobject, null);
module.ControlTitle = (string)moduletype.GetProperty("Title").GetValue(moduleobject);
module.Actions = (string)moduletype.GetProperty("Actions").GetValue(moduleobject);
module.UseAdminContainer = (bool)moduletype.GetProperty("UseAdminContainer").GetValue(moduleobject);
}
}
}
else
{
module.ModuleType = typename.Replace(Constants.ActionToken, Constants.DefaultAction);
}
// ensure module's pane exists in current page and if not, assign it to the Admin pane
if (panes == null || !panes.ToLower().Contains(module.Pane.ToLower()))
{
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];
if (string.IsNullOrEmpty(module.ContainerType))
{
module.ContainerType = defaultcontainertype;
}
}
}
foreach (Module module in modules.Where(item => item.PageId == pageid))
{
module.PaneModuleCount = paneindex[module.Pane] + 1;
}
return modules;
}
}