commit
99b0c9c079
@ -15,7 +15,7 @@
|
||||
<div style="@_display">
|
||||
<CascadingAuthenticationState>
|
||||
<CascadingValue Value="@PageState">
|
||||
<SiteRouter Runtime="@Runtime" RenderMode="@RenderMode" OnStateChange="@ChangeState" />
|
||||
<SiteRouter Runtime="@Runtime" RenderMode="@RenderMode" VisitorId="@VisitorId" OnStateChange="@ChangeState" />
|
||||
</CascadingValue>
|
||||
</CascadingAuthenticationState>
|
||||
</div>
|
||||
@ -39,6 +39,9 @@
|
||||
[Parameter]
|
||||
public string RenderMode { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public int VisitorId { get; set; }
|
||||
|
||||
private bool _initialized = false;
|
||||
private string _display = "display: none;";
|
||||
private Installation _installation = new Installation { Success = false, Message = "" };
|
||||
|
@ -46,6 +46,8 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||
services.AddScoped<ILocalizationService, LocalizationService>();
|
||||
services.AddScoped<ILanguageService, LanguageService>();
|
||||
services.AddScoped<IDatabaseService, DatabaseService>();
|
||||
services.AddScoped<IUrlMappingService, UrlMappingService>();
|
||||
services.AddScoped<IVisitorService, VisitorService>();
|
||||
services.AddScoped<ISyncService, SyncService>();
|
||||
|
||||
return services;
|
||||
|
@ -158,8 +158,8 @@
|
||||
if (firstRender)
|
||||
{
|
||||
var interop = new Interop(JSRuntime);
|
||||
await interop.IncludeLink("", "stylesheet", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.2/css/bootstrap.min.css", "text/css", "sha512-usVBAd66/NpVNfBge19gws2j6JZinnca12rAe2l+d+QkLU9fiG02O1X8Q6hepIpr/EYKZvKx/I9WsnujJuOmBA==", "anonymous", "");
|
||||
await interop.IncludeScript("", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.2/js/bootstrap.min.js", "sha512-a6ctI6w1kg3J4dSjknHj3aWLEbjitAXAjLDRUxo2wyYmDFRcz2RJuQr5M3Kt8O/TtUSp8n2rAyaXYy1sjoKmrQ==", "anonymous", "", "head", "");
|
||||
await interop.IncludeLink("", "stylesheet", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/css/bootstrap.min.css", "text/css", "sha512-GQGU0fMMi238uA+a/bdWJfpUGKUkBdgfFdgBm72SUQ6BeyWjoY/ton0tEjH+OSH9iP4Dfh+7HM0I9f5eR0L/4w==", "anonymous", "");
|
||||
await interop.IncludeScript("", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/js/bootstrap.bundle.min.js", "sha512-pax4MlgXjHEPfCwcJLQhigY7+N8rt6bVvWLFyUMuxShv170X53TRzGPmPkZmGBhk+jikR8WBM4yl7A9WMHHqvg==", "anonymous", "", "head", "");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,7 +113,7 @@ else
|
||||
<TabPanel Name="Upload" ResourceKey="Upload" Security="SecurityAccessLevel.Host">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" HelpText="Upload one or more translations. Once they are uploaded click Install to complete the installation." ResourceKey="Module">Language: </Label>
|
||||
<Label Class="col-sm-3" HelpText="Upload one or more translations. Once they are uploaded click Install to complete the installation." ResourceKey="LanguageUpload">Language: </Label>
|
||||
<div class="col-sm-9">
|
||||
<FileManager Folder="@Constants.PackagesFolder" UploadMultiple="true" />
|
||||
</div>
|
||||
@ -350,7 +350,7 @@ else
|
||||
var localizationCookieValue = CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture));
|
||||
await interop.SetCookie(CookieRequestCultureProvider.DefaultCookieName, localizationCookieValue, 360);
|
||||
|
||||
NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true);
|
||||
NavigationManager.NavigateTo(NavigationManager.Uri, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,100 +10,32 @@
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="dateTime" HelpText="The date and time of this log" ResourceKey="DateTime">Date/Time: </Label>
|
||||
<Label Class="col-sm-3" For="dateTime" HelpText="The date and time of this log" ResourceKey="DateTime">Date/Time: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="dateTime" class="form-control" @bind="@_logDate" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="level" HelpText="The level of this log" ResourceKey="Level">Level: </Label>
|
||||
<Label Class="col-sm-3" For="level" HelpText="The level of this log" ResourceKey="Level">Level: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="level" class="form-control" @bind="@_level" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="feature" HelpText="The feature that was affected" ResourceKey="Feature">Feature: </Label>
|
||||
<Label Class="col-sm-3" For="feature" HelpText="The feature that was affected" ResourceKey="Feature">Feature: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="feature" class="form-control" @bind="@_feature" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="function" HelpText="The function that was performed" ResourceKey="Function">Function: </Label>
|
||||
<Label Class="col-sm-3" For="function" HelpText="The function that was performed" ResourceKey="Function">Function: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="function" class="form-control" @bind="@_function" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="category" HelpText="The categories that were affected" ResourceKey="Category">Category: </Label>
|
||||
<Label Class="col-sm-3" For="category" HelpText="The categories that were affected" ResourceKey="Category">Category: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="category" class="form-control" @bind="@_category" readonly />
|
||||
</div>
|
||||
@ -111,7 +43,7 @@
|
||||
@if (_pageName != string.Empty)
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="page" HelpText="The page that was affected" ResourceKey="Page">Page: </Label>
|
||||
<Label Class="col-sm-3" For="page" HelpText="The page that was affected" ResourceKey="Page">Page: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="page" class="form-control" @bind="@_pageName" readonly />
|
||||
</div>
|
||||
@ -120,7 +52,7 @@
|
||||
@if (_moduleTitle != string.Empty)
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="module" HelpText="The module that was affected" ResourceKey="Module">Module: </Label>
|
||||
<Label Class="col-sm-3" For="module" HelpText="The module that was affected" ResourceKey="Module">Module: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="module" class="form-control" @bind="@_moduleTitle" readonly />
|
||||
</div>
|
||||
@ -129,26 +61,26 @@
|
||||
@if (_username != string.Empty)
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="user" HelpText="The user that caused this log" ResourceKey="User">User: </Label>
|
||||
<Label Class="col-sm-3" For="user" HelpText="The user that caused this log" ResourceKey="User">User: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="user" class="form-control" @bind="@_username" readonly />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="url" HelpText="The url the log comes from" ResourceKey="Url">Url: </Label>
|
||||
<Label Class="col-sm-3" For="url" HelpText="The url the log comes from" ResourceKey="Url">Url: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="url" class="form-control" @bind="@_url" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="template" HelpText="What the log is about" ResourceKey="Template">Template: </Label>
|
||||
<Label Class="col-sm-3" For="template" HelpText="What the log is about" ResourceKey="Template">Template: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="template" class="form-control" @bind="@_template" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="message" HelpText="The message that the system generated" ResourceKey="Message">Message: </Label>
|
||||
<Label Class="col-sm-3" For="message" HelpText="The message that the system generated" ResourceKey="Message">Message: </Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="message" class="form-control" @bind="@_message" rows="5" readonly></textarea>
|
||||
</div>
|
||||
@ -156,24 +88,25 @@
|
||||
@if (!string.IsNullOrEmpty(_exception))
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="exception" HelpText="The exceptions generated by the system" ResourceKey="Exception">Exception: </Label>
|
||||
<div class="col-sm-9">
|
||||
<Label Class="col-sm-3" For="exception" HelpText="The exceptions generated by the system" ResourceKey="Exception">Exception: </Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="exception" class="form-control" @bind="@_exception" rows="5" readonly></textarea>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="properties" HelpText="The properties that were affected" ResourceKey="Properties">Properties: </Label>
|
||||
<Label Class="col-sm-3" For="properties" HelpText="The properties that were affected" ResourceKey="Properties">Properties: </Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="properties" class="form-control" @bind="@_properties" rows="5" readonly></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="server" HelpText="The server that was affected" ResourceKey="Server">Server: </Label>
|
||||
<div class="col-sm-9">
|
||||
<Label Class="col-sm-3" For="server" HelpText="The server that was affected" ResourceKey="Server">Server: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="server" class="form-control" @bind="@_server" readonly />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
|
||||
|
@ -51,11 +51,11 @@ else
|
||||
{
|
||||
<Pager Items="@_logs">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@Localizer["Date"]</th>
|
||||
<th>@Localizer["Level"]</th>
|
||||
<th>@Localizer["Feature"]</th>
|
||||
<th>@Localizer["Function"]</th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@Localizer["Date"]</th>
|
||||
<th>@Localizer["Level"]</th>
|
||||
<th>@Localizer["Feature"]</th>
|
||||
<th>@Localizer["Function"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td class="@GetClass(context.Function)"><ActionLink Action="Detail" Parameters="@($"id=" + context.LogId.ToString())" ResourceKey="LogDetails" /></td>
|
||||
|
@ -1,7 +1,9 @@
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Documentation;
|
||||
using Oqtane.Models;
|
||||
|
||||
namespace Oqtane.Modules.Admin.ModuleCreator
|
||||
{
|
||||
[PrivateApi("Mark this as private, since it's not very useful in the public docs")]
|
||||
public class ModuleInfo : IModule
|
||||
{
|
||||
public ModuleDefinition ModuleDefinition => new ModuleDefinition
|
||||
|
@ -22,6 +22,7 @@ else
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@SharedLocalizer["Name"]</th>
|
||||
<th>@SharedLocalizer["Version"]</th>
|
||||
<th>@Localizer["InUse"]</th>
|
||||
<th>@SharedLocalizer["Expires"]</th>
|
||||
<th style="width: 1px;"> </th>
|
||||
</Header>
|
||||
@ -35,6 +36,16 @@ else
|
||||
</td>
|
||||
<td>@context.Name</td>
|
||||
<td>@context.Version</td>
|
||||
<td>
|
||||
@if(context.AssemblyName == "Oqtane.Client" || PageState.Modules.Where(m => m.ModuleDefinition.ModuleDefinitionId == context.ModuleDefinitionId).Count() > 0)
|
||||
{
|
||||
<span>@SharedLocalizer["Yes"]</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>@SharedLocalizer["No"]</span>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
@((MarkupString)PurchaseLink(context.PackageName))
|
||||
</td>
|
||||
|
@ -3,13 +3,14 @@
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IPageService PageService
|
||||
@inject IPageModuleService PageModuleService
|
||||
@inject IThemeService ThemeService
|
||||
@inject IStringLocalizer<Edit> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||
<TabStrip Refresh="@_refresh">
|
||||
<TabPanel Name="Settings" ResourceKey="Settings">
|
||||
<TabPanel Name="Settings" ResourceKey="Settings" Heading=@Localizer["Settings.Heading"]>
|
||||
@if (_themeList != null)
|
||||
{
|
||||
<div class="container">
|
||||
@ -151,10 +152,27 @@
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<PermissionGrid EntityName="@EntityNames.Page" Permissions="@_permissions" @ref="_permissionGrid" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
}
|
||||
</TabPanel>
|
||||
<TabPanel Name="PageModules" Heading="Modules" ResourceKey="PageModules">
|
||||
@if(_pageModules != null)
|
||||
{
|
||||
<Pager Items="_pageModules">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@Localizer["ModuleTitle"]</th>
|
||||
<th>@Localizer["ModuleDefinition"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><ActionLink Action="Settings" Text="Edit" ModuleId="@context.ModuleId" Security="SecurityAccessLevel.Edit" Permissions="@context.Permissions" ResourceKey="ModuleSettings" /></td>
|
||||
<td><ActionDialog Header="Delete Module" Message="Are You Sure You Wish To Delete This Module?" Action="Delete" Security="SecurityAccessLevel.Edit" Permissions="@context.Permissions" Class="btn btn-danger" OnClick="@(async () => await DeleteModule(context))" ResourceKey="DeleteModule" /></td>
|
||||
<td>@context.Title</td>
|
||||
<td>@context.ModuleDefinition?.Name</td>
|
||||
</Row>
|
||||
</Pager>
|
||||
}
|
||||
</TabPanel>
|
||||
@if (_themeSettingsType != null)
|
||||
@ -170,114 +188,136 @@
|
||||
</form>
|
||||
|
||||
@code {
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private List<Theme> _themeList;
|
||||
private List<ThemeControl> _themes = new List<ThemeControl>();
|
||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||
private List<Page> _pageList;
|
||||
private int _pageId;
|
||||
private string _name;
|
||||
private string _title;
|
||||
private string _path;
|
||||
private string _currentparentid;
|
||||
private string _parentid = "-1";
|
||||
private string _insert = "=";
|
||||
private List<Page> _children;
|
||||
private int _childid = -1;
|
||||
private string _isnavigation;
|
||||
private string _isclickable;
|
||||
private string _url;
|
||||
private string _ispersonalizable;
|
||||
private string _themetype;
|
||||
private string _containertype = "-";
|
||||
private string _icon;
|
||||
private string _permissions = null;
|
||||
private string _createdby;
|
||||
private DateTime _createdon;
|
||||
private string _modifiedby;
|
||||
private DateTime _modifiedon;
|
||||
private string _deletedby;
|
||||
private DateTime? _deletedon;
|
||||
private PermissionGrid _permissionGrid;
|
||||
private Type _themeSettingsType;
|
||||
private object _themeSettings;
|
||||
private RenderFragment ThemeSettingsComponent { get; set; }
|
||||
private bool _refresh = false;
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private List<Theme> _themeList;
|
||||
private List<ThemeControl> _themes = new List<ThemeControl>();
|
||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||
private List<Page> _pageList;
|
||||
private List<Module> _pageModules;
|
||||
private int _pageId;
|
||||
private string _name;
|
||||
private string _title;
|
||||
private string _path;
|
||||
private string _currentparentid;
|
||||
private string _parentid = "-1";
|
||||
private string _insert = "=";
|
||||
private List<Page> _children;
|
||||
private int _childid = -1;
|
||||
private string _isnavigation;
|
||||
private string _isclickable;
|
||||
private string _url;
|
||||
private string _ispersonalizable;
|
||||
private string _themetype;
|
||||
private string _containertype = "-";
|
||||
private string _icon;
|
||||
private string _permissions = null;
|
||||
private string _createdby;
|
||||
private DateTime _createdon;
|
||||
private string _modifiedby;
|
||||
private DateTime _modifiedon;
|
||||
private string _deletedby;
|
||||
private DateTime? _deletedon;
|
||||
private PermissionGrid _permissionGrid;
|
||||
private Type _themeSettingsType;
|
||||
private object _themeSettings;
|
||||
private RenderFragment ThemeSettingsComponent { get; set; }
|
||||
private bool _refresh = false;
|
||||
protected Page page;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_pageList = PageState.Pages;
|
||||
_children = PageState.Pages.Where(item => item.ParentId == null).ToList();
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_pageList = PageState.Pages;
|
||||
_children = PageState.Pages.Where(item => item.ParentId == null).ToList();
|
||||
_themeList = await ThemeService.GetThemesAsync();
|
||||
_themes = ThemeService.GetThemeControls(_themeList);
|
||||
|
||||
_themeList = await ThemeService.GetThemesAsync();
|
||||
_themes = ThemeService.GetThemeControls(_themeList);
|
||||
_pageId = Int32.Parse(PageState.QueryString["id"]);
|
||||
page = PageState.Pages.FirstOrDefault(item => item.PageId == _pageId);
|
||||
|
||||
_pageId = Int32.Parse(PageState.QueryString["id"]);
|
||||
var page = PageState.Pages.FirstOrDefault(item => item.PageId == _pageId);
|
||||
if (page != null)
|
||||
{
|
||||
_name = page.Name;
|
||||
_title = page.Title;
|
||||
_path = page.Path;
|
||||
if (page != null)
|
||||
{
|
||||
_name = page.Name;
|
||||
_title = page.Title;
|
||||
_path = page.Path;
|
||||
_pageModules = PageState.Modules.Where(m => m.PageId == page.PageId && m.IsDeleted == false).ToList();
|
||||
|
||||
if (string.IsNullOrEmpty(_path))
|
||||
{
|
||||
_path = "/";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_path.Contains("/"))
|
||||
{
|
||||
_path = _path.Substring(_path.LastIndexOf("/") + 1);
|
||||
}
|
||||
}
|
||||
if (string.IsNullOrEmpty(_path))
|
||||
{
|
||||
_path = "/";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_path.Contains("/"))
|
||||
{
|
||||
_path = _path.Substring(_path.LastIndexOf("/") + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (page.ParentId == null)
|
||||
{
|
||||
_parentid = "-1";
|
||||
}
|
||||
else
|
||||
{
|
||||
_parentid = page.ParentId.ToString();
|
||||
}
|
||||
if (page.ParentId == null)
|
||||
{
|
||||
_parentid = "-1";
|
||||
}
|
||||
else
|
||||
{
|
||||
_parentid = page.ParentId.ToString();
|
||||
}
|
||||
|
||||
_currentparentid = _parentid;
|
||||
_isnavigation = page.IsNavigation.ToString();
|
||||
_isclickable = page.IsClickable.ToString();
|
||||
_url = page.Url;
|
||||
_ispersonalizable = page.IsPersonalizable.ToString();
|
||||
_themetype = page.ThemeType;
|
||||
if (string.IsNullOrEmpty(_themetype))
|
||||
{
|
||||
_themetype = PageState.Site.DefaultThemeType;
|
||||
}
|
||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
||||
_containertype = page.DefaultContainerType;
|
||||
if (string.IsNullOrEmpty(_containertype))
|
||||
{
|
||||
_containertype = PageState.Site.DefaultContainerType;
|
||||
}
|
||||
_icon = page.Icon;
|
||||
_permissions = page.Permissions;
|
||||
_createdby = page.CreatedBy;
|
||||
_createdon = page.CreatedOn;
|
||||
_modifiedby = page.ModifiedBy;
|
||||
_modifiedon = page.ModifiedOn;
|
||||
_deletedby = page.DeletedBy;
|
||||
_deletedon = page.DeletedOn;
|
||||
_currentparentid = _parentid;
|
||||
_isnavigation = page.IsNavigation.ToString();
|
||||
_isclickable = page.IsClickable.ToString();
|
||||
_url = page.Url;
|
||||
_ispersonalizable = page.IsPersonalizable.ToString();
|
||||
_themetype = page.ThemeType;
|
||||
if (string.IsNullOrEmpty(_themetype))
|
||||
{
|
||||
_themetype = PageState.Site.DefaultThemeType;
|
||||
}
|
||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
||||
_containertype = page.DefaultContainerType;
|
||||
if (string.IsNullOrEmpty(_containertype))
|
||||
{
|
||||
_containertype = PageState.Site.DefaultContainerType;
|
||||
}
|
||||
_icon = page.Icon;
|
||||
_permissions = page.Permissions;
|
||||
_createdby = page.CreatedBy;
|
||||
_createdon = page.CreatedOn;
|
||||
_modifiedby = page.ModifiedBy;
|
||||
_modifiedon = page.ModifiedOn;
|
||||
_deletedby = page.DeletedBy;
|
||||
_deletedon = page.DeletedOn;
|
||||
|
||||
ThemeSettings();
|
||||
}
|
||||
ThemeSettings();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Page {PageId} {Error}", _pageId, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Page.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DeleteModule(Module module)
|
||||
{
|
||||
try
|
||||
{
|
||||
PageModule pagemodule = await PageModuleService.GetPageModuleAsync(page.PageId, module.ModuleId);
|
||||
pagemodule.IsDeleted = true;
|
||||
await PageModuleService.UpdatePageModuleAsync(pagemodule);
|
||||
await logger.LogInformation(LogFunction.Update,"Module Deleted {Title}", module.Title);
|
||||
_pageModules.RemoveAll(item => item.PageModuleId == pagemodule.PageModuleId);
|
||||
StateHasChanged();
|
||||
NavigationManager.NavigateTo(NavigationManager.Uri + "&tab=PageModules");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Page {PageId} {Error}", _pageId, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Page.Load"], MessageType.Error);
|
||||
await logger.LogError(ex, "Error Deleting Module {Title} {Error}", module.Title, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Module.Delete"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
<th>@Localizer["DeletedOn"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><button @onclick="@(() => RestorePage(context))" class="btn btn-info" title="Restore">Restore</button></td>
|
||||
<td><button type="button" @onclick="@(() => RestorePage(context))" class="btn btn-info" title="Restore">Restore</button></td>
|
||||
<td><ActionDialog Header="Delete Page" Message="@string.Format(Localizer["Confirm.Page.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeletePage(context))" ResourceKey="DeletePage" /></td>
|
||||
<td>@context.Name</td>
|
||||
<td>@context.DeletedBy</td>
|
||||
@ -34,9 +34,7 @@
|
||||
</Pager>
|
||||
@if (_pages.Any())
|
||||
{
|
||||
<div style="text-align:right;">
|
||||
<ActionDialog Header="Delete All Pages" Message="Are You Sure You Wish To Permanently Delete All Pages?" Action="Delete All Pages" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllPages())" ResourceKey="DeleteAllPages" />
|
||||
</div>
|
||||
<br /><ActionDialog Header="Delete All Pages" Message="Are You Sure You Wish To Permanently Delete All Pages?" Action="Delete All Pages" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllPages())" ResourceKey="DeleteAllPages" />
|
||||
}
|
||||
}
|
||||
</TabPanel>
|
||||
@ -58,7 +56,7 @@
|
||||
<th>@Localizer["DeletedOn"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><button @onclick="@(() => RestoreModule(context))" class="btn btn-info" title="Restore">@Localizer["Restore"]</button></td>
|
||||
<td><button type="button" @onclick="@(() => RestoreModule(context))" class="btn btn-info" title="Restore">@Localizer["Restore"]</button></td>
|
||||
<td><ActionDialog Header="Delete Module" Message="@string.Format(Localizer["Confirm.Module.Delete"], context.Title)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteModule(context))" ResourceKey="DeleteModule" /></td>
|
||||
<td>@PageState.Pages.Find(item => item.PageId == context.PageId).Name</td>
|
||||
<td>@context.Title</td>
|
||||
@ -68,9 +66,7 @@
|
||||
</Pager>
|
||||
@if (_modules.Any())
|
||||
{
|
||||
<div style="text-align:right;">
|
||||
<ActionDialog Header="Delete All Modules" Message="Are You Sure You Wish To Permanently Delete All Modules?" Action="Delete All Modules" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllModules())" ResourceKey="DeleteAllModules" />
|
||||
</div>
|
||||
<br /><ActionDialog Header="Delete All Modules" Message="Are You Sure You Wish To Permanently Delete All Modules?" Action="Delete All Modules" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllModules())" ResourceKey="DeleteAllModules" />
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -34,15 +34,6 @@
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="allowRegister" HelpText="Do you want the users to be able to register for an account on the site" ResourceKey="AllowRegistration">Allow User Registration? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="allowRegister" class="form-select" @bind="@_allowregistration" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="isDeleted" HelpText="Is this site deleted?" ResourceKey="IsDeleted">Is Deleted? </Label>
|
||||
<div class="col-sm-9">
|
||||
@ -240,243 +231,246 @@
|
||||
}
|
||||
|
||||
@code {
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private bool _initialized = false;
|
||||
private List<Theme> _themeList;
|
||||
private List<ThemeControl> _themes = new List<ThemeControl>();
|
||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||
private string _name = string.Empty;
|
||||
private List<Alias> _aliasList;
|
||||
private string _urls = string.Empty;
|
||||
private string _runtime = "";
|
||||
private string _prerender = "";
|
||||
private int _logofileid = -1;
|
||||
private FileManager _logofilemanager;
|
||||
private int _faviconfileid = -1;
|
||||
private FileManager _faviconfilemanager;
|
||||
private string _themetype = "-";
|
||||
private string _containertype = "-";
|
||||
private string _admincontainertype = "-";
|
||||
private string _allowregistration;
|
||||
private string _smtphost = string.Empty;
|
||||
private string _smtpport = string.Empty;
|
||||
private string _smtpssl = "False";
|
||||
private string _smtpusername = string.Empty;
|
||||
private string _smtppassword = string.Empty;
|
||||
private string _smtpsender = string.Empty;
|
||||
private string _pwaisenabled;
|
||||
private int _pwaappiconfileid = -1;
|
||||
private FileManager _pwaappiconfilemanager;
|
||||
private int _pwasplashiconfileid = -1;
|
||||
private FileManager _pwasplashiconfilemanager;
|
||||
private string _tenant = string.Empty;
|
||||
private string _database = string.Empty;
|
||||
private string _connectionstring = string.Empty;
|
||||
private string _createdby;
|
||||
private DateTime _createdon;
|
||||
private string _modifiedby;
|
||||
private DateTime _modifiedon;
|
||||
private string _deletedby;
|
||||
private DateTime? _deletedon;
|
||||
private string _isdeleted;
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private bool _initialized = false;
|
||||
private List<Theme> _themeList;
|
||||
private List<ThemeControl> _themes = new List<ThemeControl>();
|
||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||
private string _name = string.Empty;
|
||||
private List<Alias> _aliasList;
|
||||
private string _urls = string.Empty;
|
||||
private string _runtime = "";
|
||||
private string _prerender = "";
|
||||
private int _logofileid = -1;
|
||||
private FileManager _logofilemanager;
|
||||
private int _faviconfileid = -1;
|
||||
private FileManager _faviconfilemanager;
|
||||
private string _themetype = "-";
|
||||
private string _containertype = "-";
|
||||
private string _admincontainertype = "-";
|
||||
private string _smtphost = string.Empty;
|
||||
private string _smtpport = string.Empty;
|
||||
private string _smtpssl = "False";
|
||||
private string _smtpusername = string.Empty;
|
||||
private string _smtppassword = string.Empty;
|
||||
private string _smtpsender = string.Empty;
|
||||
private string _pwaisenabled;
|
||||
private int _pwaappiconfileid = -1;
|
||||
private FileManager _pwaappiconfilemanager;
|
||||
private int _pwasplashiconfileid = -1;
|
||||
private FileManager _pwasplashiconfilemanager;
|
||||
private string _tenant = string.Empty;
|
||||
private string _database = string.Empty;
|
||||
private string _connectionstring = string.Empty;
|
||||
private string _createdby;
|
||||
private DateTime _createdon;
|
||||
private string _modifiedby;
|
||||
private DateTime _modifiedon;
|
||||
private string _deletedby;
|
||||
private DateTime? _deletedon;
|
||||
private string _isdeleted;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_themeList = await ThemeService.GetThemesAsync();
|
||||
Site site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
|
||||
if (site != null)
|
||||
{
|
||||
_name = site.Name;
|
||||
_runtime = site.Runtime;
|
||||
_prerender = site.RenderMode.Replace(_runtime, "");
|
||||
_allowregistration = site.AllowRegistration.ToString();
|
||||
_isdeleted = site.IsDeleted.ToString();
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_themeList = await ThemeService.GetThemesAsync();
|
||||
Site site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
|
||||
if (site != null)
|
||||
{
|
||||
_name = site.Name;
|
||||
_runtime = site.Runtime;
|
||||
_prerender = site.RenderMode.Replace(_runtime, "");
|
||||
_isdeleted = site.IsDeleted.ToString();
|
||||
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
_aliasList = await AliasService.GetAliasesAsync();
|
||||
foreach (Alias alias in _aliasList.Where(item => item.SiteId == site.SiteId && item.TenantId == site.TenantId).ToList())
|
||||
{
|
||||
_urls += alias.Name + ",";
|
||||
}
|
||||
_urls = _urls.Substring(0, _urls.Length - 1);
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
_aliasList = await AliasService.GetAliasesAsync();
|
||||
foreach (Alias alias in _aliasList.Where(item => item.SiteId == site.SiteId && item.TenantId == site.TenantId).ToList())
|
||||
{
|
||||
_urls += alias.Name + ",";
|
||||
}
|
||||
_urls = _urls.Substring(0, _urls.Length - 1);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (site.LogoFileId != null)
|
||||
{
|
||||
_logofileid = site.LogoFileId.Value;
|
||||
}
|
||||
if (site.LogoFileId != null)
|
||||
{
|
||||
_logofileid = site.LogoFileId.Value;
|
||||
}
|
||||
|
||||
if (site.FaviconFileId != null)
|
||||
{
|
||||
_faviconfileid = site.FaviconFileId.Value;
|
||||
}
|
||||
if (site.FaviconFileId != null)
|
||||
{
|
||||
_faviconfileid = site.FaviconFileId.Value;
|
||||
}
|
||||
|
||||
_themes = ThemeService.GetThemeControls(_themeList);
|
||||
_themetype = (!string.IsNullOrEmpty(site.DefaultThemeType)) ? site.DefaultThemeType : Constants.DefaultTheme;
|
||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
||||
_containertype = (!string.IsNullOrEmpty(site.DefaultContainerType)) ? site.DefaultContainerType : Constants.DefaultContainer;
|
||||
_admincontainertype = (!string.IsNullOrEmpty(site.AdminContainerType)) ? site.AdminContainerType : Constants.DefaultAdminContainer;
|
||||
_themes = ThemeService.GetThemeControls(_themeList);
|
||||
_themetype = (!string.IsNullOrEmpty(site.DefaultThemeType)) ? site.DefaultThemeType : Constants.DefaultTheme;
|
||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
||||
_containertype = (!string.IsNullOrEmpty(site.DefaultContainerType)) ? site.DefaultContainerType : Constants.DefaultContainer;
|
||||
_admincontainertype = (!string.IsNullOrEmpty(site.AdminContainerType)) ? site.AdminContainerType : Constants.DefaultAdminContainer;
|
||||
|
||||
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
||||
_smtphost = SettingService.GetSetting(settings, "SMTPHost", string.Empty);
|
||||
_smtpport = SettingService.GetSetting(settings, "SMTPPort", string.Empty);
|
||||
_smtpssl = SettingService.GetSetting(settings, "SMTPSSL", "False");
|
||||
_smtpusername = SettingService.GetSetting(settings, "SMTPUsername", string.Empty);
|
||||
_smtppassword = SettingService.GetSetting(settings, "SMTPPassword", string.Empty);
|
||||
_smtpsender = SettingService.GetSetting(settings, "SMTPSender", string.Empty);
|
||||
_pwaisenabled = site.PwaIsEnabled.ToString();
|
||||
if (site.PwaAppIconFileId != null)
|
||||
{
|
||||
_pwaappiconfileid = site.PwaAppIconFileId.Value;
|
||||
}
|
||||
if (site.PwaSplashIconFileId != null)
|
||||
{
|
||||
_pwasplashiconfileid = site.PwaSplashIconFileId.Value;
|
||||
}
|
||||
|
||||
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
||||
_smtphost = SettingService.GetSetting(settings, "SMTPHost", string.Empty);
|
||||
_smtpport = SettingService.GetSetting(settings, "SMTPPort", string.Empty);
|
||||
_smtpssl = SettingService.GetSetting(settings, "SMTPSSL", "False");
|
||||
_smtpusername = SettingService.GetSetting(settings, "SMTPUsername", string.Empty);
|
||||
_smtppassword = SettingService.GetSetting(settings, "SMTPPassword", string.Empty);
|
||||
_smtpsender = SettingService.GetSetting(settings, "SMTPSender", string.Empty);
|
||||
|
||||
_pwaisenabled = site.PwaIsEnabled.ToString();
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
var tenants = await TenantService.GetTenantsAsync();
|
||||
var _databases = await DatabaseService.GetDatabasesAsync();
|
||||
var tenant = tenants.Find(item => item.TenantId == site.TenantId);
|
||||
if (tenant != null)
|
||||
{
|
||||
_tenant = tenant.Name;
|
||||
_database = _databases.Find(item => item.DBType == tenant.DBType)?.Name;
|
||||
_connectionstring = tenant.DBConnectionString;
|
||||
}
|
||||
}
|
||||
|
||||
if (site.PwaAppIconFileId != null)
|
||||
{
|
||||
_pwaappiconfileid = site.PwaAppIconFileId.Value;
|
||||
}
|
||||
_createdby = site.CreatedBy;
|
||||
_createdon = site.CreatedOn;
|
||||
_modifiedby = site.ModifiedBy;
|
||||
_modifiedon = site.ModifiedOn;
|
||||
_deletedby = site.DeletedBy;
|
||||
_deletedon = site.DeletedOn;
|
||||
|
||||
if (site.PwaSplashIconFileId != null)
|
||||
{
|
||||
_pwasplashiconfileid = site.PwaSplashIconFileId.Value;
|
||||
}
|
||||
_initialized = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Site {SiteId} {Error}", PageState.Site.SiteId, ex.Message);
|
||||
AddModuleMessage(ex.Message, MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
_pwaisenabled = site.PwaIsEnabled.ToString();
|
||||
if (site.PwaAppIconFileId != null)
|
||||
{
|
||||
_pwaappiconfileid = site.PwaAppIconFileId.Value;
|
||||
}
|
||||
if (site.PwaSplashIconFileId != null)
|
||||
{
|
||||
_pwasplashiconfileid = site.PwaSplashIconFileId.Value;
|
||||
}
|
||||
private async void ThemeChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_themetype = (string)e.Value;
|
||||
if (_themetype != "-")
|
||||
{
|
||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
||||
}
|
||||
else
|
||||
{
|
||||
_containers = new List<ThemeControl>();
|
||||
}
|
||||
_containertype = "-";
|
||||
_admincontainertype = Constants.DefaultAdminContainer;
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", _themetype, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Theme.LoadPane"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
var tenants = await TenantService.GetTenantsAsync();
|
||||
var _databases = await DatabaseService.GetDatabasesAsync();
|
||||
var tenant = tenants.Find(item => item.TenantId == site.TenantId);
|
||||
if (tenant != null)
|
||||
{
|
||||
_tenant = tenant.Name;
|
||||
_database = _databases.Find(item => item.DBType == tenant.DBType)?.Name;
|
||||
_connectionstring = tenant.DBConnectionString;
|
||||
}
|
||||
}
|
||||
private async Task SaveSite()
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_name != string.Empty && _urls != string.Empty && _themetype != "-" && _containertype != "-")
|
||||
{
|
||||
var unique = true;
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
foreach (string name in _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
if (_aliasList.Exists(item => item.Name == name && item.SiteId != PageState.Alias.SiteId && item.TenantId != PageState.Alias.TenantId))
|
||||
{
|
||||
unique = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_createdby = site.CreatedBy;
|
||||
_createdon = site.CreatedOn;
|
||||
_modifiedby = site.ModifiedBy;
|
||||
_modifiedon = site.ModifiedOn;
|
||||
_deletedby = site.DeletedBy;
|
||||
_deletedon = site.DeletedOn;
|
||||
if (unique)
|
||||
{
|
||||
var site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
|
||||
if (site != null)
|
||||
{
|
||||
bool refresh = false;
|
||||
bool reload = false;
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Site {SiteId} {Error}", PageState.Site.SiteId, ex.Message);
|
||||
AddModuleMessage(ex.Message, MessageType.Error);
|
||||
}
|
||||
}
|
||||
site.Name = _name;
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
if (site.Runtime != _runtime || site.RenderMode != _runtime + _prerender)
|
||||
{
|
||||
site.Runtime = _runtime;
|
||||
site.RenderMode = _runtime + _prerender;
|
||||
refresh = true;
|
||||
reload = true; // needs to be reloaded on server
|
||||
}
|
||||
}
|
||||
site.IsDeleted = (_isdeleted == null ? true : Boolean.Parse(_isdeleted));
|
||||
|
||||
private async void ThemeChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_themetype = (string)e.Value;
|
||||
if (_themetype != "-")
|
||||
{
|
||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
||||
}
|
||||
else
|
||||
{
|
||||
_containers = new List<ThemeControl>();
|
||||
}
|
||||
_containertype = "-";
|
||||
_admincontainertype = Constants.DefaultAdminContainer;
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", _themetype, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Theme.LoadPane"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
site.LogoFileId = null;
|
||||
var logofileid = _logofilemanager.GetFileId();
|
||||
if (logofileid != -1)
|
||||
{
|
||||
site.LogoFileId = logofileid;
|
||||
}
|
||||
int? faviconFieldId = _faviconfilemanager.GetFileId();
|
||||
if (faviconFieldId == -1) faviconFieldId = null;
|
||||
if (site.FaviconFileId != faviconFieldId)
|
||||
{
|
||||
site.FaviconFileId = faviconFieldId;
|
||||
reload = true; // needs to be reloaded on server
|
||||
}
|
||||
if (site.DefaultThemeType != _themetype)
|
||||
{
|
||||
site.DefaultThemeType = _themetype;
|
||||
refresh = true; // needs to be refreshed on client
|
||||
}
|
||||
if (site.DefaultContainerType != _containertype)
|
||||
{
|
||||
site.DefaultContainerType = _containertype;
|
||||
refresh = true; // needs to be refreshed on client
|
||||
}
|
||||
site.AdminContainerType = _admincontainertype;
|
||||
|
||||
private async Task SaveSite()
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_name != string.Empty && _urls != string.Empty && _themetype != "-" && _containertype != "-")
|
||||
{
|
||||
var unique = true;
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
foreach (string name in _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
if (_aliasList.Exists(item => item.Name == name && item.SiteId != PageState.Alias.SiteId && item.TenantId != PageState.Alias.TenantId))
|
||||
{
|
||||
unique = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (unique)
|
||||
{
|
||||
var site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
|
||||
if (site != null)
|
||||
{
|
||||
bool reload = false;
|
||||
bool refresh = (site.DefaultThemeType != _themetype || site.DefaultContainerType != _containertype);
|
||||
|
||||
site.Name = _name;
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
if (site.Runtime != _runtime || site.RenderMode != _runtime + _prerender)
|
||||
{
|
||||
site.Runtime = _runtime;
|
||||
site.RenderMode = _runtime + _prerender;
|
||||
refresh = true;
|
||||
reload = true;
|
||||
}
|
||||
}
|
||||
site.AllowRegistration = (_allowregistration == null ? true : Boolean.Parse(_allowregistration));
|
||||
site.IsDeleted = (_isdeleted == null ? true : Boolean.Parse(_isdeleted));
|
||||
|
||||
site.LogoFileId = null;
|
||||
var logofileid = _logofilemanager.GetFileId();
|
||||
if (logofileid != -1)
|
||||
{
|
||||
site.LogoFileId = logofileid;
|
||||
}
|
||||
var faviconFieldId = _faviconfilemanager.GetFileId();
|
||||
if (faviconFieldId != -1)
|
||||
{
|
||||
site.FaviconFileId = faviconFieldId;
|
||||
}
|
||||
site.DefaultThemeType = _themetype;
|
||||
site.DefaultContainerType = _containertype;
|
||||
site.AdminContainerType = _admincontainertype;
|
||||
|
||||
site.PwaIsEnabled = (_pwaisenabled == null ? true : Boolean.Parse(_pwaisenabled));
|
||||
var pwaappiconfileid = _pwaappiconfilemanager.GetFileId();
|
||||
if (pwaappiconfileid != -1)
|
||||
if (site.PwaIsEnabled.ToString() != _pwaisenabled)
|
||||
{
|
||||
site.PwaIsEnabled = Boolean.Parse(_pwaisenabled);
|
||||
reload = true; // needs to be reloaded on server
|
||||
}
|
||||
int? pwaappiconfileid = _pwaappiconfilemanager.GetFileId();
|
||||
if (pwaappiconfileid == -1) pwaappiconfileid = null;
|
||||
if (site.PwaAppIconFileId != pwaappiconfileid)
|
||||
{
|
||||
site.PwaAppIconFileId = pwaappiconfileid;
|
||||
reload = true; // needs to be reloaded on server
|
||||
}
|
||||
var pwasplashiconfileid = _pwasplashiconfilemanager.GetFileId();
|
||||
if (pwasplashiconfileid != -1)
|
||||
int? pwasplashiconfileid = _pwasplashiconfilemanager.GetFileId();
|
||||
if (pwasplashiconfileid == -1) pwasplashiconfileid = null;
|
||||
if (site.PwaSplashIconFileId != pwasplashiconfileid)
|
||||
{
|
||||
site.PwaSplashIconFileId = pwasplashiconfileid;
|
||||
reload = true; // needs to be reloaded on server
|
||||
}
|
||||
|
||||
site = await SiteService.UpdateSiteAsync(site);
|
||||
@ -518,7 +512,7 @@
|
||||
|
||||
if (refresh)
|
||||
{
|
||||
NavigationManager.NavigateTo(NavigateUrl(), reload); // refresh to show new theme or container
|
||||
NavigationManager.NavigateTo(NavigateUrl(true), reload); // refresh/reload
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -52,6 +52,11 @@ else
|
||||
|
||||
private void Edit(string name)
|
||||
{
|
||||
if (name.Equals("*"))
|
||||
{
|
||||
var uri = new Uri(NavigationManager.Uri);
|
||||
name = uri.Authority;
|
||||
}
|
||||
NavigationManager.NavigateTo(_scheme + name + "/admin/site/?reload");
|
||||
}
|
||||
|
||||
|
71
Oqtane.Client/Modules/Admin/UrlMappings/Add.razor
Normal file
71
Oqtane.Client/Modules/Admin/UrlMappings/Add.razor
Normal file
@ -0,0 +1,71 @@
|
||||
@namespace Oqtane.Modules.Admin.UrlMappings
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IUrlMappingService UrlMappingService
|
||||
@inject IStringLocalizer<Edit> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="url" HelpText="The fully qualified Url for this site" ResourceKey="Url">Url:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="url" class="form-control" @bind="@_url" maxlength="500" required />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="mappedurl" HelpText="A fully qualified Url where the user will be redirected" ResourceKey="MappedUrl">Redirect To:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="mappedurl" class="form-control" @bind="@_mappedurl" maxlength="500" required />
|
||||
</div>
|
||||
</div>
|
||||
<br /><br />
|
||||
<button type="button" class="btn btn-success" @onclick="SaveUrlMapping">@SharedLocalizer["Save"]</button>
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@code {
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
|
||||
private string _url = string.Empty;
|
||||
private string _mappedurl = string.Empty;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
private async Task SaveUrlMapping()
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form))
|
||||
{
|
||||
var route = new Route(_url, PageState.Alias.Path);
|
||||
var url = route.SiteUrl + "/" + route.PagePath;
|
||||
|
||||
var urlmapping = new UrlMapping();
|
||||
urlmapping.SiteId = PageState.Site.SiteId;
|
||||
urlmapping.Url = url;
|
||||
urlmapping.MappedUrl = _mappedurl;
|
||||
urlmapping.Requests = 0;
|
||||
urlmapping.CreatedOn = DateTime.UtcNow;
|
||||
urlmapping.RequestedOn = DateTime.UtcNow;
|
||||
|
||||
try
|
||||
{
|
||||
urlmapping = await UrlMappingService.AddUrlMappingAsync(urlmapping);
|
||||
await logger.LogInformation("UrlMapping Saved {UrlMapping}", urlmapping);
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving UrlMapping {UrlMapping} {Error}", urlmapping, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.SaveUrlMapping"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
}
|
83
Oqtane.Client/Modules/Admin/UrlMappings/Edit.razor
Normal file
83
Oqtane.Client/Modules/Admin/UrlMappings/Edit.razor
Normal file
@ -0,0 +1,83 @@
|
||||
@namespace Oqtane.Modules.Admin.UrlMappings
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IUrlMappingService UrlMappingService
|
||||
@inject IStringLocalizer<Edit> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="url" HelpText="A fully qualified Url for this site" ResourceKey="Url">Url:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="url" class="form-control" @bind="@_url" maxlength="500" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="mappedurl" HelpText="A fully qualified Url where the user will be redirected" ResourceKey="MappedUrl">Redirect To:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="mappedurl" class="form-control" @bind="@_mappedurl" maxlength="500" required />
|
||||
</div>
|
||||
</div>
|
||||
<br /><br />
|
||||
<button type="button" class="btn btn-success" @onclick="SaveUrlMapping">@SharedLocalizer["Save"]</button>
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@code {
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
|
||||
private int _urlmappingid;
|
||||
private string _url = string.Empty;
|
||||
private string _mappedurl = string.Empty;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_urlmappingid = Int32.Parse(PageState.QueryString["id"]);
|
||||
var urlmapping = await UrlMappingService.GetUrlMappingAsync(_urlmappingid);
|
||||
if (urlmapping != null)
|
||||
{
|
||||
_url = urlmapping.Url;
|
||||
_mappedurl = urlmapping.MappedUrl;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading UrlMapping {UrlMappingId} {Error}", _urlmappingid, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.LoadUrlMapping"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SaveUrlMapping()
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form))
|
||||
{
|
||||
var urlmapping = await UrlMappingService.GetUrlMappingAsync(_urlmappingid);
|
||||
urlmapping.MappedUrl = _mappedurl;
|
||||
|
||||
try
|
||||
{
|
||||
urlmapping = await UrlMappingService.UpdateUrlMappingAsync(urlmapping);
|
||||
await logger.LogInformation("UrlMapping Saved {UrlMapping}", urlmapping);
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving UrlMapping {UrlMapping} {Error}", urlmapping, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.SaveUrlMapping"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
}
|
140
Oqtane.Client/Modules/Admin/UrlMappings/Index.razor
Normal file
140
Oqtane.Client/Modules/Admin/UrlMappings/Index.razor
Normal file
@ -0,0 +1,140 @@
|
||||
@namespace Oqtane.Modules.Admin.UrlMappings
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IUrlMappingService UrlMappingService
|
||||
@inject ISiteService SiteService
|
||||
@inject IStringLocalizer<Index> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
@if (_urlMappings == null)
|
||||
{
|
||||
<p><em>@SharedLocalizer["Loading"]</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<TabStrip>
|
||||
<TabPanel Name="Urls" Heading="Urls" ResourceKey="Urls">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<div class="col-sm-6">
|
||||
<ActionLink Action="Add" Text="Add Url Mapping" ResourceKey="AddUrlMapping" />
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<select id="type" class="form-select custom-select" @onchange="(e => MappedChanged(e))">
|
||||
<option value="true">@Localizer["Mapped"]</option>
|
||||
<option value="false">@Localizer["Broken"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
<Pager Items="@_urlMappings">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@Localizer["Url"]</th>
|
||||
<th>@Localizer["Requests"]</th>
|
||||
<th>@Localizer["Requested"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.UrlMappingId.ToString())" ResourceKey="Edit" /></td>
|
||||
<td><ActionDialog Header="Delete Url Mapping" Message="@string.Format(Localizer["Confirm.DeleteUrlMapping"], context.Url)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteUrlMapping(context))" ResourceKey="DeleteUrlMapping" /></td>
|
||||
<td>
|
||||
<a href="" onclick="@(() => BrowseUrl(context.Url))">@context.Url</a>
|
||||
@if (_mapped)
|
||||
{
|
||||
@((MarkupString)"<br />>> ")<a href="" onclick="@(() => BrowseUrl(context.MappedUrl))">@context.MappedUrl</a>
|
||||
}
|
||||
</td>
|
||||
<td>@context.Requests</td>
|
||||
<td>@context.RequestedOn</td>
|
||||
</Row>
|
||||
</Pager>
|
||||
</TabPanel>
|
||||
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="capturebrokenurls" HelpText="Specify if broken Urls should be captured automatically and saved in Url Mappings" ResourceKey="CaptureBrokenUrls">Capture Broken Urls? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="capturebrokenurls" class="form-select" @bind="@_capturebrokenurls" >
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button>
|
||||
</TabPanel>
|
||||
</TabStrip>
|
||||
}
|
||||
|
||||
@code {
|
||||
private bool _mapped = true;
|
||||
private List<UrlMapping> _urlMappings;
|
||||
private string _capturebrokenurls;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
await GetUrlMappings();
|
||||
_capturebrokenurls = PageState.Site.CaptureBrokenUrls.ToString();
|
||||
}
|
||||
|
||||
private async void MappedChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_mapped = bool.Parse(e.Value.ToString());
|
||||
await GetUrlMappings();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error On TypeChanged");
|
||||
}
|
||||
}
|
||||
|
||||
private void BrowseUrl(string url)
|
||||
{
|
||||
NavigationManager.NavigateTo(url, true);
|
||||
}
|
||||
|
||||
private async Task DeleteUrlMapping(UrlMapping urlMapping)
|
||||
{
|
||||
try
|
||||
{
|
||||
await UrlMappingService.DeleteUrlMappingAsync(urlMapping.UrlMappingId);
|
||||
await logger.LogInformation("UrlMapping Deleted {UrlMapping}", urlMapping);
|
||||
await GetUrlMappings();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Deleting UrlMapping {UrlMapping} {Error}", urlMapping, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.DeleteUrlMapping"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task GetUrlMappings()
|
||||
{
|
||||
_urlMappings = await UrlMappingService.GetUrlMappingsAsync(PageState.Site.SiteId, _mapped);
|
||||
}
|
||||
|
||||
private async Task SaveSiteSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
var site = PageState.Site;
|
||||
site.CaptureBrokenUrls = bool.Parse(_capturebrokenurls);
|
||||
await SiteService.UpdateSiteAsync(site);
|
||||
AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving Site Settings {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.SaveSiteSettings"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
@inject IUserRoleService UserRoleService
|
||||
@inject IUserService UserService
|
||||
@inject ISettingService SettingService
|
||||
@inject ISiteService SiteService
|
||||
@inject IStringLocalizer<Index> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
@ -14,45 +15,65 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<div class="col-sm-4">
|
||||
<ActionLink Action="Add" Text="Add User" ResourceKey="AddUser" />
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<input class="form-control" @bind="@_search" />
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<button class="btn btn-secondary" @onclick="OnSearch">@SharedLocalizer["Search"]</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Pager Items="@userroles">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@SharedLocalizer["Name"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td>
|
||||
<ActionLink Action="Edit" Parameters="@($"id=" + context.UserId.ToString())" ResourceKey="EditUser" />
|
||||
</td>
|
||||
<td>
|
||||
<ActionDialog Header="Delete User" Message="@string.Format(Localizer["Confirm.User.Delete"], context.User.DisplayName)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteUser(context))" Disabled="@(context.UserId == PageState.User.UserId)" ResourceKey="DeleteUser" />
|
||||
</td>
|
||||
<td>
|
||||
<ActionLink Action="Roles" Parameters="@($"id=" + context.UserId.ToString())" ResourceKey="Roles" />
|
||||
</td>
|
||||
<td>@context.User.DisplayName</td>
|
||||
</Row>
|
||||
</Pager>
|
||||
<TabStrip>
|
||||
<TabPanel Name="Users" Heading="Users" ResourceKey="Users">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<div class="col-sm-4">
|
||||
<ActionLink Action="Add" Text="Add User" ResourceKey="AddUser" />
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<input class="form-control" @bind="@_search" />
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<button type="button" class="btn btn-secondary" @onclick="OnSearch">@SharedLocalizer["Search"]</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Pager Items="@userroles">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@SharedLocalizer["Name"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td>
|
||||
<ActionLink Action="Edit" Parameters="@($"id=" + context.UserId.ToString())" ResourceKey="EditUser" />
|
||||
</td>
|
||||
<td>
|
||||
<ActionDialog Header="Delete User" Message="@string.Format(Localizer["Confirm.User.Delete"], context.User.DisplayName)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteUser(context))" Disabled="@(context.UserId == PageState.User.UserId)" ResourceKey="DeleteUser" />
|
||||
</td>
|
||||
<td>
|
||||
<ActionLink Action="Roles" Parameters="@($"id=" + context.UserId.ToString())" ResourceKey="Roles" />
|
||||
</td>
|
||||
<td>@context.User.DisplayName</td>
|
||||
</Row>
|
||||
</Pager>
|
||||
</TabPanel>
|
||||
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="allowregistration" HelpText="Do you want to allow visitors to be able to register for a user account on the site" ResourceKey="AllowRegistration">Allow User Registration? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="allowregistration" class="form-select" @bind="@_allowregistration" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button>
|
||||
</TabPanel>
|
||||
</TabStrip>
|
||||
}
|
||||
|
||||
@code {
|
||||
private List<UserRole> allroles;
|
||||
private List<UserRole> userroles;
|
||||
private string _search;
|
||||
private string _allowregistration;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
@ -61,6 +82,7 @@ else
|
||||
allroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId);
|
||||
await LoadSettingsAsync();
|
||||
userroles = Search(_search);
|
||||
_allowregistration = PageState.Site.AllowRegistration.ToString();
|
||||
}
|
||||
|
||||
private List<UserRole> Search(string search)
|
||||
@ -122,4 +144,20 @@ else
|
||||
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
|
||||
}
|
||||
|
||||
private async Task SaveSiteSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
var site = PageState.Site;
|
||||
site.AllowRegistration = bool.Parse(_allowregistration);
|
||||
await SiteService.UpdateSiteAsync(site);
|
||||
AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving Site Settings {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.SaveSiteSettings"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
123
Oqtane.Client/Modules/Admin/Visitors/Detail.razor
Normal file
123
Oqtane.Client/Modules/Admin/Visitors/Detail.razor
Normal file
@ -0,0 +1,123 @@
|
||||
@namespace Oqtane.Modules.Admin.Visitors
|
||||
@using System.Globalization
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IVisitorService VisitorService
|
||||
@inject IUserService UserService
|
||||
@inject IStringLocalizer<Detail> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="ip" HelpText="The last recorded IP address for this visitor" ResourceKey="IP">IP Address: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="ip" class="form-control" @bind="@_ip" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="language" HelpText="The last recorded language for this visitor" ResourceKey="Language">Language: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="language" class="form-control" @bind="@_language" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="useragent" HelpText="The last recorded user agent for this visitor" ResourceKey="UserAgent">User Agent: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="useragent" class="form-control" @bind="@_useragent" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="url" HelpText="The last recorded url for this visitor" ResourceKey="Url">Url: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="url" class="form-control" @bind="@_url" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="referrer" HelpText="The last recorded referrer for this visitor" ResourceKey="Referrer">Referrer: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="referrer" class="form-control" @bind="@_referrer" readonly />
|
||||
</div>
|
||||
</div>
|
||||
@if (_user != string.Empty)
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="user" HelpText="The last recorded user associated with this visitor" ResourceKey="User">User: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="user" class="form-control" @bind="@_user" readonly />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="visits" HelpText="The total number of visits by this visitor all time" ResourceKey="Visits">Visits: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="visits" class="form-control" @bind="@_visits" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="visited" HelpText="The last recorded date/time when the visitor visited the site" ResourceKey="Visited">Visited: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="visited" class="form-control" @bind="@_visited" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="created" HelpText="The first recorded date/time when this visitor visited the site" ResourceKey="Created">Created: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="created" class="form-control" @bind="@_created" readonly />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
|
||||
@code {
|
||||
private int _visitorId;
|
||||
private string _ip = string.Empty;
|
||||
private string _language = string.Empty;
|
||||
private string _useragent = string.Empty;
|
||||
private string _url = string.Empty;
|
||||
private string _referrer = string.Empty;
|
||||
private string _user = string.Empty;
|
||||
private string _visits = string.Empty;
|
||||
private string _visited = string.Empty;
|
||||
private string _created = string.Empty;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_visitorId = Int32.Parse(PageState.QueryString["id"]);
|
||||
var visitor = await VisitorService.GetVisitorAsync(_visitorId);
|
||||
if (visitor != null)
|
||||
{
|
||||
_ip = visitor.IPAddress;
|
||||
_language = visitor.Language;
|
||||
_useragent = visitor.UserAgent;
|
||||
_url = visitor.Url;
|
||||
_referrer = visitor.Referrer;
|
||||
_visits = visitor.Visits.ToString();
|
||||
_visited = visitor.VisitedOn.ToString(CultureInfo.CurrentCulture);
|
||||
_created = visitor.CreatedOn.ToString(CultureInfo.CurrentCulture);
|
||||
|
||||
if (visitor.UserId != null)
|
||||
{
|
||||
var user = await UserService.GetUserAsync(visitor.UserId.Value, PageState.Site.SiteId);
|
||||
if (user != null)
|
||||
{
|
||||
_user = user.DisplayName;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Error.LoadVisitor"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Visitor {VisitorId} {Error}", _visitorId, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.LoadVisitor"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
144
Oqtane.Client/Modules/Admin/Visitors/Index.razor
Normal file
144
Oqtane.Client/Modules/Admin/Visitors/Index.razor
Normal file
@ -0,0 +1,144 @@
|
||||
@namespace Oqtane.Modules.Admin.Visitors
|
||||
@inherits ModuleBase
|
||||
@inject IVisitorService VisitorService
|
||||
@inject ISiteService SiteService
|
||||
@inject IStringLocalizer<Index> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
@if (_visitors == null)
|
||||
{
|
||||
<p><em>@SharedLocalizer["Loading"]</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<TabStrip>
|
||||
<TabPanel Name="Visitors" Heading="Visitors" ResourceKey="Visitors">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<div class="col-sm-6">
|
||||
<select id="type" class="form-select custom-select" @onchange="(e => TypeChanged(e))">
|
||||
<option value="false">@Localizer["AllVisitors"]</option>
|
||||
<option value="true">@Localizer["UsersOnly"]</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<select id="type" class="form-select custom-select" @onchange="(e => DateChanged(e))">
|
||||
<option value="1">@Localizer["PastDay"]</option>
|
||||
<option value="7">@Localizer["PastWeek"]</option>
|
||||
<option value="30">@Localizer["PastMonth"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
<Pager Items="@_visitors">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@Localizer["IP"]</th>
|
||||
<th>@Localizer["User"]</th>
|
||||
<th>@Localizer["Language"]</th>
|
||||
<th>@Localizer["Visits"]</th>
|
||||
<th>@Localizer["Visited"]</th>
|
||||
<th>@Localizer["Created"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><ActionLink Action="Detail" Parameters="@($"id=" + context.VisitorId.ToString())" ResourceKey="Details" /></td>
|
||||
<td>@context.IPAddress</td>
|
||||
<td>
|
||||
@if (context.UserId != null)
|
||||
{
|
||||
@context.User.DisplayName
|
||||
}
|
||||
</td>
|
||||
<td>@context.Language</td>
|
||||
<td>@context.Visits</td>
|
||||
<td>@context.VisitedOn</td>
|
||||
<td>@context.CreatedOn</td>
|
||||
</Row>
|
||||
</Pager>
|
||||
</TabPanel>
|
||||
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="visitortracking" HelpText="Specify if visitor tracking is enabled" ResourceKey="VisitorTracking">Visitor Tracking Enabled? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="visitortracking" class="form-select" @bind="@_visitortracking" >
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button>
|
||||
</TabPanel>
|
||||
</TabStrip>
|
||||
}
|
||||
|
||||
@code {
|
||||
private bool _users = false;
|
||||
private int _days = 1;
|
||||
private List<Visitor> _visitors;
|
||||
private string _visitortracking;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
await GetVisitors();
|
||||
_visitortracking = PageState.Site.VisitorTracking.ToString();
|
||||
}
|
||||
|
||||
private async void TypeChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_users = bool.Parse(e.Value.ToString());
|
||||
await GetVisitors();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error On TypeChanged");
|
||||
}
|
||||
}
|
||||
|
||||
private async void DateChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_days = int.Parse(e.Value.ToString());
|
||||
await GetVisitors();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error On DateChanged");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task GetVisitors()
|
||||
{
|
||||
_visitors = await VisitorService.GetVisitorsAsync(PageState.Site.SiteId, DateTime.UtcNow.AddDays(-_days));
|
||||
if (_users)
|
||||
{
|
||||
_visitors = _visitors.Where(item => item.UserId != null).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SaveSiteSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
var site = PageState.Site;
|
||||
site.VisitorTracking = bool.Parse(_visitortracking);
|
||||
await SiteService.UpdateSiteAsync(site);
|
||||
AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving Site Settings {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.SaveSiteSettings"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@
|
||||
<div class="modal-footer">
|
||||
@if (!string.IsNullOrEmpty(Action))
|
||||
{
|
||||
<button type="button" class="@Class" @onclick="Confirm">@((MarkupString)_iconSpan) @Localize(Action)</button>
|
||||
<button type="button" class="@Class" @onclick="Confirm">@((MarkupString)_iconSpan) @Text</button>
|
||||
}
|
||||
<button type="button" class="btn btn-secondary" @onclick="DisplayModal">@Localize("Cancel")</button>
|
||||
</div>
|
||||
@ -30,16 +30,17 @@
|
||||
{
|
||||
if (Disabled)
|
||||
{
|
||||
<button class="@Class" disabled>@((MarkupString)_iconSpan) @Text</button>
|
||||
<button type="button" class="@Class" disabled>@((MarkupString)_iconSpan) @Text</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button class="@Class" @onclick="DisplayModal">@((MarkupString)_iconSpan) @Text</button>
|
||||
<button type="button" class="@Class" @onclick="DisplayModal">@((MarkupString)_iconSpan) @Text</button>
|
||||
}
|
||||
}
|
||||
|
||||
@code {
|
||||
private bool _visible = false;
|
||||
private string _permissions = string.Empty;
|
||||
private bool _editmode = false;
|
||||
private bool _authorized = false;
|
||||
private string _iconSpan = string.Empty;
|
||||
@ -59,6 +60,9 @@
|
||||
[Parameter]
|
||||
public SecurityAccessLevel? Security { get; set; } // optional - can be used to explicitly specify SecurityAccessLevel
|
||||
|
||||
[Parameter]
|
||||
public string Permissions { get; set; } // optional - can be used to specify a permission string
|
||||
|
||||
[Parameter]
|
||||
public string Class { get; set; } // optional
|
||||
|
||||
@ -105,6 +109,7 @@
|
||||
Header = Localize(nameof(Header), Header);
|
||||
Message = Localize(nameof(Message), Message);
|
||||
|
||||
_permissions = (string.IsNullOrEmpty(Permissions)) ? ModuleState.Permissions : Permissions;
|
||||
_authorized = IsAuthorized();
|
||||
}
|
||||
|
||||
@ -138,10 +143,10 @@
|
||||
authorized = true;
|
||||
break;
|
||||
case SecurityAccessLevel.View:
|
||||
authorized = UserSecurity.IsAuthorized(PageState.User,PermissionNames.View, ModuleState.Permissions);
|
||||
authorized = UserSecurity.IsAuthorized(PageState.User,PermissionNames.View, _permissions);
|
||||
break;
|
||||
case SecurityAccessLevel.Edit:
|
||||
authorized = UserSecurity.IsAuthorized(PageState.User,PermissionNames.Edit, ModuleState.Permissions);
|
||||
authorized = UserSecurity.IsAuthorized(PageState.User,PermissionNames.Edit, _permissions);
|
||||
break;
|
||||
case SecurityAccessLevel.Admin:
|
||||
authorized = UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin);
|
||||
|
@ -6,101 +6,118 @@
|
||||
{
|
||||
if (Disabled)
|
||||
{
|
||||
<button class="@_classname" style="@_style" disabled>@((MarkupString)_iconSpan) @_text</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<NavLink class="@_classname" href="@_url" style="@_style">@((MarkupString)_iconSpan) @_text</NavLink>
|
||||
}
|
||||
<button type="button" class="@_classname" style="@_style" disabled>@((MarkupString)_iconSpan) @_text</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
if (OnClick == null)
|
||||
{
|
||||
<NavLink class="@_classname" href="@_url" style="@_style">@((MarkupString)_iconSpan) @_text</NavLink>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button type="button" class="@_classname" style="@_style" onclick="@OnClick">@((MarkupString)_iconSpan) @_text</button>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@code {
|
||||
private string _text = string.Empty;
|
||||
private string _url = string.Empty;
|
||||
private string _parameters = string.Empty;
|
||||
private string _classname = "btn btn-primary";
|
||||
private string _style = string.Empty;
|
||||
private bool _editmode = false;
|
||||
private bool _authorized = false;
|
||||
private string _iconSpan = string.Empty;
|
||||
private string _text = string.Empty;
|
||||
private string _parameters = string.Empty;
|
||||
private string _url = string.Empty;
|
||||
private string _permissions = string.Empty;
|
||||
private bool _editmode = false;
|
||||
private bool _authorized = false;
|
||||
private string _classname = "btn btn-primary";
|
||||
private string _style = string.Empty;
|
||||
private string _iconSpan = string.Empty;
|
||||
|
||||
[Parameter]
|
||||
public string Action { get; set; } // required
|
||||
[Parameter]
|
||||
public string Action { get; set; } // required
|
||||
|
||||
[Parameter]
|
||||
public SecurityAccessLevel? Security { get; set; } // optional - can be used to explicitly specify SecurityAccessLevel
|
||||
[Parameter]
|
||||
public string Text { get; set; } // optional - defaults to Action if not specified
|
||||
|
||||
[Parameter]
|
||||
public string Text { get; set; } // optional - defaults to Action if not specified
|
||||
[Parameter]
|
||||
public string Parameters { get; set; } // optional - querystring parameters should be in the form of "id=x&name=y"
|
||||
|
||||
[Parameter]
|
||||
public string Parameters { get; set; } // optional - querystring parameter should be in the form of "id=x&name=y"
|
||||
[Parameter]
|
||||
public int ModuleId { get; set; } = -1; // optional - allows the link to target a specific moduleid
|
||||
|
||||
[Parameter]
|
||||
public string Class { get; set; } // optional - defaults to primary if not specified
|
||||
[Parameter]
|
||||
public Action OnClick { get; set; } = null; // optional - executes a method in the calling component
|
||||
|
||||
[Parameter]
|
||||
public string Style { get; set; } // optional
|
||||
[Parameter]
|
||||
public SecurityAccessLevel? Security { get; set; } // optional - can be used to explicitly specify SecurityAccessLevel
|
||||
|
||||
[Parameter]
|
||||
public bool Disabled { get; set; } // optional
|
||||
[Parameter]
|
||||
public string Permissions { get; set; } // optional - can be used to specify a permission string
|
||||
|
||||
[Parameter]
|
||||
public string EditMode { get; set; } // optional - specifies if an authorized user must be in edit mode to see the action - default is false.
|
||||
[Parameter]
|
||||
public bool Disabled { get; set; } // optional
|
||||
|
||||
[Parameter]
|
||||
public string IconName { get; set; } // optional - specifies an icon for the link - default is no icon
|
||||
[Parameter]
|
||||
public string EditMode { get; set; } // optional - specifies if an authorized user must be in edit mode to see the action - default is false.
|
||||
|
||||
[Parameter]
|
||||
public bool IconOnly { get; set; } // optional - specifies only icon in link
|
||||
[Parameter]
|
||||
public string Class { get; set; } // optional - defaults to primary if not specified
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
base.OnParametersSet();
|
||||
[Parameter]
|
||||
public string Style { get; set; } // optional
|
||||
|
||||
_text = Action;
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
_text = Text;
|
||||
}
|
||||
[Parameter]
|
||||
public string IconName { get; set; } // optional - specifies an icon for the link - default is no icon
|
||||
|
||||
if (IconOnly && !string.IsNullOrEmpty(IconName))
|
||||
{
|
||||
_text = string.Empty;
|
||||
}
|
||||
[Parameter]
|
||||
public bool IconOnly { get; set; } // optional - specifies only icon in link
|
||||
|
||||
if (!string.IsNullOrEmpty(Parameters))
|
||||
{
|
||||
_parameters = Parameters;
|
||||
}
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
base.OnParametersSet();
|
||||
|
||||
if (!string.IsNullOrEmpty(Class))
|
||||
{
|
||||
_classname = Class;
|
||||
}
|
||||
_text = Action;
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
_text = Text;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(Style))
|
||||
{
|
||||
_style = Style;
|
||||
}
|
||||
if (IconOnly && !string.IsNullOrEmpty(IconName))
|
||||
{
|
||||
_text = string.Empty;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(EditMode))
|
||||
{
|
||||
_editmode = bool.Parse(EditMode);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(Parameters))
|
||||
{
|
||||
_parameters = Parameters;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(IconName))
|
||||
{
|
||||
if (!IconName.Contains(" "))
|
||||
{
|
||||
IconName = "oi oi-" + IconName;
|
||||
}
|
||||
_iconSpan = $"<span class=\"{IconName}\"></span>{(IconOnly ? "" : " ")}";
|
||||
if (!string.IsNullOrEmpty(Class))
|
||||
{
|
||||
_classname = Class;
|
||||
}
|
||||
|
||||
}
|
||||
if (!string.IsNullOrEmpty(Style))
|
||||
{
|
||||
_style = Style;
|
||||
}
|
||||
|
||||
_text = Localize(nameof(Text), _text);
|
||||
_url = EditUrl(Action, _parameters);
|
||||
if (!string.IsNullOrEmpty(EditMode))
|
||||
{
|
||||
_editmode = bool.Parse(EditMode);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(IconName))
|
||||
{
|
||||
if (!IconName.Contains(" "))
|
||||
{
|
||||
IconName = "oi oi-" + IconName;
|
||||
}
|
||||
_iconSpan = $"<span class=\"{IconName}\"></span>{(IconOnly ? "" : " ")}";
|
||||
}
|
||||
|
||||
_permissions = (string.IsNullOrEmpty(Permissions)) ? ModuleState.Permissions : Permissions;
|
||||
_text = Localize(nameof(Text), _text);
|
||||
_url = (ModuleId == -1) ? EditUrl(Action, _parameters) : EditUrl(ModuleId, Action, _parameters);
|
||||
_authorized = IsAuthorized();
|
||||
}
|
||||
|
||||
@ -136,10 +153,10 @@
|
||||
authorized = true;
|
||||
break;
|
||||
case SecurityAccessLevel.View:
|
||||
authorized = UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, ModuleState.Permissions);
|
||||
authorized = UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, _permissions);
|
||||
break;
|
||||
case SecurityAccessLevel.Edit:
|
||||
authorized = UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, ModuleState.Permissions);
|
||||
authorized = UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, _permissions);
|
||||
break;
|
||||
case SecurityAccessLevel.Admin:
|
||||
authorized = UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin);
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
@if (ItemList != null)
|
||||
{
|
||||
@if (Toolbar == "Top" && _pages > 0 && Items.Count() > _maxItems)
|
||||
@if ((Toolbar == "Top" || Toolbar == "Both") && _pages > 0 && Items.Count() > _maxItems)
|
||||
{
|
||||
<ul class="pagination justify-content-center my-2">
|
||||
<li class="page-item@((_page > 1) ? "" : " disabled")">
|
||||
@ -101,7 +101,7 @@
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@if (Toolbar == "Bottom" && _pages > 0 && Items.Count() > _maxItems)
|
||||
@if ((Toolbar == "Bottom" || Toolbar == "Both") && _pages > 0 && Items.Count() > _maxItems)
|
||||
{
|
||||
<ul class="pagination justify-content-center my-2">
|
||||
<li class="page-item@((_page > 1) ? "" : " disabled")">
|
||||
@ -164,7 +164,7 @@
|
||||
public string Format { get; set; } // Table or Grid
|
||||
|
||||
[Parameter]
|
||||
public string Toolbar { get; set; } // Top or Bottom
|
||||
public string Toolbar { get; set; } // Top, Bottom or Both
|
||||
|
||||
[Parameter]
|
||||
public RenderFragment Header { get; set; } = null;
|
||||
|
@ -115,24 +115,24 @@
|
||||
|
||||
public override List<Resource> Resources => new List<Resource>()
|
||||
{
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill1.3.6.min.js" },
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill1.3.7.min.js" },
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-blot-formatter.min.js" },
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-interop.js" }
|
||||
};
|
||||
|
||||
protected override void OnInitialized()
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
_content = Content; // raw HTML
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
|
||||
if (firstRender)
|
||||
{
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
|
||||
await interop.CreateEditor(
|
||||
_editorElement,
|
||||
_toolBar,
|
||||
@ -140,14 +140,15 @@
|
||||
Placeholder,
|
||||
Theme,
|
||||
DebugLevel);
|
||||
|
||||
await interop.LoadEditorContent(_editorElement, Content);
|
||||
|
||||
_content = Content; // raw HTML
|
||||
|
||||
// preserve a copy of the rich text content ( Quill sanitizes content so we need to retrieve it from the editor )
|
||||
_original = await interop.GetHtml(_editorElement);
|
||||
}
|
||||
|
||||
await interop.LoadEditorContent(_editorElement, Content);
|
||||
|
||||
_content = Content; // raw HTML
|
||||
|
||||
// preserve a copy of the rich text content ( Quill sanitizes content so we need to retrieve it from the editor )
|
||||
_original = await interop.GetHtml(_editorElement);
|
||||
|
||||
}
|
||||
|
||||
public void CloseFileManager()
|
||||
|
@ -40,6 +40,10 @@ else
|
||||
{
|
||||
Heading = Localize(nameof(Name), Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
Heading = Localize(nameof(Heading), Heading);
|
||||
}
|
||||
}
|
||||
|
||||
public string DisplayHeading()
|
||||
|
@ -43,16 +43,12 @@
|
||||
[Parameter]
|
||||
public bool Refresh { get; set; } // optional - used in scenarios where TabPanels are added/removed dynamically within a parent form. ActiveTab may need to be reset as well when this property is used.
|
||||
|
||||
protected override void OnInitialized()
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
if (PageState.QueryString.ContainsKey("tab"))
|
||||
{
|
||||
ActiveTab = PageState.QueryString["tab"];
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
if (_tabPanels == null || Refresh)
|
||||
{
|
||||
_tabPanels = new List<TabPanel>();
|
||||
|
@ -30,8 +30,8 @@
|
||||
public override List<Resource> Resources => new List<Resource>()
|
||||
{
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" },
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill1.3.6.bubble.css" },
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill1.3.6.snow.css" }
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill1.3.7.bubble.css" },
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill1.3.7.snow.css" }
|
||||
};
|
||||
|
||||
private RichTextEditor RichTextEditorHtml;
|
||||
@ -65,8 +65,8 @@
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "An Error Occurred Loading Html/Text Content. " + ex.Message);
|
||||
AddModuleMessage(ex.Message, MessageType.Error);
|
||||
await logger.LogError(ex, "Error Loading Content {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Content.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,7 +91,7 @@
|
||||
await HtmlTextService.AddHtmlTextAsync(htmltext);
|
||||
}
|
||||
|
||||
await logger.LogInformation("Html/Text Content Saved {HtmlText}", htmltext);
|
||||
await logger.LogInformation("Content Saved {HtmlText}", htmltext);
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -15,16 +15,16 @@
|
||||
}
|
||||
|
||||
@code {
|
||||
public override List<Resource> Resources => new List<Resource>()
|
||||
public override List<Resource> Resources => new List<Resource>()
|
||||
{
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" }
|
||||
};
|
||||
|
||||
private string content = "";
|
||||
private string content = "";
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
try
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId);
|
||||
if (htmltext != null)
|
||||
@ -35,8 +35,8 @@
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "An Error Occurred Loading Html/Text Content. " + ex.Message);
|
||||
AddModuleMessage(ex.Message, MessageType.Error);
|
||||
await logger.LogError(ex, "Error Loading Content {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Content.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
using Oqtane.Documentation;
|
||||
using Oqtane.Models;
|
||||
|
||||
namespace Oqtane.Modules.HtmlText
|
||||
{
|
||||
[PrivateApi("Mark HtmlText classes as private, since it's not very useful in the public docs")]
|
||||
public class ModuleInfo : IModule
|
||||
{
|
||||
public ModuleDefinition ModuleDefinition => new ModuleDefinition
|
||||
|
@ -1,10 +1,12 @@
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Oqtane.Documentation;
|
||||
using Oqtane.Services;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Modules.HtmlText.Services
|
||||
{
|
||||
[PrivateApi("Mark HtmlText classes as private, since it's not very useful in the public docs")]
|
||||
public class HtmlTextService : ServiceBase, IHtmlTextService, IService
|
||||
{
|
||||
public HtmlTextService(HttpClient http, SiteState siteState) : base(http, siteState) {}
|
||||
|
@ -1,9 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Oqtane.Documentation;
|
||||
using Oqtane.Modules.HtmlText.Models;
|
||||
|
||||
namespace Oqtane.Modules.HtmlText.Services
|
||||
{
|
||||
[PrivateApi("Mark HtmlText classes as private, since it's not very useful in the public docs")]
|
||||
public interface IHtmlTextService
|
||||
{
|
||||
Task<Models.HtmlText> GetHtmlTextAsync(int ModuleId);
|
||||
|
@ -136,7 +136,12 @@ namespace Oqtane.Modules
|
||||
|
||||
public string ImageUrl(int fileid, int width, int height, string mode)
|
||||
{
|
||||
return Utilities.ImageUrl(PageState.Alias, fileid, width, height, mode);
|
||||
return ImageUrl(fileid, width, height, mode, 0);
|
||||
}
|
||||
|
||||
public string ImageUrl(int fileid, int width, int height, string mode, int rotate)
|
||||
{
|
||||
return Utilities.ImageUrl(PageState.Alias, fileid, width, height, mode, rotate);
|
||||
}
|
||||
|
||||
public virtual Dictionary<string, string> GetUrlParameters(string parametersTemplate = "")
|
||||
|
@ -5,7 +5,7 @@
|
||||
<OutputType>Exe</OutputType>
|
||||
<RazorLangVersion>3.0</RazorLangVersion>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<Version>3.0.0</Version>
|
||||
<Version>3.0.1</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -13,7 +13,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.0</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<RootNamespace>Oqtane</RootNamespace>
|
||||
@ -34,11 +34,6 @@
|
||||
<ProjectReference Include="..\Oqtane.Shared\Oqtane.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Resources\" />
|
||||
<Folder Include="Resources\Themes\Controls\Theme\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<TrimmerRootAssembly Include="System.Runtime" />
|
||||
<TrimmerRootAssembly Include="System.Linq.Parallel" />
|
||||
|
@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||
using Microsoft.AspNetCore.Localization;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.JSInterop;
|
||||
using Oqtane.Documentation;
|
||||
using Oqtane.Modules;
|
||||
using Oqtane.Services;
|
||||
using Oqtane.Shared;
|
||||
@ -19,6 +20,7 @@ using Oqtane.UI;
|
||||
|
||||
namespace Oqtane.Client
|
||||
{
|
||||
[PrivateApi("Mark Entry-Program as private, since it's not very useful in the public docs")]
|
||||
public class Program
|
||||
{
|
||||
public static async Task Main(string[] args)
|
||||
|
@ -159,4 +159,10 @@
|
||||
<data name="Type" xml:space="preserve">
|
||||
<value>Type</value>
|
||||
</data>
|
||||
<data name="DeleteFile.Text" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
<data name="UploadFiles.Text" xml:space="preserve">
|
||||
<value>Upload Files</value>
|
||||
</data>
|
||||
</root>
|
@ -168,4 +168,13 @@
|
||||
<data name="Stop" xml:space="preserve">
|
||||
<value>Stop</value>
|
||||
</data>
|
||||
<data name="DeleteJob.Text" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
<data name="EditJob.Text" xml:space="preserve">
|
||||
<value>Edit</value>
|
||||
</data>
|
||||
<data name="JobLog.Text" xml:space="preserve">
|
||||
<value>Log</value>
|
||||
</data>
|
||||
</root>
|
@ -153,4 +153,19 @@
|
||||
<data name="Search.NoResults" xml:space="preserve">
|
||||
<value>No Translations Match The Criteria Provided Or Package Service Is Disabled</value>
|
||||
</data>
|
||||
<data name="Download.Heading" xml:space="preserve">
|
||||
<value>Download</value>
|
||||
</data>
|
||||
<data name="LanguageUpload.HelpText" xml:space="preserve">
|
||||
<value>Upload one or more translations. Once they are uploaded click Install to complete the installation.</value>
|
||||
</data>
|
||||
<data name="LanguageUpload.Text" xml:space="preserve">
|
||||
<value>Upload Language</value>
|
||||
</data>
|
||||
<data name="Manage.Heading" xml:space="preserve">
|
||||
<value>Manage</value>
|
||||
</data>
|
||||
<data name="Upload.Heading" xml:space="preserve">
|
||||
<value>Upload</value>
|
||||
</data>
|
||||
</root>
|
@ -141,4 +141,7 @@
|
||||
<data name="Default" xml:space="preserve">
|
||||
<value>Default</value>
|
||||
</data>
|
||||
<data name="DeleteLanguage.Text" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
</root>
|
@ -189,4 +189,7 @@
|
||||
<data name="Create" xml:space="preserve">
|
||||
<value>Create</value>
|
||||
</data>
|
||||
<data name="LogDetails.Text" xml:space="preserve">
|
||||
<value>Details</value>
|
||||
</data>
|
||||
</root>
|
@ -138,4 +138,10 @@
|
||||
<data name="Search.NoResults" xml:space="preserve">
|
||||
<value>No Modules Match The Criteria Provided Or Package Service Is Disabled</value>
|
||||
</data>
|
||||
<data name="Download.Heading" xml:space="preserve">
|
||||
<value>Download</value>
|
||||
</data>
|
||||
<data name="Upload.Heading" xml:space="preserve">
|
||||
<value>Upload</value>
|
||||
</data>
|
||||
</root>
|
@ -183,7 +183,16 @@
|
||||
<data name="Runtimes.Text" xml:space="preserve">
|
||||
<value>Runtimes: </value>
|
||||
</data>
|
||||
<data name="Definition.Name" xml:space="preserve">
|
||||
<data name="Definition.Heading" xml:space="preserve">
|
||||
<value>Definition</value>
|
||||
</data>
|
||||
<data name="Information.Heading" xml:space="preserve">
|
||||
<value>Information</value>
|
||||
</data>
|
||||
<data name="Permissions.Heading" xml:space="preserve">
|
||||
<value>Permissions</value>
|
||||
</data>
|
||||
<data name="Information.Text" xml:space="preserve">
|
||||
<value>Information</value>
|
||||
</data>
|
||||
</root>
|
@ -144,4 +144,10 @@
|
||||
<data name="DeleteModule.Header" xml:space="preserve">
|
||||
<value>Delete Module</value>
|
||||
</data>
|
||||
<data name="InUse" xml:space="preserve">
|
||||
<value>In Use</value>
|
||||
</data>
|
||||
<data name="EditModule.Text" xml:space="preserve">
|
||||
<value>Edit</value>
|
||||
</data>
|
||||
</root>
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
@ -210,7 +210,7 @@
|
||||
<data name="Personalizable.Text" xml:space="preserve">
|
||||
<value>Personalizable? </value>
|
||||
</data>
|
||||
<data name="Appearance.Name" xml:space="preserve">
|
||||
<data name="Appearance.Heading" xml:space="preserve">
|
||||
<value>Appearance</value>
|
||||
</data>
|
||||
<data name="ThisLocation.Keep" xml:space="preserve">
|
||||
@ -231,4 +231,40 @@
|
||||
<data name="Move.Text" xml:space="preserve">
|
||||
<value>Move: </value>
|
||||
</data>
|
||||
<data name="ModuleDefinition" xml:space="preserve">
|
||||
<value>Module</value>
|
||||
</data>
|
||||
<data name="ModuleTitle" xml:space="preserve">
|
||||
<value>Title</value>
|
||||
</data>
|
||||
<data name="PageModules.Heading" xml:space="preserve">
|
||||
<value>Modules</value>
|
||||
</data>
|
||||
<data name="ModuleSettings.Text" xml:space="preserve">
|
||||
<value>Edit</value>
|
||||
</data>
|
||||
<data name="DeleteModule.Header" xml:space="preserve">
|
||||
<value>Delete Module</value>
|
||||
</data>
|
||||
<data name="DeleteModule.Message" xml:space="preserve">
|
||||
<value>Are You Sure You Wish To Delete This Module?</value>
|
||||
</data>
|
||||
<data name="DeleteModule.Text" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
<data name="Permissions.Heading" xml:space="preserve">
|
||||
<value>Permissions</value>
|
||||
</data>
|
||||
<data name="ThemeSettings.Heading" xml:space="preserve">
|
||||
<value>Theme Settings</value>
|
||||
</data>
|
||||
<data name="Appearance.Hea" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Clickable.HelpText" xml:space="preserve">
|
||||
<value>Select whether the link in the site navigation is enabled or disabled</value>
|
||||
</data>
|
||||
<data name="Clickable.Text" xml:space="preserve">
|
||||
<value>Clickable?</value>
|
||||
</data>
|
||||
</root>
|
@ -132,4 +132,10 @@
|
||||
<data name="Browse" xml:space="preserve">
|
||||
<value>Browse</value>
|
||||
</data>
|
||||
<data name="DeletePage.Text" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
<data name="EditPage.Text" xml:space="preserve">
|
||||
<value>Edit</value>
|
||||
</data>
|
||||
</root>
|
@ -132,4 +132,10 @@
|
||||
<data name="DeleteProfile.Header" xml:space="preserve">
|
||||
<value>Delete Profile</value>
|
||||
</data>
|
||||
<data name="DeleteProfile.Text" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
<data name="EditProfile.Text" xml:space="preserve">
|
||||
<value>Edit</value>
|
||||
</data>
|
||||
</root>
|
@ -177,7 +177,10 @@
|
||||
<data name="DeleteAllModules.Message" xml:space="preserve">
|
||||
<value>Are You Sure You Wish To Permanently Delete All Modules?</value>
|
||||
</data>
|
||||
<data name="Pages.Name" xml:space="preserve">
|
||||
<data name="Pages.Heading" xml:space="preserve">
|
||||
<value>Pages</value>
|
||||
</data>
|
||||
<data name="Modules.Heading" xml:space="preserve">
|
||||
<value>Modules</value>
|
||||
</data>
|
||||
</root>
|
@ -129,4 +129,13 @@
|
||||
<data name="DeleteRole.Header" xml:space="preserve">
|
||||
<value>Delete Role</value>
|
||||
</data>
|
||||
<data name="DeleteRole.Text" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
<data name="Edit.Text" xml:space="preserve">
|
||||
<value>Edit</value>
|
||||
</data>
|
||||
<data name="Users.Text" xml:space="preserve">
|
||||
<value>Users</value>
|
||||
</data>
|
||||
</root>
|
@ -129,7 +129,7 @@
|
||||
<data name="DefaultContainer.Text" xml:space="preserve">
|
||||
<value>Default Container: </value>
|
||||
</data>
|
||||
<data name="Appearance.Name" xml:space="preserve">
|
||||
<data name="Appearance.Heading" xml:space="preserve">
|
||||
<value>Appearance</value>
|
||||
</data>
|
||||
<data name="DefaultAdminContainer" xml:space="preserve">
|
||||
@ -171,9 +171,6 @@
|
||||
<data name="Aliases.HelpText" xml:space="preserve">
|
||||
<value>The aliases for the site. An alias can be a domain name (www.site.com) or a virtual folder (ie. www.site.com/folder). If a site has multiple aliases they should be separated by commas.</value>
|
||||
</data>
|
||||
<data name="AllowRegistration.HelpText" xml:space="preserve">
|
||||
<value>Do you want the users to be able to register for an account on the site</value>
|
||||
</data>
|
||||
<data name="IsDeleted.HelpText" xml:space="preserve">
|
||||
<value>Is this site deleted?</value>
|
||||
</data>
|
||||
@ -225,9 +222,6 @@
|
||||
<data name="Aliases.Text" xml:space="preserve">
|
||||
<value>Aliases: </value>
|
||||
</data>
|
||||
<data name="AllowRegistration.Text" xml:space="preserve">
|
||||
<value>Allow User Registration? </value>
|
||||
</data>
|
||||
<data name="IsDeleted.Text" xml:space="preserve">
|
||||
<value>Is Deleted? </value>
|
||||
</data>
|
||||
@ -282,7 +276,7 @@
|
||||
<data name="Theme.Select" xml:space="preserve">
|
||||
<value>Select Theme</value>
|
||||
</data>
|
||||
<data name="Hosting" xml:space="preserve">
|
||||
<data name="Hosting.Heading" xml:space="preserve">
|
||||
<value>Hosting Model</value>
|
||||
</data>
|
||||
<data name="Prerender.HelpText" xml:space="preserve">
|
||||
@ -300,4 +294,28 @@
|
||||
<data name="Browse" xml:space="preserve">
|
||||
<value>Browse</value>
|
||||
</data>
|
||||
<data name="TenantInformation.Heading" xml:space="preserve">
|
||||
<value>Tenant Information</value>
|
||||
</data>
|
||||
<data name="PWASettings.Heading" xml:space="preserve">
|
||||
<value>PWA Settings</value>
|
||||
</data>
|
||||
<data name="SMTPSettings.Heading" xml:space="preserve">
|
||||
<value>SMTP Settings</value>
|
||||
</data>
|
||||
<data name="ConnectionString.Text" xml:space="preserve">
|
||||
<value>Connection:</value>
|
||||
</data>
|
||||
<data name="Database.Text" xml:space="preserve">
|
||||
<value>Database:</value>
|
||||
</data>
|
||||
<data name="ConnectionString.HelpText" xml:space="preserve">
|
||||
<value>The connection information for the database</value>
|
||||
</data>
|
||||
<data name="Database.HelpText" xml:space="preserve">
|
||||
<value>The database for the tenant</value>
|
||||
</data>
|
||||
<data name="DeleteSite.Text" xml:space="preserve">
|
||||
<value>Delete Site</value>
|
||||
</data>
|
||||
</root>
|
@ -204,10 +204,10 @@
|
||||
<data name="Critical" xml:space="preserve">
|
||||
<value>Critical</value>
|
||||
</data>
|
||||
<data name="Info" xml:space="preserve">
|
||||
<data name="Info.Heading" xml:space="preserve">
|
||||
<value>Info</value>
|
||||
</data>
|
||||
<data name="Options" xml:space="preserve">
|
||||
<data name="Options.Heading" xml:space="preserve">
|
||||
<value>Options</value>
|
||||
</data>
|
||||
<data name="Register" xml:space="preserve">
|
||||
@ -228,4 +228,7 @@
|
||||
<data name="Swagger.Text" xml:space="preserve">
|
||||
<value>Swagger Enabled?</value>
|
||||
</data>
|
||||
<data name="RestartApplication.Text" xml:space="preserve">
|
||||
<value>Restart Application</value>
|
||||
</data>
|
||||
</root>
|
@ -138,4 +138,10 @@
|
||||
<data name="DeleteTheme.Header" xml:space="preserve">
|
||||
<value>Delete Theme</value>
|
||||
</data>
|
||||
<data name="CreateTheme.Text" xml:space="preserve">
|
||||
<value>Create Theme</value>
|
||||
</data>
|
||||
<data name="ViewTheme.Text" xml:space="preserve">
|
||||
<value>View</value>
|
||||
</data>
|
||||
</root>
|
@ -135,4 +135,10 @@
|
||||
<data name="Success.Framework.Download" xml:space="preserve">
|
||||
<value>Framework Downloaded Successfully... Please Select Upgrade To Complete the Process</value>
|
||||
</data>
|
||||
<data name="Download.Heading" xml:space="preserve">
|
||||
<value>Download</value>
|
||||
</data>
|
||||
<data name="Upload.Heading" xml:space="preserve">
|
||||
<value>Upload</value>
|
||||
</data>
|
||||
</root>
|
138
Oqtane.Client/Resources/Modules/Admin/UrlMappings/Add.resx
Normal file
138
Oqtane.Client/Resources/Modules/Admin/UrlMappings/Add.resx
Normal file
@ -0,0 +1,138 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="MappedUrl.Text" xml:space="preserve">
|
||||
<value>Redirect To:</value>
|
||||
</data>
|
||||
<data name="MappedUrl.HelpText" xml:space="preserve">
|
||||
<value>A fully qualified Url where the user will be redirected</value>
|
||||
</data>
|
||||
<data name="Url.HelpText" xml:space="preserve">
|
||||
<value>A fully qualified Url for this site</value>
|
||||
</data>
|
||||
<data name="Url.Text" xml:space="preserve">
|
||||
<value>Url:</value>
|
||||
</data>
|
||||
<data name="Error.SaveUrlMapping" xml:space="preserve">
|
||||
<value>Error Saving Url Mapping</value>
|
||||
</data>
|
||||
<data name="Message.InfoRequired" xml:space="preserve">
|
||||
<value>Please Provide All Required Information</value>
|
||||
</data>
|
||||
</root>
|
141
Oqtane.Client/Resources/Modules/Admin/UrlMappings/Edit.resx
Normal file
141
Oqtane.Client/Resources/Modules/Admin/UrlMappings/Edit.resx
Normal file
@ -0,0 +1,141 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="MappedUrl.Text" xml:space="preserve">
|
||||
<value>Redirect To:</value>
|
||||
</data>
|
||||
<data name="MappedUrl.HelpText" xml:space="preserve">
|
||||
<value>A fully qualified Url where the user will be redirected</value>
|
||||
</data>
|
||||
<data name="Url.HelpText" xml:space="preserve">
|
||||
<value>A fully qualified Url for this site</value>
|
||||
</data>
|
||||
<data name="Url.Text" xml:space="preserve">
|
||||
<value>Url:</value>
|
||||
</data>
|
||||
<data name="Error.LoadUrlMapping" xml:space="preserve">
|
||||
<value>Error Loading Url Mapping</value>
|
||||
</data>
|
||||
<data name="Error.SaveUrlMapping" xml:space="preserve">
|
||||
<value>Error Saving Url Mapping</value>
|
||||
</data>
|
||||
<data name="Message.InfoRequired" xml:space="preserve">
|
||||
<value>Please Provide All Required Information</value>
|
||||
</data>
|
||||
</root>
|
162
Oqtane.Client/Resources/Modules/Admin/UrlMappings/Index.resx
Normal file
162
Oqtane.Client/Resources/Modules/Admin/UrlMappings/Index.resx
Normal file
@ -0,0 +1,162 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Confirm.DeleteUrlMapping" xml:space="preserve">
|
||||
<value>Are You Sure You Wish To Delete {0}?</value>
|
||||
</data>
|
||||
<data name="AddUrlMapping.Text" xml:space="preserve">
|
||||
<value>Add Url Mapping</value>
|
||||
</data>
|
||||
<data name="DeleteUrlMapping.Header" xml:space="preserve">
|
||||
<value>Delete Url Mapping</value>
|
||||
</data>
|
||||
<data name="Requested" xml:space="preserve">
|
||||
<value>Requested</value>
|
||||
</data>
|
||||
<data name="Requests" xml:space="preserve">
|
||||
<value>Requests</value>
|
||||
</data>
|
||||
<data name="Mapped" xml:space="preserve">
|
||||
<value>Mapped Urls</value>
|
||||
</data>
|
||||
<data name="Broken" xml:space="preserve">
|
||||
<value>Broken Urls</value>
|
||||
</data>
|
||||
<data name="CaptureBrokenUrls.HelpText" xml:space="preserve">
|
||||
<value>Specify if broken Urls should be captured automatically and saved in Url Mappings</value>
|
||||
</data>
|
||||
<data name="CaptureBrokenUrls.Text" xml:space="preserve">
|
||||
<value>Capture Broken Urls?</value>
|
||||
</data>
|
||||
<data name="Error.SaveSiteSettings" xml:space="preserve">
|
||||
<value>Error Saving Settings</value>
|
||||
</data>
|
||||
<data name="Settings.Heading" xml:space="preserve">
|
||||
<value>Settings</value>
|
||||
</data>
|
||||
<data name="Success.SaveSiteSettings" xml:space="preserve">
|
||||
<value>Settings Saved Successfully</value>
|
||||
</data>
|
||||
<data name="Urls.Heading" xml:space="preserve">
|
||||
<value>Urls</value>
|
||||
</data>
|
||||
<data name="Url" xml:space="preserve">
|
||||
<value>Url</value>
|
||||
</data>
|
||||
</root>
|
@ -177,4 +177,10 @@
|
||||
<data name="Username.Text" xml:space="preserve">
|
||||
<value>Username:</value>
|
||||
</data>
|
||||
<data name="Identity.Heading" xml:space="preserve">
|
||||
<value>Identity</value>
|
||||
</data>
|
||||
<data name="Profile.Heading" xml:space="preserve">
|
||||
<value>Profile</value>
|
||||
</data>
|
||||
</root>
|
@ -126,4 +126,31 @@
|
||||
<data name="DeleteUser.Header" xml:space="preserve">
|
||||
<value>Delete User</value>
|
||||
</data>
|
||||
<data name="AllowRegistration.HelpText" xml:space="preserve">
|
||||
<value>Do you want the users to be able to register for an account on the site</value>
|
||||
</data>
|
||||
<data name="AllowRegistration.Text" xml:space="preserve">
|
||||
<value>Allow User Registration? </value>
|
||||
</data>
|
||||
<data name="Error.SaveSiteSettings" xml:space="preserve">
|
||||
<value>Error Saving Settings</value>
|
||||
</data>
|
||||
<data name="Settings.Heading" xml:space="preserve">
|
||||
<value>Settings</value>
|
||||
</data>
|
||||
<data name="Success.SaveSiteSettings" xml:space="preserve">
|
||||
<value>Settings Saved Successfully</value>
|
||||
</data>
|
||||
<data name="Users.Heading" xml:space="preserve">
|
||||
<value>Users</value>
|
||||
</data>
|
||||
<data name="DeleteUser.Text" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
<data name="EditUser.Text" xml:space="preserve">
|
||||
<value>Edit</value>
|
||||
</data>
|
||||
<data name="Roles.Text" xml:space="preserve">
|
||||
<value>Roles</value>
|
||||
</data>
|
||||
</root>
|
@ -177,4 +177,7 @@
|
||||
<data name="Expiry" xml:space="preserve">
|
||||
<value>Expiry</value>
|
||||
</data>
|
||||
<data name="DeleteUserRole.Text" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
</root>
|
177
Oqtane.Client/Resources/Modules/Admin/Visitors/Detail.resx
Normal file
177
Oqtane.Client/Resources/Modules/Admin/Visitors/Detail.resx
Normal file
@ -0,0 +1,177 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="IP.Text" xml:space="preserve">
|
||||
<value>IP Address:</value>
|
||||
</data>
|
||||
<data name="IP.HelpText" xml:space="preserve">
|
||||
<value>The last recorded IP address for this visitor</value>
|
||||
</data>
|
||||
<data name="Language.HelpText" xml:space="preserve">
|
||||
<value>The last recorded language for this visitor</value>
|
||||
</data>
|
||||
<data name="Language.Text" xml:space="preserve">
|
||||
<value>Language:</value>
|
||||
</data>
|
||||
<data name="Error.LoadVisitor" xml:space="preserve">
|
||||
<value>Error Loading Visitor</value>
|
||||
</data>
|
||||
<data name="Created.HelpText" xml:space="preserve">
|
||||
<value>The frst recorded date/time when the visitor visited the site</value>
|
||||
</data>
|
||||
<data name="Created.Text" xml:space="preserve">
|
||||
<value>Created:</value>
|
||||
</data>
|
||||
<data name="Referrer.HelpText" xml:space="preserve">
|
||||
<value>The last recorded referrer for this visitor</value>
|
||||
</data>
|
||||
<data name="Referrer.Text" xml:space="preserve">
|
||||
<value>Referrer:</value>
|
||||
</data>
|
||||
<data name="Url.HelpText" xml:space="preserve">
|
||||
<value>The last recorded Url for this visitor</value>
|
||||
</data>
|
||||
<data name="Url.Text" xml:space="preserve">
|
||||
<value>Url:</value>
|
||||
</data>
|
||||
<data name="User.HelpText" xml:space="preserve">
|
||||
<value>The last recorded user associated with this visitor</value>
|
||||
</data>
|
||||
<data name="User.Text" xml:space="preserve">
|
||||
<value>User:</value>
|
||||
</data>
|
||||
<data name="UserAgent.HelpText" xml:space="preserve">
|
||||
<value>The last recorded user agent for this visitor</value>
|
||||
</data>
|
||||
<data name="UserAgent.Text" xml:space="preserve">
|
||||
<value>User Agent:</value>
|
||||
</data>
|
||||
<data name="Visited.HelpText" xml:space="preserve">
|
||||
<value>The last recorded date/time when the visitor visited the site</value>
|
||||
</data>
|
||||
<data name="Visited.Text" xml:space="preserve">
|
||||
<value>Visited:</value>
|
||||
</data>
|
||||
<data name="Visits.HelpText" xml:space="preserve">
|
||||
<value>The total number of visits by this visitor all time</value>
|
||||
</data>
|
||||
<data name="Visits.Text" xml:space="preserve">
|
||||
<value>Visits:</value>
|
||||
</data>
|
||||
</root>
|
174
Oqtane.Client/Resources/Modules/Admin/Visitors/Index.resx
Normal file
174
Oqtane.Client/Resources/Modules/Admin/Visitors/Index.resx
Normal file
@ -0,0 +1,174 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Url" xml:space="preserve">
|
||||
<value>Url</value>
|
||||
</data>
|
||||
<data name="Visited" xml:space="preserve">
|
||||
<value>Visited</value>
|
||||
</data>
|
||||
<data name="Visits" xml:space="preserve">
|
||||
<value>Visits</value>
|
||||
</data>
|
||||
<data name="AllVisitors" xml:space="preserve">
|
||||
<value>All Visitors</value>
|
||||
</data>
|
||||
<data name="PastDay" xml:space="preserve">
|
||||
<value>Past Day</value>
|
||||
</data>
|
||||
<data name="PastMonth" xml:space="preserve">
|
||||
<value>Past Month</value>
|
||||
</data>
|
||||
<data name="PastWeek" xml:space="preserve">
|
||||
<value>Past Week</value>
|
||||
</data>
|
||||
<data name="UsersOnly" xml:space="preserve">
|
||||
<value>Users Only</value>
|
||||
</data>
|
||||
<data name="Language" xml:space="preserve">
|
||||
<value>Language</value>
|
||||
</data>
|
||||
<data name="Error.SaveSiteSettings" xml:space="preserve">
|
||||
<value>Error Saving Settings</value>
|
||||
</data>
|
||||
<data name="Settings.Heading" xml:space="preserve">
|
||||
<value>Settings</value>
|
||||
</data>
|
||||
<data name="Success.SaveSiteSettings" xml:space="preserve">
|
||||
<value>Settings Saved Successfully</value>
|
||||
</data>
|
||||
<data name="Visitors.Heading" xml:space="preserve">
|
||||
<value>Visitors</value>
|
||||
</data>
|
||||
<data name="VisitorTracking.HelpText" xml:space="preserve">
|
||||
<value>Specify if visitor tracking is enabled</value>
|
||||
</data>
|
||||
<data name="VisitorTracking.Text" xml:space="preserve">
|
||||
<value>Visitor Tracking Enabled?</value>
|
||||
</data>
|
||||
<data name="IP" xml:space="preserve">
|
||||
<value>IP</value>
|
||||
</data>
|
||||
<data name="User" xml:space="preserve">
|
||||
<value>User</value>
|
||||
</data>
|
||||
<data name="Created" xml:space="preserve">
|
||||
<value>Created</value>
|
||||
</data>
|
||||
</root>
|
@ -117,7 +117,10 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Error.Content.Load" xml:space="preserve">
|
||||
<value>An Error Occurred Loading Content</value>
|
||||
</data>
|
||||
<data name="Error.Content.Save" xml:space="preserve">
|
||||
<value>Error Saving Content</value>
|
||||
<value>An Error Occurred Saving Content</value>
|
||||
</data>
|
||||
</root>
|
@ -1,65 +1,65 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
@ -120,4 +120,7 @@
|
||||
<data name="Edit.Action" xml:space="preserve">
|
||||
<value>Edit</value>
|
||||
</data>
|
||||
<data name="Error.Content.Load" xml:space="preserve">
|
||||
<value>An Error Occurred Loading Content</value>
|
||||
</data>
|
||||
</root>
|
@ -318,4 +318,7 @@
|
||||
<data name="BlazorWebAssembly" xml:space="preserve">
|
||||
<value>Blazor WebAssembly</value>
|
||||
</data>
|
||||
<data name="Settings" xml:space="preserve">
|
||||
<value>Settings</value>
|
||||
</data>
|
||||
</root>
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
@ -123,4 +123,7 @@
|
||||
<data name="Error.Module.InvalidType" xml:space="preserve">
|
||||
<value>Module Type Is Invalid For {0}</value>
|
||||
</data>
|
||||
<data name="Error.Module.Exception" xml:space="preserve">
|
||||
<value>An Unexpected Error Has Occurred</value>
|
||||
</data>
|
||||
</root>
|
@ -1,4 +1,5 @@
|
||||
using Oqtane.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -70,7 +71,7 @@ namespace Oqtane.Services
|
||||
/// <summary>
|
||||
/// Returns a key-value dictionary of all module settings for the given module
|
||||
/// </summary>
|
||||
/// <param name="pageId"></param>
|
||||
/// <param name="moduleId"></param>
|
||||
/// <returns></returns>
|
||||
Task<Dictionary<string, string>> GetModuleSettingsAsync(int moduleId);
|
||||
|
||||
@ -82,6 +83,21 @@ namespace Oqtane.Services
|
||||
/// <returns></returns>
|
||||
Task UpdateModuleSettingsAsync(Dictionary<string, string> moduleSettings, int moduleId);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a key-value dictionary of all module settings for the given module
|
||||
/// </summary>
|
||||
/// <param name="moduleDefinitionId"></param>
|
||||
/// <returns></returns>
|
||||
Task<Dictionary<string, string>> GetModuleDefinitionSettingsAsync(int moduleDefinitionId);
|
||||
|
||||
/// <summary>
|
||||
/// Updates a module setting
|
||||
/// </summary>
|
||||
/// <param name="moduleDefinitionSettings"></param>
|
||||
/// <param name="moduleDefinitionId"></param>
|
||||
/// <returns></returns>
|
||||
Task UpdateModuleDefinitionSettingsAsync(Dictionary<string, string> moduleDefinitionSettings, int moduleDefinitionId);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a key-value dictionary of all user settings for the given user
|
||||
/// </summary>
|
||||
@ -113,6 +129,19 @@ namespace Oqtane.Services
|
||||
/// <returns></returns>
|
||||
Task UpdateFolderSettingsAsync(Dictionary<string, string> folderSettings, int folderId);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a key-value dictionary of all tenant settings
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<Dictionary<string, string>> GetHostSettingsAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Updates a host setting
|
||||
/// </summary>
|
||||
/// <param name="hostSettings"></param>
|
||||
/// <returns></returns>
|
||||
Task UpdateHostSettingsAsync(Dictionary<string, string> hostSettings);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a key-value dictionary of all settings for the given entityName
|
||||
/// </summary>
|
||||
@ -135,7 +164,7 @@ namespace Oqtane.Services
|
||||
/// </summary>
|
||||
/// <param name="settingId"></param>
|
||||
/// <returns></returns>
|
||||
Task<Setting> GetSettingAsync(int settingId);
|
||||
Task<Setting> GetSettingAsync(string entityName, int settingId);
|
||||
|
||||
|
||||
/// <summary>
|
||||
@ -157,7 +186,7 @@ namespace Oqtane.Services
|
||||
/// </summary>
|
||||
/// <param name="settingId"></param>
|
||||
/// <returns></returns>
|
||||
Task DeleteSettingAsync(int settingId);
|
||||
Task DeleteSettingAsync(string entityName, int settingId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the given settingName (key) from the given key-value dictionary
|
||||
@ -180,5 +209,13 @@ namespace Oqtane.Services
|
||||
Dictionary<string, string> SetSetting(Dictionary<string, string> settings, string settingName, string settingValue, bool isPublic);
|
||||
|
||||
Dictionary<string, string> MergeSettings(Dictionary<string, string> settings1, Dictionary<string, string> settings2);
|
||||
}
|
||||
|
||||
|
||||
[Obsolete("GetSettingAsync(int settingId) is deprecated. Use GetSettingAsync(string entityName, int settingId) instead.", false)]
|
||||
Task<Setting> GetSettingAsync(int settingId);
|
||||
|
||||
[Obsolete("DeleteSettingAsync(int settingId) is deprecated. Use DeleteSettingAsync(string entityName, int settingId) instead.", false)]
|
||||
Task DeleteSettingAsync(int settingId);
|
||||
|
||||
}
|
||||
}
|
||||
|
48
Oqtane.Client/Services/Interfaces/IUrlMappingService.cs
Normal file
48
Oqtane.Client/Services/Interfaces/IUrlMappingService.cs
Normal file
@ -0,0 +1,48 @@
|
||||
using Oqtane.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Oqtane.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Service to manage <see cref="UrlMapping"/>s on a <see cref="Site"/>
|
||||
/// </summary>
|
||||
public interface IUrlMappingService
|
||||
{
|
||||
/// <summary>
|
||||
/// Get all <see cref="UrlMapping"/>s of this <see cref="Site"/>.
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="siteId">ID-reference of a <see cref="Site"/></param>
|
||||
/// <returns></returns>
|
||||
Task<List<UrlMapping>> GetUrlMappingsAsync(int siteId, bool isMapped);
|
||||
|
||||
/// <summary>
|
||||
/// Get one specific <see cref="UrlMapping"/>
|
||||
/// </summary>
|
||||
/// <param name="urlMappingId">ID-reference of a <see cref="UrlMapping"/></param>
|
||||
/// <returns></returns>
|
||||
Task<UrlMapping> GetUrlMappingAsync(int urlMappingId);
|
||||
|
||||
/// <summary>
|
||||
/// Add / save a new <see cref="UrlMapping"/> to the database.
|
||||
/// </summary>
|
||||
/// <param name="urlMapping"></param>
|
||||
/// <returns></returns>
|
||||
Task<UrlMapping> AddUrlMappingAsync(UrlMapping urlMapping);
|
||||
|
||||
/// <summary>
|
||||
/// Update a <see cref="UrlMapping"/> in the database.
|
||||
/// </summary>
|
||||
/// <param name="urlMapping"></param>
|
||||
/// <returns></returns>
|
||||
Task<UrlMapping> UpdateUrlMappingAsync(UrlMapping urlMapping);
|
||||
|
||||
/// <summary>
|
||||
/// Delete a <see cref="UrlMapping"/> in the database.
|
||||
/// </summary>
|
||||
/// <param name="urlMappingId">ID-reference of a <see cref="UrlMapping"/></param>
|
||||
/// <returns></returns>
|
||||
Task DeleteUrlMappingAsync(int urlMappingId);
|
||||
}
|
||||
}
|
29
Oqtane.Client/Services/Interfaces/IVisitorService.cs
Normal file
29
Oqtane.Client/Services/Interfaces/IVisitorService.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using Oqtane.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Oqtane.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Service to manage <see cref="Visitor"/>s on a <see cref="Site"/>
|
||||
/// </summary>
|
||||
public interface IVisitorService
|
||||
{
|
||||
/// <summary>
|
||||
/// Get all <see cref="Visitor"/>s of this <see cref="Site"/>.
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="siteId">ID-reference of a <see cref="Site"/></param>
|
||||
/// <returns></returns>
|
||||
Task<List<Visitor>> GetVisitorsAsync(int siteId, DateTime fromDate);
|
||||
|
||||
/// <summary>
|
||||
/// Get a specific <see cref="Visitor"/> of this <see cref="Site"/>.
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="visitorId">ID-reference of a <see cref="Visitor"/></param>
|
||||
/// <returns></returns>
|
||||
Task<Visitor> GetVisitorAsync(int visitorId);
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ namespace Oqtane.Services
|
||||
}
|
||||
|
||||
private string Apiurl => CreateApiUrl("Setting", _siteState.Alias);
|
||||
|
||||
public async Task<Dictionary<string, string>> GetTenantSettingsAsync()
|
||||
{
|
||||
return await GetSettingsAsync(EntityNames.Tenant, -1);
|
||||
@ -71,6 +72,16 @@ namespace Oqtane.Services
|
||||
await UpdateSettingsAsync(moduleSettings, EntityNames.Module, moduleId);
|
||||
}
|
||||
|
||||
public async Task<Dictionary<string, string>> GetModuleDefinitionSettingsAsync(int moduleDefinitionId)
|
||||
{
|
||||
return await GetSettingsAsync(EntityNames.ModuleDefinition, moduleDefinitionId);
|
||||
}
|
||||
|
||||
public async Task UpdateModuleDefinitionSettingsAsync(Dictionary<string, string> moduleDefinitionSettings, int moduleDefinitionId)
|
||||
{
|
||||
await UpdateSettingsAsync(moduleDefinitionSettings, EntityNames.ModuleDefinition, moduleDefinitionId);
|
||||
}
|
||||
|
||||
public async Task<Dictionary<string, string>> GetUserSettingsAsync(int userId)
|
||||
{
|
||||
return await GetSettingsAsync(EntityNames.User, userId);
|
||||
@ -91,6 +102,16 @@ namespace Oqtane.Services
|
||||
await UpdateSettingsAsync(folderSettings, EntityNames.Folder, folderId);
|
||||
}
|
||||
|
||||
public async Task<Dictionary<string, string>> GetHostSettingsAsync()
|
||||
{
|
||||
return await GetSettingsAsync(EntityNames.Host, -1);
|
||||
}
|
||||
|
||||
public async Task UpdateHostSettingsAsync(Dictionary<string, string> hostSettings)
|
||||
{
|
||||
await UpdateSettingsAsync(hostSettings, EntityNames.Host, -1);
|
||||
}
|
||||
|
||||
public async Task<Dictionary<string, string>> GetSettingsAsync(string entityName, int entityId)
|
||||
{
|
||||
var dictionary = new Dictionary<string, string>();
|
||||
@ -144,9 +165,9 @@ namespace Oqtane.Services
|
||||
}
|
||||
|
||||
|
||||
public async Task<Setting> GetSettingAsync(int settingId)
|
||||
public async Task<Setting> GetSettingAsync(string entityName, int settingId)
|
||||
{
|
||||
return await GetJsonAsync<Setting>($"{Apiurl}/{settingId}");
|
||||
return await GetJsonAsync<Setting>($"{Apiurl}/{settingId}/{entityName}");
|
||||
}
|
||||
|
||||
public async Task<Setting> AddSettingAsync(Setting setting)
|
||||
@ -159,9 +180,9 @@ namespace Oqtane.Services
|
||||
return await PutJsonAsync<Setting>($"{Apiurl}/{setting.SettingId}", setting);
|
||||
}
|
||||
|
||||
public async Task DeleteSettingAsync(int settingId)
|
||||
public async Task DeleteSettingAsync(string entityName, int settingId)
|
||||
{
|
||||
await DeleteAsync($"{Apiurl}/{settingId}");
|
||||
await DeleteAsync($"{Apiurl}/{settingId}/{entityName}");
|
||||
}
|
||||
|
||||
|
||||
@ -220,5 +241,19 @@ namespace Oqtane.Services
|
||||
}
|
||||
return settings1;
|
||||
}
|
||||
|
||||
[Obsolete("GetSettingAsync(int settingId) is deprecated. Use GetSettingAsync(string entityName, int settingId) instead.", false)]
|
||||
public async Task<Setting> GetSettingAsync(int settingId)
|
||||
{
|
||||
return await GetJsonAsync<Setting>($"{Apiurl}/{settingId}/tenant");
|
||||
}
|
||||
|
||||
[Obsolete("DeleteSettingAsync(int settingId) is deprecated. Use DeleteSettingAsync(string entityName, int settingId) instead.", false)]
|
||||
public async Task DeleteSettingAsync(int settingId)
|
||||
{
|
||||
await DeleteAsync($"{Apiurl}/{settingId}/tenant");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
51
Oqtane.Client/Services/UrlMappingService.cs
Normal file
51
Oqtane.Client/Services/UrlMappingService.cs
Normal file
@ -0,0 +1,51 @@
|
||||
using Oqtane.Models;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net.Http;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using Oqtane.Documentation;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Services
|
||||
{
|
||||
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
||||
public class UrlMappingService : ServiceBase, IUrlMappingService
|
||||
{
|
||||
|
||||
private readonly SiteState _siteState;
|
||||
|
||||
public UrlMappingService(HttpClient http, SiteState siteState) : base(http)
|
||||
{
|
||||
|
||||
_siteState = siteState;
|
||||
}
|
||||
|
||||
private string Apiurl => CreateApiUrl("UrlMapping", _siteState.Alias);
|
||||
|
||||
public async Task<List<UrlMapping>> GetUrlMappingsAsync(int siteId, bool isMapped)
|
||||
{
|
||||
List<UrlMapping> urlMappings = await GetJsonAsync<List<UrlMapping>>($"{Apiurl}?siteid={siteId}&ismapped={isMapped}");
|
||||
return urlMappings.OrderByDescending(item => item.RequestedOn).ToList();
|
||||
}
|
||||
|
||||
public async Task<UrlMapping> GetUrlMappingAsync(int urlMappingId)
|
||||
{
|
||||
return await GetJsonAsync<UrlMapping>($"{Apiurl}/{urlMappingId}");
|
||||
}
|
||||
|
||||
public async Task<UrlMapping> AddUrlMappingAsync(UrlMapping role)
|
||||
{
|
||||
return await PostJsonAsync<UrlMapping>(Apiurl, role);
|
||||
}
|
||||
|
||||
public async Task<UrlMapping> UpdateUrlMappingAsync(UrlMapping role)
|
||||
{
|
||||
return await PutJsonAsync<UrlMapping>($"{Apiurl}/{role.UrlMappingId}", role);
|
||||
}
|
||||
|
||||
public async Task DeleteUrlMappingAsync(int urlMappingId)
|
||||
{
|
||||
await DeleteAsync($"{Apiurl}/{urlMappingId}");
|
||||
}
|
||||
}
|
||||
}
|
37
Oqtane.Client/Services/VisitorService.cs
Normal file
37
Oqtane.Client/Services/VisitorService.cs
Normal file
@ -0,0 +1,37 @@
|
||||
using Oqtane.Models;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net.Http;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using Oqtane.Documentation;
|
||||
using Oqtane.Shared;
|
||||
using System;
|
||||
|
||||
namespace Oqtane.Services
|
||||
{
|
||||
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
||||
public class VisitorService : ServiceBase, IVisitorService
|
||||
{
|
||||
|
||||
private readonly SiteState _siteState;
|
||||
|
||||
public VisitorService(HttpClient http, SiteState siteState) : base(http)
|
||||
{
|
||||
|
||||
_siteState = siteState;
|
||||
}
|
||||
|
||||
private string Apiurl => CreateApiUrl("Visitor", _siteState.Alias);
|
||||
|
||||
public async Task<List<Visitor>> GetVisitorsAsync(int siteId, DateTime fromDate)
|
||||
{
|
||||
List<Visitor> visitors = await GetJsonAsync<List<Visitor>>($"{Apiurl}?siteid={siteId}&fromdate={fromDate.ToString("dd-MMM-yyyy")}");
|
||||
return visitors.OrderByDescending(item => item.VisitedOn).ToList();
|
||||
}
|
||||
|
||||
public async Task<Visitor> GetVisitorAsync(int visitorId)
|
||||
{
|
||||
return await GetJsonAsync<Visitor>($"{Apiurl}/{visitorId}");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Documentation;
|
||||
using Oqtane.Models;
|
||||
|
||||
namespace Oqtane.Themes.BlazorTheme
|
||||
{
|
||||
[PrivateApi("Mark Build-In Theme-Info classes as private, since it's not very useful in the public docs")]
|
||||
public class ThemeInfo : ITheme
|
||||
{
|
||||
public Theme Theme => new Theme
|
||||
|
@ -16,7 +16,15 @@
|
||||
else
|
||||
{
|
||||
<li class="breadcrumb-item">
|
||||
<a href="@NavigateUrl(p.Path)">@p.Name</a>
|
||||
@if(p.IsClickable)
|
||||
{
|
||||
<a href="@NavigateUrl(p.Path)">@p.Name</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
@p.Name
|
||||
}
|
||||
|
||||
</li>
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@
|
||||
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions))
|
||||
{
|
||||
<button class="btn @ButtonClass" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasControlPanel" aria-controls="offcanvasControlPanel">
|
||||
<button type="button" class="btn @ButtonClass" data-bs-toggle="offcanvas" data-bs-target="#offcanvasControlPanel" aria-controls="offcanvasControlPanel">
|
||||
<span class="oi oi-cog"></span>
|
||||
</button>
|
||||
|
||||
@ -50,7 +50,7 @@
|
||||
{
|
||||
<div class="row d-flex">
|
||||
<div class="col">
|
||||
<button data-bs-dismiss="offcanvas" type="button" class="btn btn-primary col-12" @onclick=@(async () => Navigate("Admin"))>@Localizer["AdminDash"]</button>
|
||||
<button type="button" data-bs-dismiss="offcanvas" class="btn btn-primary col-12" @onclick=@(async () => Navigate("Admin"))>@Localizer["AdminDash"]</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -63,9 +63,9 @@
|
||||
</div>
|
||||
<div class="row d-flex">
|
||||
<div class="col d-flex justify-content-between">
|
||||
<button type="button" class="btn btn-secondary col-3" data-bs-dismiss="offcanvas" @onclick=@(async () => Navigate("Add"))>@SharedLocalizer["Add"]</button>
|
||||
<button type="button" class="btn btn-secondary col-3" data-bs-dismiss="offcanvas" @onclick=@(async () => Navigate("Edit"))>@SharedLocalizer["Edit"]</button>
|
||||
<button type="button" class="btn btn-danger col-3" @onclick="ConfirmDelete">@SharedLocalizer["Delete"]</button>
|
||||
<button type="button" class="btn btn-secondary col me-1" data-bs-dismiss="offcanvas" @onclick=@(async () => Navigate("Add"))>@SharedLocalizer["Add"]</button>
|
||||
<button type="button" class="btn btn-secondary col" data-bs-dismiss="offcanvas" @onclick=@(async () => Navigate("Edit"))>@SharedLocalizer["Edit"]</button>
|
||||
<button type="button" class="btn btn-danger col ms-1" @onclick="ConfirmDelete">@SharedLocalizer["Delete"]</button>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
|
@ -5,7 +5,7 @@
|
||||
@if (MenuPages.Any())
|
||||
{
|
||||
<span class="app-menu-toggler navbar-expand-md">
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#Menu" aria-controls="Menu" aria-expanded="false" aria-label="Toggle Navigation">
|
||||
<button type="button" class="navbar-toggler" data-bs-toggle="collapse" data-bs-target="#Menu" aria-controls="Menu" aria-expanded="false" aria-label="Toggle Navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
</span>
|
||||
|
@ -4,7 +4,7 @@
|
||||
@if (MenuPages.Any())
|
||||
{
|
||||
<span class="app-menu-toggler">
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#Menu" aria-controls="Menu" aria-expanded="false" aria-label="Toggle Navigation">
|
||||
<button type="button" class="navbar-toggler" data-bs-toggle="collapse" data-bs-target="#Menu" aria-controls="Menu" aria-expanded="false" aria-label="Toggle Navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
</span>
|
||||
|
@ -1,7 +1,9 @@
|
||||
using Oqtane.Documentation;
|
||||
using Oqtane.Models;
|
||||
|
||||
namespace Oqtane.Themes.OqtaneTheme
|
||||
{
|
||||
[PrivateApi("Mark Build-In Theme-Info classes as private, since it's not very useful in the public docs")]
|
||||
public class ThemeInfo : ITheme
|
||||
{
|
||||
public Theme Theme => new Theme
|
||||
|
@ -106,7 +106,12 @@ namespace Oqtane.Themes
|
||||
|
||||
public string ImageUrl(int fileid, int width, int height, string mode)
|
||||
{
|
||||
return Utilities.ImageUrl(PageState.Alias, fileid, width, height, mode);
|
||||
return ImageUrl(fileid, width, height, mode, 0);
|
||||
}
|
||||
|
||||
public string ImageUrl(int fileid, int width, int height, string mode, int rotate)
|
||||
{
|
||||
return Utilities.ImageUrl(PageState.Alias, fileid, width, height, mode, rotate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,78 +1,104 @@
|
||||
@namespace Oqtane.UI
|
||||
@inject IStringLocalizer<ModuleInstance> Localizer
|
||||
@inject ILogService LoggingService
|
||||
@inherits ErrorBoundary
|
||||
|
||||
<ModuleMessage Message="@_message" Type="@_messagetype" />
|
||||
@DynamicComponent
|
||||
@if (_progressindicator)
|
||||
@if (CurrentException is null)
|
||||
{
|
||||
<div class="app-progress-indicator"></div>
|
||||
<ModuleMessage Message="@_message" Type="@_messageType"/>
|
||||
@if (ModuleType != null)
|
||||
{
|
||||
<DynamicComponent Type="@ModuleType" Parameters="@ModuleParameters"></DynamicComponent>
|
||||
@if (_progressIndicator)
|
||||
{
|
||||
<div class="app-progress-indicator"></div>
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@if (!string.IsNullOrEmpty(_error))
|
||||
{
|
||||
<ModuleMessage Message="@_error" Type="@MessageType.Error"/>
|
||||
}
|
||||
}
|
||||
|
||||
@code {
|
||||
private string _message;
|
||||
private MessageType _messagetype;
|
||||
private bool _progressindicator = false;
|
||||
private string _message;
|
||||
private string _error;
|
||||
private MessageType _messageType;
|
||||
private bool _progressIndicator = false;
|
||||
|
||||
[CascadingParameter]
|
||||
protected PageState PageState { get; set; }
|
||||
private Type ModuleType { get; set; }
|
||||
private IDictionary<string, object> ModuleParameters { get; set; }
|
||||
|
||||
[CascadingParameter]
|
||||
private Module ModuleState { get; set; }
|
||||
[CascadingParameter]
|
||||
protected PageState PageState { get; set; }
|
||||
|
||||
private ModuleMessage ModuleMessage { get; set; }
|
||||
[CascadingParameter]
|
||||
private Module ModuleState { get; set; }
|
||||
|
||||
private RenderFragment DynamicComponent { get; set; }
|
||||
private ModuleMessage ModuleMessage { get; set; }
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
_message = "";
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
_message = "";
|
||||
if (!string.IsNullOrEmpty(ModuleState.ModuleType))
|
||||
{
|
||||
ModuleType = Type.GetType(ModuleState.ModuleType);
|
||||
if (ModuleType != null)
|
||||
{
|
||||
ModuleParameters = new Dictionary<string, object> { { "ModuleInstance", this } };
|
||||
return;
|
||||
}
|
||||
// module does not exist with typename specified
|
||||
_message = string.Format(Localizer["Error.Module.InvalidName"], Utilities.GetTypeNameLastSegment(ModuleState.ModuleType, 0));
|
||||
_messageType = MessageType.Error;
|
||||
}
|
||||
else
|
||||
{
|
||||
_message = string.Format(Localizer["Error.Module.InvalidType"], ModuleState.ModuleDefinitionName);
|
||||
_messageType = MessageType.Error;
|
||||
}
|
||||
}
|
||||
|
||||
DynamicComponent = builder =>
|
||||
{
|
||||
Type moduleType = null;
|
||||
if (!string.IsNullOrEmpty(ModuleState.ModuleType))
|
||||
{
|
||||
moduleType = Type.GetType(ModuleState.ModuleType);
|
||||
public void AddModuleMessage(string message, MessageType type)
|
||||
{
|
||||
_message = message;
|
||||
_messageType = type;
|
||||
_progressIndicator = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
if (moduleType != null)
|
||||
{
|
||||
builder.OpenComponent(0, moduleType);
|
||||
builder.AddAttribute(1, "ModuleInstance", this);
|
||||
builder.CloseComponent();
|
||||
}
|
||||
else
|
||||
{
|
||||
// module does not exist with typename specified
|
||||
_message = string.Format(Localizer["Error.Module.InvalidName"], Utilities.GetTypeNameLastSegment(ModuleState.ModuleType, 0));
|
||||
_messagetype = MessageType.Error;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_message = string.Format(Localizer["Error.Module.InvalidType"], ModuleState.ModuleDefinitionName);
|
||||
_messagetype = MessageType.Error;
|
||||
}
|
||||
public void ShowProgressIndicator()
|
||||
{
|
||||
_progressIndicator = true;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
};
|
||||
public void HideProgressIndicator()
|
||||
{
|
||||
_progressIndicator = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
protected override async Task OnErrorAsync(Exception exception)
|
||||
{
|
||||
// retrieve friendly localized error
|
||||
_error = Localizer["Error.Module.Exception"];
|
||||
// log error
|
||||
int? userId = (PageState.User != null) ? PageState.User.UserId : null;
|
||||
string category = GetType().AssemblyQualifiedName;
|
||||
string feature = Utilities.GetTypeNameLastSegment(category, 1);
|
||||
await LoggingService.Log(null, ModuleState.PageId, ModuleState.ModuleId, userId, category, feature, LogFunction.Other, LogLevel.Error, exception, "An Unexpected Error Has Occurred In {ModuleDefinitionName}: {Error}", ModuleState.ModuleDefinitionName, exception.Message);
|
||||
await base.OnErrorAsync(exception);
|
||||
return;
|
||||
}
|
||||
|
||||
public new void Recover()
|
||||
{
|
||||
_error = "";
|
||||
base.Recover();
|
||||
}
|
||||
|
||||
public void AddModuleMessage(string message, MessageType type)
|
||||
{
|
||||
_message = message;
|
||||
_messagetype = type;
|
||||
_progressindicator = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
public void ShowProgressIndicator()
|
||||
{
|
||||
_progressindicator = true;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
public void HideProgressIndicator()
|
||||
{
|
||||
_progressindicator = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
@ -20,5 +20,6 @@ namespace Oqtane.UI
|
||||
public bool EditMode { get; set; }
|
||||
public DateTime LastSyncDate { get; set; }
|
||||
public Oqtane.Shared.Runtime Runtime { get; set; }
|
||||
public int VisitorId { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -15,78 +15,75 @@
|
||||
@DynamicComponent
|
||||
|
||||
@code {
|
||||
private string _absoluteUri;
|
||||
private bool _navigationInterceptionEnabled;
|
||||
private PageState _pagestate;
|
||||
private string _absoluteUri;
|
||||
private bool _navigationInterceptionEnabled;
|
||||
private PageState _pagestate;
|
||||
|
||||
[Parameter]
|
||||
public string Runtime { get; set; }
|
||||
[Parameter]
|
||||
public string Runtime { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string RenderMode { get; set; }
|
||||
[Parameter]
|
||||
public string RenderMode { get; set; }
|
||||
|
||||
[CascadingParameter]
|
||||
PageState PageState { get; set; }
|
||||
[Parameter]
|
||||
public int VisitorId { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public Action<PageState> OnStateChange { get; set; }
|
||||
[CascadingParameter]
|
||||
PageState PageState { get; set; }
|
||||
|
||||
private RenderFragment DynamicComponent { get; set; }
|
||||
[Parameter]
|
||||
public Action<PageState> OnStateChange { get; set; }
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_absoluteUri = NavigationManager.Uri;
|
||||
NavigationManager.LocationChanged += LocationChanged;
|
||||
private RenderFragment DynamicComponent { get; set; }
|
||||
|
||||
DynamicComponent = builder =>
|
||||
{
|
||||
if (PageState != null)
|
||||
{
|
||||
builder.OpenComponent(0, Type.GetType(Constants.PageComponent));
|
||||
builder.CloseComponent();
|
||||
}
|
||||
};
|
||||
}
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_absoluteUri = NavigationManager.Uri;
|
||||
NavigationManager.LocationChanged += LocationChanged;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
NavigationManager.LocationChanged -= LocationChanged;
|
||||
}
|
||||
DynamicComponent = builder =>
|
||||
{
|
||||
if (PageState != null)
|
||||
{
|
||||
builder.OpenComponent(0, Type.GetType(Constants.PageComponent));
|
||||
builder.CloseComponent();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
if (PageState == null)
|
||||
{
|
||||
await Refresh();
|
||||
}
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
NavigationManager.LocationChanged -= LocationChanged;
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "StringIndexOfIsCultureSpecific.1")]
|
||||
private async Task Refresh()
|
||||
{
|
||||
Site site;
|
||||
List<Page> pages;
|
||||
Page page;
|
||||
User user = null;
|
||||
List<Module> modules;
|
||||
var moduleid = -1;
|
||||
var action = Constants.DefaultAction;
|
||||
var urlparameters = string.Empty;
|
||||
var editmode = false;
|
||||
var refresh = UI.Refresh.None;
|
||||
var lastsyncdate = DateTime.UtcNow.AddHours(-1);
|
||||
var runtime = (Shared.Runtime)Enum.Parse(typeof(Shared.Runtime), Runtime);
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
if (PageState == null)
|
||||
{
|
||||
await Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
Uri uri = new Uri(_absoluteUri);
|
||||
[SuppressMessage("ReSharper", "StringIndexOfIsCultureSpecific.1")]
|
||||
private async Task Refresh()
|
||||
{
|
||||
Site site;
|
||||
List<Page> pages;
|
||||
Page page;
|
||||
User user = null;
|
||||
List<Module> modules;
|
||||
var editmode = false;
|
||||
var refresh = UI.Refresh.None;
|
||||
var lastsyncdate = DateTime.UtcNow.AddHours(-1);
|
||||
var runtime = (Shared.Runtime)Enum.Parse(typeof(Shared.Runtime), Runtime);
|
||||
|
||||
// get path
|
||||
var path = uri.LocalPath.Substring(1);
|
||||
|
||||
// parse querystring
|
||||
var querystring = ParseQueryString(uri.Query);
|
||||
Route route = new Route(_absoluteUri, SiteState.Alias.Path);
|
||||
var moduleid = (int.TryParse(route.ModuleId, out int mid)) ? mid : -1;
|
||||
var action = (!string.IsNullOrEmpty(route.Action)) ? route.Action : Constants.DefaultAction;
|
||||
var querystring = ParseQueryString(route.Query);
|
||||
|
||||
// reload the client application if there is a forced reload or the user navigated to a site with a different alias
|
||||
if (querystring.ContainsKey("reload") || (!path.ToLower().StartsWith(SiteState.Alias.Path.ToLower()) && !string.IsNullOrEmpty(SiteState.Alias.Path)))
|
||||
if (querystring.ContainsKey("reload") || (!route.AbsolutePath.Substring(1).ToLower().StartsWith(SiteState.Alias.Path.ToLower()) && !string.IsNullOrEmpty(SiteState.Alias.Path)))
|
||||
{
|
||||
NavigationManager.NavigateTo(_absoluteUri.Replace("?reload", ""), true);
|
||||
return;
|
||||
@ -168,72 +165,9 @@
|
||||
pages = PageState.Pages;
|
||||
}
|
||||
|
||||
// format path and remove alias
|
||||
path = path.Replace("//", "/"); // in case of doubleslash at end
|
||||
path += (!path.EndsWith("/")) ? "/" : "";
|
||||
if (SiteState.Alias.Path != "" && path.StartsWith(SiteState.Alias.Path))
|
||||
{
|
||||
path = path.Substring(SiteState.Alias.Path.Length + 1);
|
||||
}
|
||||
|
||||
// extract admin route elements from path
|
||||
var segments = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
int result;
|
||||
|
||||
int modIdPos = 0;
|
||||
int actionPos = 0;
|
||||
int urlParametersPos = 0;
|
||||
|
||||
for (int i = 0; i < segments.Length; i++)
|
||||
{
|
||||
|
||||
if (segments[i] == Constants.UrlParametersDelimiter)
|
||||
{
|
||||
urlParametersPos = i + 1;
|
||||
}
|
||||
|
||||
if (i >= urlParametersPos && urlParametersPos != 0)
|
||||
{
|
||||
urlparameters += "/" + segments[i];
|
||||
}
|
||||
|
||||
if (segments[i] == Constants.ModuleDelimiter)
|
||||
{
|
||||
modIdPos = i + 1;
|
||||
actionPos = modIdPos + 1;
|
||||
if (actionPos <= segments.Length - 1)
|
||||
{
|
||||
action = segments[actionPos];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if path has moduleid and action specification ie. pagename/*/moduleid/action/
|
||||
if (modIdPos > 0)
|
||||
{
|
||||
int.TryParse(segments[modIdPos], out result);
|
||||
moduleid = result;
|
||||
if (actionPos > segments.Length - 1)
|
||||
{
|
||||
path = path.Replace(segments[modIdPos - 1] + "/" + segments[modIdPos] + "/", "");
|
||||
}
|
||||
else
|
||||
{
|
||||
path = path.Replace(segments[modIdPos - 1] + "/" + segments[modIdPos] + "/" + segments[actionPos] + "/", "");
|
||||
}
|
||||
}
|
||||
|
||||
if (urlParametersPos > 0)
|
||||
{
|
||||
path = path.Replace(segments[urlParametersPos - 1] + urlparameters + "/", "");
|
||||
}
|
||||
|
||||
// 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 || refresh == UI.Refresh.Site)
|
||||
{
|
||||
page = pages.FirstOrDefault(item => item.Path.Equals(path, StringComparison.OrdinalIgnoreCase));
|
||||
page = pages.FirstOrDefault(item => item.Path.Equals(route.PagePath, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -241,14 +175,13 @@
|
||||
}
|
||||
|
||||
// get the page if the path has changed
|
||||
if (page == null || page.Path != path)
|
||||
if (page == null || page.Path != route.PagePath)
|
||||
{
|
||||
page = pages.FirstOrDefault(item => item.Path.Equals(path, StringComparison.OrdinalIgnoreCase));
|
||||
// if the home page path does not exist then use the first page in the collection (a future enhancement would allow the admin to specify a home page)
|
||||
if (page == null && path == "")
|
||||
page = pages.FirstOrDefault(item => item.Path.Equals(route.PagePath, StringComparison.OrdinalIgnoreCase));
|
||||
// if the home page path does not exist then use the first page in the collection (a future enhancement would allow the admin to specify the home page)
|
||||
if (page == null && route.PagePath == "")
|
||||
{
|
||||
page = pages.FirstOrDefault();
|
||||
path = page.Path;
|
||||
}
|
||||
editmode = false;
|
||||
}
|
||||
@ -286,12 +219,13 @@
|
||||
Modules = modules,
|
||||
Uri = new Uri(_absoluteUri, UriKind.Absolute),
|
||||
QueryString = querystring,
|
||||
UrlParameters = urlparameters,
|
||||
UrlParameters = route.UrlParameters,
|
||||
ModuleId = moduleid,
|
||||
Action = action,
|
||||
EditMode = editmode,
|
||||
LastSyncDate = lastsyncdate,
|
||||
Runtime = runtime
|
||||
Runtime = runtime,
|
||||
VisitorId = VisitorId
|
||||
};
|
||||
|
||||
OnStateChange?.Invoke(_pagestate);
|
||||
@ -302,12 +236,12 @@
|
||||
if (user == null)
|
||||
{
|
||||
// redirect to login page
|
||||
NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "login", "?returnurl=" + path));
|
||||
NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "login", "?returnurl=" + route.AbsolutePath));
|
||||
}
|
||||
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 != "")
|
||||
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 != "")
|
||||
{
|
||||
// redirect to home page
|
||||
NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "", ""));
|
||||
|
@ -5,103 +5,55 @@
|
||||
@DynamicComponent
|
||||
|
||||
@code {
|
||||
[CascadingParameter] PageState PageState { get; set; }
|
||||
[CascadingParameter] PageState PageState { get; set; }
|
||||
|
||||
RenderFragment DynamicComponent { get; set; }
|
||||
RenderFragment DynamicComponent { get; set; }
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
var interop = new Interop(JsRuntime);
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
// handle page redirection
|
||||
if (!string.IsNullOrEmpty(PageState.Page.Url))
|
||||
{
|
||||
NavigationManager.NavigateTo(PageState.Page.Url);
|
||||
return;
|
||||
}
|
||||
|
||||
// handle page redirection
|
||||
if (!string.IsNullOrEmpty(PageState.Page.Url))
|
||||
{
|
||||
NavigationManager.NavigateTo(PageState.Page.Url);
|
||||
return;
|
||||
}
|
||||
DynamicComponent = builder =>
|
||||
{
|
||||
var themeType = Type.GetType(PageState.Page.ThemeType);
|
||||
builder.OpenComponent(0, themeType);
|
||||
builder.CloseComponent();
|
||||
};
|
||||
}
|
||||
|
||||
// set page title
|
||||
if (!string.IsNullOrEmpty(PageState.Page.Title))
|
||||
{
|
||||
await interop.UpdateTitle(PageState.Page.Title);
|
||||
}
|
||||
else
|
||||
{
|
||||
await interop.UpdateTitle(PageState.Site.Name + " - " + PageState.Page.Name);
|
||||
}
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (!firstRender)
|
||||
{
|
||||
var interop = new Interop(JsRuntime);
|
||||
|
||||
// manage stylesheets for this page
|
||||
string batch = DateTime.Now.ToString("yyyyMMddHHmmssfff");
|
||||
var links = new List<object>();
|
||||
foreach (Resource resource in PageState.Page.Resources.Where(item => item.ResourceType == ResourceType.Stylesheet && item.Declaration != ResourceDeclaration.Global))
|
||||
{
|
||||
links.Add(new { id = "app-stylesheet-" + batch + "-" + (links.Count + 1).ToString("00"), rel = "stylesheet", href = resource.Url, type = "text/css", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", key = "" });
|
||||
}
|
||||
if (links.Any())
|
||||
{
|
||||
await interop.IncludeLinks(links.ToArray());
|
||||
}
|
||||
await interop.RemoveElementsById("app-stylesheet", "", "app-stylesheet-" + batch + "-00");
|
||||
// set page title
|
||||
if (!string.IsNullOrEmpty(PageState.Page.Title))
|
||||
{
|
||||
await interop.UpdateTitle(PageState.Page.Title);
|
||||
}
|
||||
else
|
||||
{
|
||||
await interop.UpdateTitle(PageState.Site.Name + " - " + PageState.Page.Name);
|
||||
}
|
||||
|
||||
// add favicon
|
||||
if (PageState.Site.FaviconFileId != null)
|
||||
{
|
||||
await interop.IncludeLink("app-favicon", "shortcut icon", Utilities.ContentUrl(PageState.Alias, PageState.Site.FaviconFileId.Value), "image/x-icon", "", "", "id");
|
||||
}
|
||||
// add PWA support
|
||||
if (PageState.Site.PwaIsEnabled && PageState.Site.PwaAppIconFileId != null && PageState.Site.PwaSplashIconFileId != null)
|
||||
{
|
||||
await InitializePwa(interop);
|
||||
}
|
||||
|
||||
DynamicComponent = builder =>
|
||||
{
|
||||
var themeType = Type.GetType(PageState.Page.ThemeType);
|
||||
builder.OpenComponent(0, themeType);
|
||||
builder.CloseComponent();
|
||||
};
|
||||
}
|
||||
|
||||
private async Task InitializePwa(Interop interop)
|
||||
{
|
||||
string url = NavigationManager.BaseUri;
|
||||
url = url.Substring(0, url.Length - 1);
|
||||
|
||||
// dynamically create manifest.json and add to page
|
||||
string manifest = "setTimeout(() => { " +
|
||||
"var manifest = { " +
|
||||
"\"name\": \"" + PageState.Site.Name + "\", " +
|
||||
"\"short_name\": \"" + PageState.Site.Name + "\", " +
|
||||
"\"start_url\": \"" + url + "/\", " +
|
||||
"\"display\": \"standalone\", " +
|
||||
"\"background_color\": \"#fff\", " +
|
||||
"\"description\": \"" + PageState.Site.Name + "\", " +
|
||||
"\"icons\": [{ " +
|
||||
"\"src\": \"" + url + Utilities.ContentUrl(PageState.Alias, PageState.Site.PwaAppIconFileId.Value) + "\", " +
|
||||
"\"sizes\": \"192x192\", " +
|
||||
"\"type\": \"image/png\" " +
|
||||
"}, { " +
|
||||
"\"src\": \"" + url + Utilities.ContentUrl(PageState.Alias, PageState.Site.PwaSplashIconFileId.Value) + "\", " +
|
||||
"\"sizes\": \"512x512\", " +
|
||||
"\"type\": \"image/png\" " +
|
||||
"}] " +
|
||||
"}; " +
|
||||
"const serialized = JSON.stringify(manifest); " +
|
||||
"const blob = new Blob([serialized], {type: 'application/javascript'}); " +
|
||||
"const url = URL.createObjectURL(blob); " +
|
||||
"document.getElementById('app-manifest').setAttribute('href', url); " +
|
||||
"} " +
|
||||
", 1000);";
|
||||
await interop.IncludeScript("app-pwa", "", "", "", manifest, "body", "id");
|
||||
|
||||
// service worker must be in root of site
|
||||
string serviceworker = "if ('serviceWorker' in navigator) { " +
|
||||
"navigator.serviceWorker.register('/service-worker.js').then(function(registration) { " +
|
||||
"console.log('ServiceWorker Registration Successful'); " +
|
||||
"}).catch (function(err) { " +
|
||||
"console.log('ServiceWorker Registration Failed ', err); " +
|
||||
"}); " +
|
||||
"}";
|
||||
await interop.IncludeScript("app-serviceworker", "", "", "", serviceworker, "body", "id");
|
||||
}
|
||||
// manage stylesheets for this page
|
||||
string batch = DateTime.Now.ToString("yyyyMMddHHmmssfff");
|
||||
var links = new List<object>();
|
||||
foreach (Resource resource in PageState.Page.Resources.Where(item => item.ResourceType == ResourceType.Stylesheet && item.Declaration != ResourceDeclaration.Global))
|
||||
{
|
||||
links.Add(new { id = "app-stylesheet-" + batch + "-" + (links.Count + 1).ToString("00"), rel = "stylesheet", href = resource.Url, type = "text/css", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", key = "" });
|
||||
}
|
||||
if (links.Any())
|
||||
{
|
||||
await interop.IncludeLinks(links.ToArray());
|
||||
}
|
||||
await interop.RemoveElementsById("app-stylesheet", "", "app-stylesheet-" + batch + "-00");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Version>3.0.0</Version>
|
||||
<Version>3.0.1</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -10,7 +10,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.0</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Database.MySQL</id>
|
||||
<version>3.0.0</version>
|
||||
<version>3.0.1</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane MySQL Provider</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.0</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Version>3.0.0</Version>
|
||||
<Version>3.0.1</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -10,7 +10,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.0</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Database.PostgreSQL</id>
|
||||
<version>3.0.0</version>
|
||||
<version>3.0.1</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane PostgreSQL Provider</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.0</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Version>3.0.0</Version>
|
||||
<Version>3.0.1</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -10,7 +10,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.0</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Database.SqlServer</id>
|
||||
<version>3.0.0</version>
|
||||
<version>3.0.1</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane SQL Server Provider</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.0</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Version>3.0.0</Version>
|
||||
<Version>3.0.1</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -10,7 +10,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.0</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Database.Sqlite</id>
|
||||
<version>3.0.0</version>
|
||||
<version>3.0.1</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane SQLite Provider</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.0</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Client</id>
|
||||
<version>3.0.0</version>
|
||||
<version>3.0.1</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane Framework</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.0</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Framework</id>
|
||||
<version>3.0.0</version>
|
||||
<version>3.0.1</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane Framework</title>
|
||||
@ -11,8 +11,8 @@
|
||||
<copyright>.NET Foundation</copyright>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework/releases/download/v3.0.0/Oqtane.Framework.3.0.0.Upgrade.zip</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.0</releaseNotes>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework/releases/download/v3.0.1/Oqtane.Framework.3.0.1.Upgrade.zip</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane framework</tags>
|
||||
</metadata>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Server</id>
|
||||
<version>3.0.0</version>
|
||||
<version>3.0.1</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane Framework</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.0</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Shared</id>
|
||||
<version>3.0.0</version>
|
||||
<version>3.0.1</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane Framework</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.0</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Updater</id>
|
||||
<version>3.0.0</version>
|
||||
<version>3.0.1</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane Framework</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.0</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -1 +1 @@
|
||||
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net6.0\publish\*" -DestinationPath "Oqtane.Framework.3.0.0.Install.zip" -Force
|
||||
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net6.0\publish\*" -DestinationPath "Oqtane.Framework.3.0.1.Install.zip" -Force
|
@ -1 +1 @@
|
||||
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net6.0\publish\*" -DestinationPath "Oqtane.Framework.3.0.0.Upgrade.zip" -Force
|
||||
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net6.0\publish\*" -DestinationPath "Oqtane.Framework.3.0.1.Upgrade.zip" -Force
|
@ -508,8 +508,8 @@ namespace Oqtane.Controllers
|
||||
return System.IO.File.Exists(errorPath) ? PhysicalFile(errorPath, MimeUtilities.GetMimeType(errorPath)) : null;
|
||||
}
|
||||
|
||||
[HttpGet("image/{id}/{width}/{height}/{mode?}")]
|
||||
public IActionResult GetImage(int id, int width, int height, string mode)
|
||||
[HttpGet("image/{id}/{width}/{height}/{mode?}/{rotate?}")]
|
||||
public IActionResult GetImage(int id, int width, int height, string mode, string rotate)
|
||||
{
|
||||
var file = _files.GetFile(id);
|
||||
if (file != null && file.Folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.View, file.Folder.Permissions))
|
||||
@ -520,6 +520,7 @@ namespace Oqtane.Controllers
|
||||
if (System.IO.File.Exists(filepath))
|
||||
{
|
||||
mode = (string.IsNullOrEmpty(mode)) ? "crop" : mode;
|
||||
rotate = (string.IsNullOrEmpty(rotate)) ? "0" : rotate;
|
||||
|
||||
string imagepath = filepath.Replace(Path.GetExtension(filepath), "." + width.ToString() + "x" + height.ToString() + "." + mode.ToLower() + ".png");
|
||||
if (!System.IO.File.Exists(imagepath))
|
||||
@ -528,7 +529,7 @@ namespace Oqtane.Controllers
|
||||
!string.IsNullOrEmpty(file.Folder.ImageSizes) && file.Folder.ImageSizes.ToLower().Split(",").Contains(width.ToString() + "x" + height.ToString()))
|
||||
&& Enum.TryParse(mode, true, out ResizeMode resizemode))
|
||||
{
|
||||
imagepath = CreateImage(filepath, width, height, resizemode.ToString(), imagepath);
|
||||
imagepath = CreateImage(filepath, width, height, resizemode.ToString(), rotate, imagepath);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -568,7 +569,7 @@ namespace Oqtane.Controllers
|
||||
return System.IO.File.Exists(errorPath) ? PhysicalFile(errorPath, MimeUtilities.GetMimeType(errorPath)) : null;
|
||||
}
|
||||
|
||||
private string CreateImage(string filepath, int width, int height, string mode, string imagepath)
|
||||
private string CreateImage(string filepath, int width, int height, string mode, string rotate, string imagepath)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -585,6 +586,11 @@ namespace Oqtane.Controllers
|
||||
})
|
||||
.BackgroundColor(new Rgba32(255, 255, 255, 0)));
|
||||
|
||||
if (rotate != "0" && int.TryParse(rotate, out int angle))
|
||||
{
|
||||
image.Mutate(x => x.Rotate(angle));
|
||||
}
|
||||
|
||||
image.Save(imagepath, new PngEncoder());
|
||||
}
|
||||
stream.Close();
|
||||
|
@ -22,11 +22,12 @@ namespace Oqtane.Controllers
|
||||
private readonly IPermissionRepository _permissionRepository;
|
||||
private readonly ISettingRepository _settings;
|
||||
private readonly IUserPermissions _userPermissions;
|
||||
private readonly IUrlMappingRepository _urlMappings;
|
||||
private readonly ISyncManager _syncManager;
|
||||
private readonly ILogManager _logger;
|
||||
private readonly Alias _alias;
|
||||
|
||||
public PageController(IPageRepository pages, IModuleRepository modules, IPageModuleRepository pageModules, IPermissionRepository permissionRepository, ISettingRepository settings, IUserPermissions userPermissions, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger)
|
||||
public PageController(IPageRepository pages, IModuleRepository modules, IPageModuleRepository pageModules, IPermissionRepository permissionRepository, ISettingRepository settings, IUserPermissions userPermissions, IUrlMappingRepository urlMappings, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger)
|
||||
{
|
||||
_pages = pages;
|
||||
_modules = modules;
|
||||
@ -34,6 +35,7 @@ namespace Oqtane.Controllers
|
||||
_permissionRepository = permissionRepository;
|
||||
_settings = settings;
|
||||
_userPermissions = userPermissions;
|
||||
_urlMappings = urlMappings;
|
||||
_syncManager = syncManager;
|
||||
_logger = logger;
|
||||
_alias = tenantManager.GetAlias();
|
||||
@ -252,17 +254,34 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
public Page Put(int id, [FromBody] Page page)
|
||||
{
|
||||
if (ModelState.IsValid && page.SiteId == _alias.SiteId && _pages.GetPage(page.PageId, false) != null && _userPermissions.IsAuthorized(User, EntityNames.Page, page.PageId, PermissionNames.Edit))
|
||||
// get current page
|
||||
var currentPage = _pages.GetPage(page.PageId, false);
|
||||
|
||||
if (ModelState.IsValid && page.SiteId == _alias.SiteId && currentPage != null && _userPermissions.IsAuthorized(User, EntityNames.Page, page.PageId, PermissionNames.Edit))
|
||||
{
|
||||
// preserve page permissions
|
||||
var oldPermissions = _permissionRepository.GetPermissions(EntityNames.Page, page.PageId).ToList();
|
||||
// get current page permissions
|
||||
var currentPermissions = _permissionRepository.GetPermissions(EntityNames.Page, page.PageId).ToList();
|
||||
|
||||
page = _pages.UpdatePage(page);
|
||||
|
||||
// get differences between old and new page permissions
|
||||
// save url mapping if page path changed
|
||||
if (currentPage.Path != page.Path)
|
||||
{
|
||||
var url = HttpContext.Request.Scheme + "://" + _alias.Name + "/";
|
||||
var urlMapping = new UrlMapping();
|
||||
urlMapping.SiteId = page.SiteId;
|
||||
urlMapping.Url = url + currentPage.Path;
|
||||
urlMapping.MappedUrl = url + page.Path;
|
||||
urlMapping.Requests = 0;
|
||||
urlMapping.CreatedOn = System.DateTime.UtcNow;
|
||||
urlMapping.RequestedOn = System.DateTime.UtcNow;
|
||||
_urlMappings.AddUrlMapping(urlMapping);
|
||||
}
|
||||
|
||||
// get differences between current and new page permissions
|
||||
var newPermissions = _permissionRepository.DecodePermissions(page.Permissions, page.SiteId, EntityNames.Page, page.PageId).ToList();
|
||||
var added = GetPermissionsDifferences(newPermissions, oldPermissions);
|
||||
var removed = GetPermissionsDifferences(oldPermissions, newPermissions);
|
||||
var added = GetPermissionsDifferences(newPermissions, currentPermissions);
|
||||
var removed = GetPermissionsDifferences(currentPermissions, newPermissions);
|
||||
|
||||
// synchronize module permissions
|
||||
if (added.Count > 0 || removed.Count > 0)
|
||||
@ -270,7 +289,6 @@ namespace Oqtane.Controllers
|
||||
foreach (PageModule pageModule in _pageModules.GetPageModules(page.PageId, "").ToList())
|
||||
{
|
||||
var modulePermissions = _permissionRepository.GetPermissions(EntityNames.Module, pageModule.Module.ModuleId).ToList();
|
||||
//var modulePermissions = _permissionRepository.DecodePermissions(pageModule.Module.Permissions, page.SiteId, EntityNames.Module, pageModule.ModuleId).ToList();
|
||||
// permissions added
|
||||
foreach(Permission permission in added)
|
||||
{
|
||||
|
@ -33,36 +33,66 @@ namespace Oqtane.Controllers
|
||||
|
||||
// GET: api/<controller>
|
||||
[HttpGet]
|
||||
public IEnumerable<Setting> Get(string entityname, int entityid)
|
||||
public IEnumerable<Setting> Get(string entityName, int entityid)
|
||||
{
|
||||
List<Setting> settings = new List<Setting>();
|
||||
if (IsAuthorized(entityname, entityid, PermissionNames.View))
|
||||
if (IsAuthorized(entityName, entityid, PermissionNames.View))
|
||||
{
|
||||
settings = _settings.GetSettings(entityname, entityid).ToList();
|
||||
if (entityname == EntityNames.Site && !User.IsInRole(RoleNames.Admin))
|
||||
settings = _settings.GetSettings(entityName, entityid).ToList();
|
||||
|
||||
// ispublic filter
|
||||
switch (entityName)
|
||||
{
|
||||
settings = settings.Where(item => item.IsPublic).ToList();
|
||||
case EntityNames.Tenant:
|
||||
case EntityNames.ModuleDefinition:
|
||||
case EntityNames.Host:
|
||||
if (!User.IsInRole(RoleNames.Host))
|
||||
{
|
||||
settings = settings.Where(item => item.IsPublic).ToList();
|
||||
}
|
||||
break;
|
||||
case EntityNames.Site:
|
||||
if (!User.IsInRole(RoleNames.Admin))
|
||||
{
|
||||
settings = settings.Where(item => item.IsPublic).ToList();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access Settings {EntityName} {EntityId}", entityname, entityid);
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access Settings {EntityName} {EntityId}", entityName, entityid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
return settings;
|
||||
}
|
||||
|
||||
// GET api/<controller>/5
|
||||
[HttpGet("{id}")]
|
||||
public Setting Get(int id)
|
||||
// GET api/<controller>/5/xxx
|
||||
[HttpGet("{id}/{entityName}")]
|
||||
public Setting Get(int id, string entityName)
|
||||
{
|
||||
Setting setting = _settings.GetSetting(id);
|
||||
Setting setting = _settings.GetSetting(entityName, id);
|
||||
if (IsAuthorized(setting.EntityName, setting.EntityId, PermissionNames.View))
|
||||
{
|
||||
if (setting.EntityName == EntityNames.Site && !User.IsInRole(RoleNames.Admin) && !setting.IsPublic)
|
||||
// ispublic filter
|
||||
switch (entityName)
|
||||
{
|
||||
setting = null;
|
||||
case EntityNames.Tenant:
|
||||
case EntityNames.ModuleDefinition:
|
||||
case EntityNames.Host:
|
||||
if (!User.IsInRole(RoleNames.Host) && !setting.IsPublic)
|
||||
{
|
||||
setting = null;
|
||||
}
|
||||
break;
|
||||
case EntityNames.Site:
|
||||
if (!User.IsInRole(RoleNames.Admin) && !setting.IsPublic)
|
||||
{
|
||||
setting = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return setting;
|
||||
}
|
||||
else
|
||||
@ -111,14 +141,14 @@ namespace Oqtane.Controllers
|
||||
return setting;
|
||||
}
|
||||
|
||||
// DELETE api/<controller>/5
|
||||
[HttpDelete("{id}")]
|
||||
public void Delete(int id)
|
||||
// DELETE api/<controller>/5/xxx
|
||||
[HttpDelete("{id}/{entityName}")]
|
||||
public void Delete(string entityName, int id)
|
||||
{
|
||||
Setting setting = _settings.GetSetting(id);
|
||||
Setting setting = _settings.GetSetting(entityName, id);
|
||||
if (IsAuthorized(setting.EntityName, setting.EntityId, PermissionNames.Edit))
|
||||
{
|
||||
_settings.DeleteSetting(id);
|
||||
_settings.DeleteSetting(setting.EntityName, id);
|
||||
AddSyncEvent(setting.EntityName);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Setting Deleted {Setting}", setting);
|
||||
}
|
||||
@ -140,7 +170,16 @@ namespace Oqtane.Controllers
|
||||
switch (entityName)
|
||||
{
|
||||
case EntityNames.Tenant:
|
||||
authorized = User.IsInRole(RoleNames.Host);
|
||||
case EntityNames.ModuleDefinition:
|
||||
case EntityNames.Host:
|
||||
if (permissionName == PermissionNames.Edit)
|
||||
{
|
||||
authorized = User.IsInRole(RoleNames.Host);
|
||||
}
|
||||
else
|
||||
{
|
||||
authorized = true;
|
||||
}
|
||||
break;
|
||||
case EntityNames.Site:
|
||||
if (permissionName == PermissionNames.Edit)
|
||||
@ -164,6 +203,17 @@ namespace Oqtane.Controllers
|
||||
authorized = User.IsInRole(RoleNames.Admin) || (_userPermissions.GetUser(User).UserId == entityId);
|
||||
}
|
||||
break;
|
||||
case EntityNames.Visitor:
|
||||
var visitorCookie = "APP_VISITOR_" + _alias.SiteId.ToString();
|
||||
if (int.TryParse(Request.Cookies[visitorCookie], out int visitorId))
|
||||
{
|
||||
authorized = (visitorId == entityId);
|
||||
}
|
||||
else
|
||||
{
|
||||
authorized = User.IsInRole(RoleNames.Admin);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return authorized;
|
||||
}
|
||||
|
119
Oqtane.Server/Controllers/UrlMappingController.cs
Normal file
119
Oqtane.Server/Controllers/UrlMappingController.cs
Normal file
@ -0,0 +1,119 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Oqtane.Enums;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Shared;
|
||||
using Oqtane.Infrastructure;
|
||||
using Oqtane.Repository;
|
||||
using System.Net;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class UrlMappingController : Controller
|
||||
{
|
||||
private readonly IUrlMappingRepository _urlMappings;
|
||||
private readonly ILogManager _logger;
|
||||
private readonly Alias _alias;
|
||||
|
||||
public UrlMappingController(IUrlMappingRepository urlMappings, ILogManager logger, ITenantManager tenantManager)
|
||||
{
|
||||
_urlMappings = urlMappings;
|
||||
_logger = logger;
|
||||
_alias = tenantManager.GetAlias();
|
||||
}
|
||||
|
||||
// GET: api/<controller>?siteid=x&ismapped=y
|
||||
[HttpGet]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public IEnumerable<UrlMapping> Get(string siteid, string ismapped)
|
||||
{
|
||||
int SiteId;
|
||||
if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId)
|
||||
{
|
||||
return _urlMappings.GetUrlMappings(SiteId, bool.Parse(ismapped));
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized UrlMapping Get Attempt {SiteId}", siteid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// GET api/<controller>/5
|
||||
[HttpGet("{id}")]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public UrlMapping Get(int id)
|
||||
{
|
||||
var urlMapping = _urlMappings.GetUrlMapping(id);
|
||||
if (urlMapping != null && (urlMapping.SiteId == _alias.SiteId))
|
||||
{
|
||||
return urlMapping;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized UrlMapping Get Attempt {UrlMappingId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// POST api/<controller>
|
||||
[HttpPost]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public UrlMapping Post([FromBody] UrlMapping urlMapping)
|
||||
{
|
||||
if (ModelState.IsValid && urlMapping.SiteId == _alias.SiteId)
|
||||
{
|
||||
urlMapping = _urlMappings.AddUrlMapping(urlMapping);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "UrlMapping Added {UrlMapping}", urlMapping);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized UrlMapping Post Attempt {Role}", urlMapping);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
urlMapping = null;
|
||||
}
|
||||
return urlMapping;
|
||||
}
|
||||
|
||||
// PUT api/<controller>/5
|
||||
[HttpPut("{id}")]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public UrlMapping Put(int id, [FromBody] UrlMapping urlMapping)
|
||||
{
|
||||
if (ModelState.IsValid && urlMapping.SiteId == _alias.SiteId && _urlMappings.GetUrlMapping(urlMapping.UrlMappingId, false) != null)
|
||||
{
|
||||
urlMapping = _urlMappings.UpdateUrlMapping(urlMapping);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "UrlMapping Updated {UrlMapping}", urlMapping);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized UrlMapping Put Attempt {UrlMapping}", urlMapping);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
urlMapping = null;
|
||||
}
|
||||
return urlMapping;
|
||||
}
|
||||
|
||||
// DELETE api/<controller>/5
|
||||
[HttpDelete("{id}")]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public void Delete(int id)
|
||||
{
|
||||
var urlMapping = _urlMappings.GetUrlMapping(id);
|
||||
if (urlMapping != null && urlMapping.SiteId == _alias.SiteId)
|
||||
{
|
||||
_urlMappings.DeleteUrlMapping(id);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "UrlMapping Deleted {UrlMappingId}", id);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized UrlMapping Delete Attempt {UrlMappingId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
74
Oqtane.Server/Controllers/VisitorController.cs
Normal file
74
Oqtane.Server/Controllers/VisitorController.cs
Normal file
@ -0,0 +1,74 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Oqtane.Enums;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Shared;
|
||||
using Oqtane.Infrastructure;
|
||||
using Oqtane.Repository;
|
||||
using System.Net;
|
||||
using System;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class VisitorController : Controller
|
||||
{
|
||||
private readonly IVisitorRepository _visitors;
|
||||
private readonly ILogManager _logger;
|
||||
private readonly Alias _alias;
|
||||
|
||||
public VisitorController(IVisitorRepository visitors, ILogManager logger, ITenantManager tenantManager)
|
||||
{
|
||||
_visitors = visitors;
|
||||
_logger = logger;
|
||||
_alias = tenantManager.GetAlias();
|
||||
}
|
||||
|
||||
// GET: api/<controller>?siteid=x&fromdate=y
|
||||
[HttpGet]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public IEnumerable<Visitor> Get(string siteid, string fromdate)
|
||||
{
|
||||
int SiteId;
|
||||
if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId)
|
||||
{
|
||||
return _visitors.GetVisitors(SiteId, DateTime.Parse(fromdate));
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Visitor Get Attempt {SiteId}", siteid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// GET api/<controller>/5
|
||||
[HttpGet("{id}")]
|
||||
public Visitor Get(int id)
|
||||
{
|
||||
bool authorized;
|
||||
var visitorCookie = "APP_VISITOR_" + _alias.SiteId.ToString();
|
||||
if (int.TryParse(Request.Cookies[visitorCookie], out int visitorId))
|
||||
{
|
||||
authorized = (visitorId == id);
|
||||
}
|
||||
else
|
||||
{
|
||||
authorized = User.IsInRole(RoleNames.Admin);
|
||||
}
|
||||
|
||||
var visitor = _visitors.GetVisitor(id);
|
||||
if (authorized && visitor != null && visitor.SiteId == _alias.SiteId)
|
||||
{
|
||||
return visitor;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Visitor Get Attempt {VisitorId}", id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -98,6 +98,8 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||
services.AddTransient<ISqlRepository, SqlRepository>();
|
||||
services.AddTransient<IUpgradeManager, UpgradeManager>();
|
||||
services.AddTransient<ILanguageRepository, LanguageRepository>();
|
||||
services.AddTransient<IVisitorRepository, VisitorRepository>();
|
||||
services.AddTransient<IUrlMappingRepository, UrlMappingRepository>();
|
||||
// obsolete - replaced by ITenantManager
|
||||
services.AddTransient<ITenantResolver, TenantResolver>();
|
||||
|
||||
|
@ -582,12 +582,19 @@ namespace Oqtane.Infrastructure
|
||||
TenantId = tenant.TenantId,
|
||||
Name = install.SiteName,
|
||||
LogoFileId = null,
|
||||
FaviconFileId = null,
|
||||
PwaIsEnabled = false,
|
||||
PwaAppIconFileId = null,
|
||||
PwaSplashIconFileId = null,
|
||||
AllowRegistration = false,
|
||||
CaptureBrokenUrls = true,
|
||||
VisitorTracking = true,
|
||||
DefaultThemeType = (!string.IsNullOrEmpty(install.DefaultTheme)) ? install.DefaultTheme : Constants.DefaultTheme,
|
||||
DefaultContainerType = (!string.IsNullOrEmpty(install.DefaultContainer)) ? install.DefaultContainer : Constants.DefaultContainer,
|
||||
AdminContainerType = (!string.IsNullOrEmpty(install.DefaultAdminContainer)) ? install.DefaultAdminContainer : Constants.DefaultAdminContainer,
|
||||
SiteTemplateType = install.SiteTemplate,
|
||||
Runtime = (!string.IsNullOrEmpty(install.Runtime)) ? install.Runtime : _configManager.GetSection("Runtime").Value,
|
||||
RenderMode = (!string.IsNullOrEmpty(install.RenderMode)) ? install.RenderMode : _configManager.GetSection("RenderMode").Value
|
||||
RenderMode = (!string.IsNullOrEmpty(install.RenderMode)) ? install.RenderMode : _configManager.GetSection("RenderMode").Value,
|
||||
};
|
||||
site = sites.AddSite(site);
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user