commit
a703df40c0
|
@ -1,3 +1,5 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Microsoft.Extensions.Localization
|
namespace Microsoft.Extensions.Localization
|
||||||
{
|
{
|
||||||
public static class OqtaneLocalizationExtensions
|
public static class OqtaneLocalizationExtensions
|
||||||
|
@ -18,5 +20,42 @@ namespace Microsoft.Extensions.Localization
|
||||||
}
|
}
|
||||||
return localizedValue;
|
return localizedValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an IStringLocalizer based on a type name. This extension method is useful in scenarios where the default IStringLocalizer is unable to locate the resources.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="localizerFactory"></param>
|
||||||
|
/// <param name="fullTypeName">the full type name ie. GetType().FullName</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IStringLocalizer Create(this IStringLocalizerFactory localizerFactory, string fullTypeName)
|
||||||
|
{
|
||||||
|
var typename = fullTypeName;
|
||||||
|
|
||||||
|
// handle generic types
|
||||||
|
var type = Type.GetType(fullTypeName);
|
||||||
|
if (type.IsGenericType)
|
||||||
|
{
|
||||||
|
typename = type.GetGenericTypeDefinition().FullName;
|
||||||
|
typename = typename.Substring(0, typename.IndexOf("`")); // remove generic type info
|
||||||
|
}
|
||||||
|
|
||||||
|
// format typename
|
||||||
|
if (typename.Contains(","))
|
||||||
|
{
|
||||||
|
typename = typename.Substring(0, typename.IndexOf(",")); // remove assembly info
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove rootnamespace
|
||||||
|
var rootnamespace = "";
|
||||||
|
var attributes = type.Assembly.GetCustomAttributes(typeof(RootNamespaceAttribute), false);
|
||||||
|
if (attributes.Length > 0)
|
||||||
|
{
|
||||||
|
rootnamespace = ((RootNamespaceAttribute)attributes[0]).RootNamespace;
|
||||||
|
}
|
||||||
|
typename = typename.Replace(rootnamespace + ".", "");
|
||||||
|
|
||||||
|
// create IStringLocalizer using factory
|
||||||
|
return localizerFactory.Create(typename, type.Assembly.GetName().Name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,14 +29,7 @@
|
||||||
<select id="databasetype" class="form-select custom-select" value="@_databaseName" @onchange="(e => DatabaseChanged(e))">
|
<select id="databasetype" class="form-select custom-select" value="@_databaseName" @onchange="(e => DatabaseChanged(e))">
|
||||||
@foreach (var database in _databases)
|
@foreach (var database in _databases)
|
||||||
{
|
{
|
||||||
if (database.IsDefault)
|
<option value="@database.Name">@Localizer[@database.Name]</option>
|
||||||
{
|
|
||||||
<option value="@database.Name" selected>@Localizer[@database.Name]</option>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<option value="@database.Name">@Localizer[@database.Name]</option>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
}
|
}
|
||||||
|
@ -63,8 +56,8 @@
|
||||||
<Label Class="col-sm-3" For="password" HelpText="Provide a password for the primary user account" ResourceKey="Password">Password:</Label>
|
<Label Class="col-sm-3" For="password" HelpText="Provide a password for the primary user account" ResourceKey="Password">Password:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="password" type="@_passwordtype" class="form-control" @bind="@_hostPassword" autocomplete="new-password" />
|
<input id="password" type="@_passwordType" class="form-control" @bind="@_hostPassword" autocomplete="new-password" />
|
||||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword">@_togglepassword</button>
|
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword">@_togglePassword</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -72,8 +65,8 @@
|
||||||
<Label Class="col-sm-3" For="confirm" HelpText="Please confirm the password entered above by entering it again" ResourceKey="Confirm">Confirm:</Label>
|
<Label Class="col-sm-3" For="confirm" HelpText="Please confirm the password entered above by entering it again" ResourceKey="Confirm">Confirm:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@_confirmPassword" autocomplete="new-password" />
|
<input id="confirm" type="@_confirmPasswordType" class="form-control" @bind="@_confirmPassword" autocomplete="new-password" />
|
||||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword">@_togglepassword</button>
|
<button type="button" class="btn btn-secondary" @onclick="@ToggleConfirmPassword">@_toggleConfirmPassword</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -110,8 +103,10 @@
|
||||||
|
|
||||||
private string _hostUsername = string.Empty;
|
private string _hostUsername = string.Empty;
|
||||||
private string _hostPassword = string.Empty;
|
private string _hostPassword = string.Empty;
|
||||||
private string _passwordtype = "password";
|
private string _passwordType = "password";
|
||||||
private string _togglepassword = string.Empty;
|
private string _confirmPasswordType = "password";
|
||||||
|
private string _togglePassword = string.Empty;
|
||||||
|
private string _toggleConfirmPassword = string.Empty;
|
||||||
private string _confirmPassword = string.Empty;
|
private string _confirmPassword = string.Empty;
|
||||||
private string _hostEmail = string.Empty;
|
private string _hostEmail = string.Empty;
|
||||||
private bool _register = true;
|
private bool _register = true;
|
||||||
|
@ -120,7 +115,9 @@
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
_togglePassword = SharedLocalizer["ShowPassword"];
|
||||||
|
_toggleConfirmPassword = SharedLocalizer["ShowPassword"];
|
||||||
|
|
||||||
_databases = await DatabaseService.GetDatabasesAsync();
|
_databases = await DatabaseService.GetDatabasesAsync();
|
||||||
if (_databases.Exists(item => item.IsDefault))
|
if (_databases.Exists(item => item.IsDefault))
|
||||||
{
|
{
|
||||||
|
@ -230,15 +227,29 @@
|
||||||
|
|
||||||
private void TogglePassword()
|
private void TogglePassword()
|
||||||
{
|
{
|
||||||
if (_passwordtype == "password")
|
if (_passwordType == "password")
|
||||||
{
|
{
|
||||||
_passwordtype = "text";
|
_passwordType = "text";
|
||||||
_togglepassword = SharedLocalizer["HidePassword"];
|
_togglePassword = SharedLocalizer["HidePassword"];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_passwordtype = "password";
|
_passwordType = "password";
|
||||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
_togglePassword = SharedLocalizer["ShowPassword"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ToggleConfirmPassword()
|
||||||
|
{
|
||||||
|
if (_confirmPasswordType == "password")
|
||||||
|
{
|
||||||
|
_confirmPasswordType = "text";
|
||||||
|
_toggleConfirmPassword = SharedLocalizer["HidePassword"];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_confirmPasswordType = "password";
|
||||||
|
_toggleConfirmPassword = SharedLocalizer["ShowPassword"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ else
|
||||||
@if (_availableCultures.Count() == 0)
|
@if (_availableCultures.Count() == 0)
|
||||||
{
|
{
|
||||||
<ModuleMessage Type="MessageType.Info" Message="@_message"></ModuleMessage>
|
<ModuleMessage Type="MessageType.Info" Message="@_message"></ModuleMessage>
|
||||||
|
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -47,9 +48,9 @@ else
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-success" @onclick="SaveLanguage">@SharedLocalizer["Save"]</button>
|
<button type="button" class="btn btn-success" @onclick="SaveLanguage">@SharedLocalizer["Save"]</button>
|
||||||
|
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||||
</form>
|
</form>
|
||||||
}
|
}
|
||||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel Name="Download" ResourceKey="Download" Security="SecurityAccessLevel.Host">
|
<TabPanel Name="Download" ResourceKey="Download" Security="SecurityAccessLevel.Host">
|
||||||
<div class="row justify-content-center mb-3">
|
<div class="row justify-content-center mb-3">
|
||||||
|
@ -78,6 +79,7 @@ else
|
||||||
<strong>@(String.Format("{0:n0}", context.Downloads))</strong> @SharedLocalizer["Search.Downloads"] |
|
<strong>@(String.Format("{0:n0}", context.Downloads))</strong> @SharedLocalizer["Search.Downloads"] |
|
||||||
@SharedLocalizer["Search.Released"]: <strong>@context.ReleaseDate.ToString("MMM dd, yyyy")</strong> |
|
@SharedLocalizer["Search.Released"]: <strong>@context.ReleaseDate.ToString("MMM dd, yyyy")</strong> |
|
||||||
@SharedLocalizer["Search.Version"]: <strong>@context.Version</strong>
|
@SharedLocalizer["Search.Version"]: <strong>@context.Version</strong>
|
||||||
|
@((MarkupString)(!string.IsNullOrEmpty(context.PackageUrl) ? " | " + SharedLocalizer["Search.Source"] + ": <strong>" + new Uri(context.PackageUrl).Host + "</strong>" : ""))
|
||||||
@((MarkupString)(context.TrialPeriod > 0 ? " | <strong>" + context.TrialPeriod + " " + @SharedLocalizer["Trial"] + "</strong>" : ""))
|
@((MarkupString)(context.TrialPeriod > 0 ? " | <strong>" + context.TrialPeriod + " " + @SharedLocalizer["Trial"] + "</strong>" : ""))
|
||||||
</td>
|
</td>
|
||||||
<td style="width: 1px; vertical-align: middle;">
|
<td style="width: 1px; vertical-align: middle;">
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
@namespace Oqtane.Modules.Admin.Logs
|
@namespace Oqtane.Modules.Admin.Logs
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
|
@inject NavigationManager NavigationManager
|
||||||
@inject ILogService LogService
|
@inject ILogService LogService
|
||||||
@inject ISettingService SettingService
|
@inject ISettingService SettingService
|
||||||
@inject IStringLocalizer<Index> Localizer
|
@inject IStringLocalizer<Index> Localizer
|
||||||
|
@ -91,19 +92,23 @@ else
|
||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private string _level = "-";
|
private string _level = "-";
|
||||||
private string _function = "-";
|
private string _function = "-";
|
||||||
private string _rows = "10";
|
private string _rows = "10";
|
||||||
private int _page = 1;
|
private int _page = 1;
|
||||||
private List<Log> _logs;
|
private List<Log> _logs;
|
||||||
private string _retention = "";
|
private string _retention = "";
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (PageState.QueryString.ContainsKey("id") && int.TryParse(PageState.QueryString["id"], out int id))
|
||||||
|
{
|
||||||
|
NavigationManager.NavigateTo(EditUrl(PageState.Page.Path, ModuleState.ModuleId, "Detail", $"id={id}"));
|
||||||
|
}
|
||||||
if (PageState.QueryString.ContainsKey("level"))
|
if (PageState.QueryString.ContainsKey("level"))
|
||||||
{
|
{
|
||||||
_level = PageState.QueryString["level"];
|
_level = PageState.QueryString["level"];
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
<strong>@(String.Format("{0:n0}", context.Downloads))</strong> @SharedLocalizer["Search.Downloads"] |
|
<strong>@(String.Format("{0:n0}", context.Downloads))</strong> @SharedLocalizer["Search.Downloads"] |
|
||||||
@SharedLocalizer["Search.Released"]: <strong>@context.ReleaseDate.ToString("MMM dd, yyyy")</strong> |
|
@SharedLocalizer["Search.Released"]: <strong>@context.ReleaseDate.ToString("MMM dd, yyyy")</strong> |
|
||||||
@SharedLocalizer["Search.Version"]: <strong>@context.Version</strong>
|
@SharedLocalizer["Search.Version"]: <strong>@context.Version</strong>
|
||||||
|
@((MarkupString)(!string.IsNullOrEmpty(context.PackageUrl) ? " | " + SharedLocalizer["Search.Source"] + ": <strong>" + new Uri(context.PackageUrl).Host + "</strong>" : ""))
|
||||||
@((MarkupString)(context.TrialPeriod > 0 ? " | <strong>" + context.TrialPeriod + " " + @SharedLocalizer["Trial"] + "</strong>" : ""))
|
@((MarkupString)(context.TrialPeriod > 0 ? " | <strong>" + context.TrialPeriod + " " + @SharedLocalizer["Trial"] + "</strong>" : ""))
|
||||||
</td>
|
</td>
|
||||||
<td style="width: 1px; vertical-align: middle;">
|
<td style="width: 1px; vertical-align: middle;">
|
||||||
|
@ -114,145 +115,145 @@
|
||||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private List<Package> _packages;
|
private List<Package> _packages;
|
||||||
private string _price = "free";
|
private string _price = "free";
|
||||||
private string _search = "";
|
private string _search = "";
|
||||||
private string _productname = "";
|
private string _productname = "";
|
||||||
private string _license = "";
|
private string _license = "";
|
||||||
private string _packageid = "";
|
private string _packageid = "";
|
||||||
private string _version = "";
|
private string _version = "";
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await LoadModuleDefinitions();
|
await LoadModuleDefinitions();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Loading Packages {Error}", ex.Message);
|
await logger.LogError(ex, "Error Loading Packages {Error}", ex.Message);
|
||||||
AddModuleMessage(Localizer["Error.Package.Load"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.Package.Load"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task LoadModuleDefinitions()
|
private async Task LoadModuleDefinitions()
|
||||||
{
|
{
|
||||||
var moduledefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
|
var moduledefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
|
||||||
_packages = await PackageService.GetPackagesAsync("module", _search, _price, "");
|
_packages = await PackageService.GetPackagesAsync("module", _search, _price, "");
|
||||||
|
|
||||||
if (_packages != null)
|
if (_packages != null)
|
||||||
{
|
{
|
||||||
foreach (Package package in _packages.ToArray())
|
foreach (Package package in _packages.ToArray())
|
||||||
{
|
{
|
||||||
if (moduledefinitions.Exists(item => item.PackageName == package.PackageId))
|
if (moduledefinitions.Exists(item => item.PackageName == package.PackageId))
|
||||||
{
|
{
|
||||||
_packages.Remove(package);
|
_packages.Remove(package);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void PriceChanged(ChangeEventArgs e)
|
private async void PriceChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_price = (string)e.Value;
|
_price = (string)e.Value;
|
||||||
_search = "";
|
_search = "";
|
||||||
await LoadModuleDefinitions();
|
await LoadModuleDefinitions();
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error On PriceChanged");
|
await logger.LogError(ex, "Error On PriceChanged");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Search()
|
private async Task Search()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await LoadModuleDefinitions();
|
await LoadModuleDefinitions();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error On Search");
|
await logger.LogError(ex, "Error On Search");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Reset()
|
private async Task Reset()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_search = "";
|
_search = "";
|
||||||
await LoadModuleDefinitions();
|
await LoadModuleDefinitions();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error On Reset");
|
await logger.LogError(ex, "Error On Reset");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HideModal()
|
private void HideModal()
|
||||||
{
|
{
|
||||||
_productname = "";
|
_productname = "";
|
||||||
_license = "";
|
_license = "";
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task GetPackage(string packageid, string version)
|
private async Task GetPackage(string packageid, string version)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var package = await PackageService.GetPackageAsync(packageid, version);
|
var package = await PackageService.GetPackageAsync(packageid, version);
|
||||||
if (package != null)
|
if (package != null)
|
||||||
{
|
{
|
||||||
_productname = package.Name;
|
_productname = package.Name;
|
||||||
if (!string.IsNullOrEmpty(package.License))
|
if (!string.IsNullOrEmpty(package.License))
|
||||||
{
|
{
|
||||||
_license = package.License.Replace("\n", "<br />");
|
_license = package.License.Replace("\n", "<br />");
|
||||||
}
|
}
|
||||||
_packageid = package.PackageId;
|
_packageid = package.PackageId;
|
||||||
_version = package.Version;
|
_version = package.Version;
|
||||||
}
|
}
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Getting Package {PackageId} {Version}", packageid, version);
|
await logger.LogError(ex, "Error Getting Package {PackageId} {Version}", packageid, version);
|
||||||
AddModuleMessage(Localizer["Error.Module.Download"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.Module.Download"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DownloadPackage()
|
private async Task DownloadPackage()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await PackageService.DownloadPackageAsync(_packageid, _version, Constants.PackagesFolder);
|
await PackageService.DownloadPackageAsync(_packageid, _version, Constants.PackagesFolder);
|
||||||
await logger.LogInformation("Package {PackageId} {Version} Downloaded Successfully", _packageid, _version);
|
await logger.LogInformation("Package {PackageId} {Version} Downloaded Successfully", _packageid, _version);
|
||||||
AddModuleMessage(Localizer["Success.Module.Download"], MessageType.Success);
|
AddModuleMessage(Localizer["Success.Module.Download"], MessageType.Success);
|
||||||
_productname = "";
|
_productname = "";
|
||||||
_license = "";
|
_license = "";
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Downloading Package {PackageId} {Version}", _packageid, _version);
|
await logger.LogError(ex, "Error Downloading Package {PackageId} {Version}", _packageid, _version);
|
||||||
AddModuleMessage(Localizer["Error.Module.Download"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.Module.Download"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task InstallModules()
|
private async Task InstallModules()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await ModuleDefinitionService.InstallModuleDefinitionsAsync();
|
await ModuleDefinitionService.InstallModuleDefinitionsAsync();
|
||||||
AddModuleMessage(string.Format(Localizer["Success.Module.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
AddModuleMessage(string.Format(Localizer["Success.Module.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Installing Module");
|
await logger.LogError(ex, "Error Installing Module");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,32 @@
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<ActionLink Action="Add" Text="Install Module" ResourceKey="InstallModule" />
|
<div class="container">
|
||||||
@((MarkupString)" ")
|
<div class="row mb-3 align-items-center">
|
||||||
<ActionLink Action="Create" Text="Create Module" ResourceKey="CreateModule" Class="btn btn-secondary" />
|
<div class="col-sm-6">
|
||||||
|
<ActionLink Action="Add" Text="Install Module" ResourceKey="InstallModule" />
|
||||||
<Pager Items="@_moduleDefinitions">
|
@((MarkupString)" ")
|
||||||
|
<ActionLink Action="Create" Text="Create Module" ResourceKey="CreateModule" Class="btn btn-secondary" />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<select class="form-select" @onchange="(e => CategoryChanged(e))">
|
||||||
|
@foreach (var category in _categories)
|
||||||
|
{
|
||||||
|
if (category == _category)
|
||||||
|
{
|
||||||
|
<option value="@category" selected>@category @Localizer["Modules"]</option>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<option value="@category">@category @Localizer["Modules"]</option>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Pager Items="@_moduleDefinitions.Where(item => item.Categories.Contains(_category))">
|
||||||
<Header>
|
<Header>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
|
@ -30,9 +51,9 @@ else
|
||||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.ModuleDefinitionId.ToString())" ResourceKey="EditModule" /></td>
|
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.ModuleDefinitionId.ToString())" ResourceKey="EditModule" /></td>
|
||||||
<td>
|
<td>
|
||||||
@if (context.AssemblyName != "Oqtane.Client")
|
@if (context.AssemblyName != "Oqtane.Client")
|
||||||
{
|
{
|
||||||
<ActionDialog Header="Delete Module" Message="@string.Format(Localizer["Confirm.Module.Delete", context.Name])" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await DeleteModule(context))" ResourceKey="DeleteModule" />
|
<ActionDialog Header="Delete Module" Message="@string.Format(Localizer["Confirm.Module.Delete", context.Name])" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await DeleteModule(context))" ResourceKey="DeleteModule" />
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
<td>@context.Name</td>
|
<td>@context.Name</td>
|
||||||
<td>@context.Version</td>
|
<td>@context.Version</td>
|
||||||
|
@ -65,6 +86,8 @@ else
|
||||||
@code {
|
@code {
|
||||||
private List<ModuleDefinition> _moduleDefinitions;
|
private List<ModuleDefinition> _moduleDefinitions;
|
||||||
private List<Package> _packages;
|
private List<Package> _packages;
|
||||||
|
private List<string> _categories = new List<string>();
|
||||||
|
private string _category = "Common";
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||||
|
|
||||||
|
@ -74,6 +97,7 @@ else
|
||||||
{
|
{
|
||||||
_moduleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
|
_moduleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
|
||||||
_packages = await PackageService.GetPackagesAsync("module");
|
_packages = await PackageService.GetPackagesAsync("module");
|
||||||
|
_categories = _moduleDefinitions.SelectMany(m => m.Categories.Split(',')).Distinct().ToList();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -115,38 +139,44 @@ else
|
||||||
{
|
{
|
||||||
return package.Version;
|
return package.Version;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DownloadModule(string packagename, string version)
|
private async Task DownloadModule(string packagename, string version)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await PackageService.DownloadPackageAsync(packagename, version, Constants.PackagesFolder);
|
await PackageService.DownloadPackageAsync(packagename, version, Constants.PackagesFolder);
|
||||||
await logger.LogInformation("Module Downloaded {ModuleDefinitionName} {Version}", packagename, version);
|
await logger.LogInformation("Module Downloaded {ModuleDefinitionName} {Version}", packagename, version);
|
||||||
await ModuleDefinitionService.InstallModuleDefinitionsAsync();
|
await ModuleDefinitionService.InstallModuleDefinitionsAsync();
|
||||||
AddModuleMessage(string.Format(Localizer["Success.Module.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
AddModuleMessage(string.Format(Localizer["Success.Module.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Downloading Module {ModuleDefinitionName} {Version} {Error}", packagename, version, ex.Message);
|
await logger.LogError(ex, "Error Downloading Module {ModuleDefinitionName} {Version} {Error}", packagename, version, ex.Message);
|
||||||
AddModuleMessage(Localizer["Error.Module.Download"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.Module.Download"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DeleteModule(ModuleDefinition moduleDefinition)
|
private async Task DeleteModule(ModuleDefinition moduleDefinition)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await ModuleDefinitionService.DeleteModuleDefinitionAsync(moduleDefinition.ModuleDefinitionId, moduleDefinition.SiteId);
|
await ModuleDefinitionService.DeleteModuleDefinitionAsync(moduleDefinition.ModuleDefinitionId, moduleDefinition.SiteId);
|
||||||
AddModuleMessage(Localizer["Success.Module.Delete"], MessageType.Success);
|
AddModuleMessage(Localizer["Success.Module.Delete"], MessageType.Success);
|
||||||
NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, true));
|
NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, true));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Deleting Module {ModuleDefinition} {Error}", moduleDefinition, ex.Message);
|
await logger.LogError(ex, "Error Deleting Module {ModuleDefinition} {Error}", moduleDefinition, ex.Message);
|
||||||
AddModuleMessage(Localizer["Error.Module.Delete"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.Module.Delete"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CategoryChanged(ChangeEventArgs e)
|
||||||
|
{
|
||||||
|
_category = (string)e.Value;
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,116 +90,117 @@
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||||
public override string Title => "Module Settings";
|
public override string Title => "Module Settings";
|
||||||
|
|
||||||
private ElementReference form;
|
private ElementReference form;
|
||||||
private bool validated = false;
|
private bool validated = false;
|
||||||
private List<Theme> _themes;
|
private List<Theme> _themes;
|
||||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||||
private string _title;
|
private string _title;
|
||||||
private string _containerType;
|
private string _containerType;
|
||||||
private string _allPages = "false";
|
private string _allPages = "false";
|
||||||
private string _permissionNames = "";
|
private string _permissionNames = "";
|
||||||
private string _permissions = null;
|
private string _permissions = null;
|
||||||
private string _pageId;
|
private string _pageId;
|
||||||
private PermissionGrid _permissionGrid;
|
private PermissionGrid _permissionGrid;
|
||||||
private Type _moduleSettingsType;
|
private Type _moduleSettingsType;
|
||||||
private object _moduleSettings;
|
private object _moduleSettings;
|
||||||
private string _moduleSettingsTitle = "Module Settings";
|
private string _moduleSettingsTitle = "Module Settings";
|
||||||
private RenderFragment ModuleSettingsComponent { get; set; }
|
private RenderFragment ModuleSettingsComponent { get; set; }
|
||||||
private Type _containerSettingsType;
|
private Type _containerSettingsType;
|
||||||
private object _containerSettings;
|
private object _containerSettings;
|
||||||
private RenderFragment ContainerSettingsComponent { get; set; }
|
private RenderFragment ContainerSettingsComponent { get; set; }
|
||||||
private string createdby;
|
private string createdby;
|
||||||
private DateTime createdon;
|
private DateTime createdon;
|
||||||
private string modifiedby;
|
private string modifiedby;
|
||||||
private DateTime modifiedon;
|
private DateTime modifiedon;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
_title = ModuleState.Title;
|
_title = ModuleState.Title;
|
||||||
_themes = await ThemeService.GetThemesAsync();
|
_themes = await ThemeService.GetThemesAsync();
|
||||||
_containers = ThemeService.GetContainerControls(_themes, PageState.Page.ThemeType);
|
_containers = ThemeService.GetContainerControls(_themes, PageState.Page.ThemeType);
|
||||||
_containerType = ModuleState.ContainerType;
|
_containerType = ModuleState.ContainerType;
|
||||||
_allPages = ModuleState.AllPages.ToString();
|
_allPages = ModuleState.AllPages.ToString();
|
||||||
_permissions = ModuleState.Permissions;
|
_permissions = ModuleState.Permissions;
|
||||||
_permissionNames = ModuleState.ModuleDefinition.PermissionNames;
|
_permissionNames = ModuleState.ModuleDefinition.PermissionNames;
|
||||||
_pageId = ModuleState.PageId.ToString();
|
_pageId = ModuleState.PageId.ToString();
|
||||||
createdby = ModuleState.CreatedBy;
|
createdby = ModuleState.CreatedBy;
|
||||||
createdon = ModuleState.CreatedOn;
|
createdon = ModuleState.CreatedOn;
|
||||||
modifiedby = ModuleState.ModifiedBy;
|
modifiedby = ModuleState.ModifiedBy;
|
||||||
modifiedon = ModuleState.ModifiedOn;
|
modifiedon = ModuleState.ModifiedOn;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(ModuleState.ModuleDefinition.SettingsType))
|
if (!string.IsNullOrEmpty(ModuleState.ModuleDefinition.SettingsType))
|
||||||
{
|
{
|
||||||
// module settings type explicitly declared in IModule interface
|
// module settings type explicitly declared in IModule interface
|
||||||
_moduleSettingsType = Type.GetType(ModuleState.ModuleDefinition.SettingsType);
|
_moduleSettingsType = Type.GetType(ModuleState.ModuleDefinition.SettingsType);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// legacy support - module settings type determined by convention ( ie. existence of a "Settings.razor" component in module )
|
// legacy support - module settings type determined by convention ( ie. existence of a "Settings.razor" component in module )
|
||||||
_moduleSettingsType = Type.GetType(ModuleState.ModuleDefinition.ControlTypeTemplate.Replace(Constants.ActionToken, PageState.Action), false, true);
|
_moduleSettingsType = Type.GetType(ModuleState.ModuleDefinition.ControlTypeTemplate.Replace(Constants.ActionToken, PageState.Action), false, true);
|
||||||
}
|
}
|
||||||
if (_moduleSettingsType != null)
|
if (_moduleSettingsType != null)
|
||||||
{
|
{
|
||||||
var moduleobject = Activator.CreateInstance(_moduleSettingsType) as IModuleControl;
|
var moduleobject = Activator.CreateInstance(_moduleSettingsType) as IModuleControl;
|
||||||
if (!string.IsNullOrEmpty(moduleobject.Title))
|
if (!string.IsNullOrEmpty(moduleobject.Title))
|
||||||
{
|
{
|
||||||
_moduleSettingsTitle = moduleobject.Title;
|
_moduleSettingsTitle = moduleobject.Title;
|
||||||
}
|
}
|
||||||
|
|
||||||
ModuleSettingsComponent = builder =>
|
ModuleSettingsComponent = builder =>
|
||||||
{
|
{
|
||||||
builder.OpenComponent(0, _moduleSettingsType);
|
builder.OpenComponent(0, _moduleSettingsType);
|
||||||
builder.AddComponentReferenceCapture(1, inst => { _moduleSettings = Convert.ChangeType(inst, _moduleSettingsType); });
|
builder.AddComponentReferenceCapture(1, inst => { _moduleSettings = Convert.ChangeType(inst, _moduleSettingsType); });
|
||||||
builder.CloseComponent();
|
builder.CloseComponent();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
var theme = _themes.FirstOrDefault(item => item.Containers.Any(themecontrol => themecontrol.TypeName.Equals(_containerType)));
|
var theme = _themes.FirstOrDefault(item => item.Containers.Any(themecontrol => themecontrol.TypeName.Equals(_containerType)));
|
||||||
if (theme != null && !string.IsNullOrEmpty(theme.ContainerSettingsType))
|
if (theme != null && !string.IsNullOrEmpty(theme.ContainerSettingsType))
|
||||||
{
|
{
|
||||||
_containerSettingsType = Type.GetType(theme.ContainerSettingsType);
|
_containerSettingsType = Type.GetType(theme.ContainerSettingsType);
|
||||||
if (_containerSettingsType != null)
|
if (_containerSettingsType != null)
|
||||||
{
|
{
|
||||||
ContainerSettingsComponent = builder =>
|
ContainerSettingsComponent = builder =>
|
||||||
{
|
{
|
||||||
builder.OpenComponent(0, _containerSettingsType);
|
builder.OpenComponent(0, _containerSettingsType);
|
||||||
builder.AddComponentReferenceCapture(1, inst => { _containerSettings = Convert.ChangeType(inst, _containerSettingsType); });
|
builder.AddComponentReferenceCapture(1, inst => { _containerSettings = Convert.ChangeType(inst, _containerSettingsType); });
|
||||||
builder.CloseComponent();
|
builder.CloseComponent();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SaveModule()
|
private async Task SaveModule()
|
||||||
{
|
{
|
||||||
validated = true;
|
validated = true;
|
||||||
var interop = new Interop(JSRuntime);
|
var interop = new Interop(JSRuntime);
|
||||||
if (await interop.FormValid(form))
|
if (await interop.FormValid(form))
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(_title))
|
if (!string.IsNullOrEmpty(_title))
|
||||||
{
|
{
|
||||||
var pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId);
|
var pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId);
|
||||||
pagemodule.PageId = int.Parse(_pageId);
|
pagemodule.PageId = int.Parse(_pageId);
|
||||||
pagemodule.Title = _title;
|
pagemodule.Title = _title;
|
||||||
pagemodule.ContainerType = (_containerType != "-") ? _containerType : string.Empty;
|
pagemodule.ContainerType = (_containerType != "-") ? _containerType : string.Empty;
|
||||||
if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Page.DefaultContainerType)
|
if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Page.DefaultContainerType)
|
||||||
{
|
{
|
||||||
pagemodule.ContainerType = string.Empty;
|
pagemodule.ContainerType = string.Empty;
|
||||||
}
|
}
|
||||||
if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Site.DefaultContainerType)
|
if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Site.DefaultContainerType)
|
||||||
{
|
{
|
||||||
pagemodule.ContainerType = string.Empty;
|
pagemodule.ContainerType = string.Empty;
|
||||||
}
|
}
|
||||||
await PageModuleService.UpdatePageModuleAsync(pagemodule);
|
await PageModuleService.UpdatePageModuleAsync(pagemodule);
|
||||||
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
|
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
|
||||||
|
|
||||||
var module = ModuleState;
|
var module = ModuleState;
|
||||||
module.AllPages = bool.Parse(_allPages);
|
module.AllPages = bool.Parse(_allPages);
|
||||||
module.Permissions = _permissionGrid.GetPermissions();
|
module.PageModuleId = ModuleState.PageModuleId;
|
||||||
await ModuleService.UpdateModuleAsync(module);
|
module.Permissions = _permissionGrid.GetPermissions();
|
||||||
|
await ModuleService.UpdateModuleAsync(module);
|
||||||
|
|
||||||
if (_moduleSettingsType != null)
|
if (_moduleSettingsType != null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -59,7 +59,7 @@ else
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
{
|
{
|
||||||
_roles = await RoleService.GetRolesAsync(PageState.Site.SiteId, true);
|
_roles = await RoleService.GetRolesAsync(PageState.Site.SiteId, true);
|
||||||
_roles = _roles.Where(item => item.Name != RoleNames.Everyone).ToList();
|
_roles.RemoveAll(item => item.Name == RoleNames.Everyone || item.Name == RoleNames.Unauthenticated);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -170,24 +170,54 @@
|
||||||
@if (_aliases != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
@if (_aliases != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
{
|
{
|
||||||
<Section Name="Aliases" Heading="Aliases" ResourceKey="Aliases">
|
<Section Name="Aliases" Heading="Aliases" ResourceKey="Aliases">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="alias" HelpText="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." ResourceKey="Aliases">Aliases: </Label>
|
<Label Class="col-sm-3" For="aliases" HelpText="The list of aliases for this site" ResourceKey="Aliases">Aliases: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<textarea id="alias" class="form-control" @bind="@_urls" rows="3" required></textarea>
|
<button type="button" class="btn btn-primary" @onclick="AddAlias">@SharedLocalizer["Add"]</button>
|
||||||
|
<Pager Items="@_aliases">
|
||||||
|
<Header>
|
||||||
|
<th style="width: 1px;"> </th>
|
||||||
|
<th style="width: 1px;"> </th>
|
||||||
|
<th>@Localizer["AliasName"]</th>
|
||||||
|
<th>@Localizer["AliasDefault"]</th>
|
||||||
|
</Header>
|
||||||
|
<Row>
|
||||||
|
@if (context.AliasId != _aliasid)
|
||||||
|
{
|
||||||
|
<td>
|
||||||
|
@if (_aliasid == -1)
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-primary" @onclick="@(() => EditAlias(context))">@SharedLocalizer["Edit"]</button>
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
@if (_aliasid == -1)
|
||||||
|
{
|
||||||
|
<ActionDialog Action="Delete" OnClick="@(async () => await DeleteAlias(context))" ResourceKey="DeleteModule" Class="btn btn-danger" Header="Delete Alias" Message="@string.Format(Localizer["Confirm.Alias.Delete", context.Name])" />
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
<td>@context.Name</td>
|
||||||
|
<td>@context.IsDefault</td>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<td><button type="button" class="btn btn-success" @onclick="@(async () => await SaveAlias())">@SharedLocalizer["Save"]</button></td>
|
||||||
|
<td><button type="button" class="btn btn-secondary" @onclick="@(async () => await CancelAlias())">@SharedLocalizer["Cancel"]</button></td>
|
||||||
|
<td>
|
||||||
|
<input id="aliasname" class="form-control" @bind="@_aliasname" />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<select id="defaultaias" class="form-select" @bind="@_defaultalias" required>
|
||||||
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
}
|
||||||
|
</Row>
|
||||||
|
</Pager>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="defaultalias" HelpText="The default alias for the site. Requests for non-default aliases will be redirected to the default alias." ResourceKey="DefaultAlias">Default Alias: </Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<select id="defaultalias" class="form-select" @bind="@_defaultalias" required>
|
|
||||||
@foreach (string name in _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(sValue => sValue.Trim()).ToArray())
|
|
||||||
{
|
|
||||||
<option value="@name">@name</option>
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
<Section Name="Hosting" Heading="Hosting Model" ResourceKey="Hosting">
|
<Section Name="Hosting" Heading="Hosting Model" ResourceKey="Hosting">
|
||||||
|
@ -253,8 +283,9 @@
|
||||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||||
private string _name = string.Empty;
|
private string _name = string.Empty;
|
||||||
private List<Alias> _aliases;
|
private List<Alias> _aliases;
|
||||||
private string _defaultalias = string.Empty;
|
private int _aliasid = -1;
|
||||||
private string _urls = string.Empty;
|
private string _aliasname;
|
||||||
|
private string _defaultalias;
|
||||||
private string _runtime = "";
|
private string _runtime = "";
|
||||||
private string _prerender = "";
|
private string _prerender = "";
|
||||||
private int _logofileid = -1;
|
private int _logofileid = -1;
|
||||||
|
@ -304,10 +335,7 @@
|
||||||
_prerender = site.RenderMode.Replace(_runtime, "");
|
_prerender = site.RenderMode.Replace(_runtime, "");
|
||||||
_isdeleted = site.IsDeleted.ToString();
|
_isdeleted = site.IsDeleted.ToString();
|
||||||
|
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
await GetAliases();
|
||||||
{
|
|
||||||
await GetAliases();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (site.LogoFileId != null)
|
if (site.LogoFileId != null)
|
||||||
{
|
{
|
||||||
|
@ -409,152 +437,92 @@
|
||||||
{
|
{
|
||||||
if (_name != string.Empty && _themetype != "-" && _containertype != "-")
|
if (_name != string.Empty && _themetype != "-" && _containertype != "-")
|
||||||
{
|
{
|
||||||
var unique = true;
|
var site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
if (site != null)
|
||||||
{
|
{
|
||||||
_urls = Regex.Replace(_urls, @"\r\n?|\n", ","); // convert line breaks to commas
|
bool refresh = false;
|
||||||
var aliases = await AliasService.GetAliasesAsync();
|
bool reload = false;
|
||||||
foreach (string name in _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(sValue => sValue.Trim()).ToArray())
|
|
||||||
|
site.Name = _name;
|
||||||
|
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
{
|
{
|
||||||
var alias = aliases.Where(item => item.Name == name).FirstOrDefault();
|
if (site.Runtime != _runtime || site.RenderMode != _runtime + _prerender)
|
||||||
if (alias != null && unique)
|
|
||||||
{
|
{
|
||||||
unique = (alias.TenantId == PageState.Site.TenantId && alias.SiteId == PageState.Site.SiteId);
|
site.Runtime = _runtime;
|
||||||
|
site.RenderMode = _runtime + _prerender;
|
||||||
|
reload = true; // needs to be reloaded on server
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (unique && string.IsNullOrEmpty(_defaultalias)) unique = false;
|
site.IsDeleted = (_isdeleted == null ? true : Boolean.Parse(_isdeleted));
|
||||||
}
|
|
||||||
|
|
||||||
if (unique)
|
site.LogoFileId = null;
|
||||||
{
|
var logofileid = _logofilemanager.GetFileId();
|
||||||
var site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
|
if (logofileid != -1)
|
||||||
if (site != null)
|
|
||||||
{
|
{
|
||||||
bool refresh = false;
|
site.LogoFileId = logofileid;
|
||||||
bool reload = false;
|
}
|
||||||
|
int? faviconFieldId = _faviconfilemanager.GetFileId();
|
||||||
site.Name = _name;
|
if (faviconFieldId == -1) faviconFieldId = null;
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
if (site.FaviconFileId != faviconFieldId)
|
||||||
{
|
{
|
||||||
if (site.Runtime != _runtime || site.RenderMode != _runtime + _prerender)
|
site.FaviconFileId = faviconFieldId;
|
||||||
{
|
reload = true; // needs to be reloaded on server
|
||||||
site.Runtime = _runtime;
|
}
|
||||||
site.RenderMode = _runtime + _prerender;
|
if (site.DefaultThemeType != _themetype)
|
||||||
reload = true; // needs to be reloaded on server
|
{
|
||||||
}
|
site.DefaultThemeType = _themetype;
|
||||||
}
|
refresh = true; // needs to be refreshed on client
|
||||||
site.IsDeleted = (_isdeleted == null ? true : Boolean.Parse(_isdeleted));
|
}
|
||||||
|
if (site.DefaultContainerType != _containertype)
|
||||||
site.LogoFileId = null;
|
{
|
||||||
var logofileid = _logofilemanager.GetFileId();
|
site.DefaultContainerType = _containertype;
|
||||||
if (logofileid != -1)
|
refresh = true; // needs to be refreshed on client
|
||||||
{
|
}
|
||||||
site.LogoFileId = logofileid;
|
site.AdminContainerType = _admincontainertype;
|
||||||
}
|
|
||||||
int? faviconFieldId = _faviconfilemanager.GetFileId();
|
if (site.PwaIsEnabled.ToString() != _pwaisenabled)
|
||||||
if (faviconFieldId == -1) faviconFieldId = null;
|
{
|
||||||
if (site.FaviconFileId != faviconFieldId)
|
site.PwaIsEnabled = Boolean.Parse(_pwaisenabled);
|
||||||
{
|
reload = true; // needs to be reloaded on server
|
||||||
site.FaviconFileId = faviconFieldId;
|
}
|
||||||
reload = true; // needs to be reloaded on server
|
int? pwaappiconfileid = _pwaappiconfilemanager.GetFileId();
|
||||||
}
|
if (pwaappiconfileid == -1) pwaappiconfileid = null;
|
||||||
if (site.DefaultThemeType != _themetype)
|
if (site.PwaAppIconFileId != pwaappiconfileid)
|
||||||
{
|
{
|
||||||
site.DefaultThemeType = _themetype;
|
site.PwaAppIconFileId = pwaappiconfileid;
|
||||||
refresh = true; // needs to be refreshed on client
|
reload = true; // needs to be reloaded on server
|
||||||
}
|
}
|
||||||
if (site.DefaultContainerType != _containertype)
|
int? pwasplashiconfileid = _pwasplashiconfilemanager.GetFileId();
|
||||||
{
|
if (pwasplashiconfileid == -1) pwasplashiconfileid = null;
|
||||||
site.DefaultContainerType = _containertype;
|
if (site.PwaSplashIconFileId != pwasplashiconfileid)
|
||||||
refresh = true; // needs to be refreshed on client
|
{
|
||||||
}
|
site.PwaSplashIconFileId = pwasplashiconfileid;
|
||||||
site.AdminContainerType = _admincontainertype;
|
reload = true; // needs to be reloaded on server
|
||||||
|
}
|
||||||
if (site.PwaIsEnabled.ToString() != _pwaisenabled)
|
|
||||||
{
|
site = await SiteService.UpdateSiteAsync(site);
|
||||||
site.PwaIsEnabled = Boolean.Parse(_pwaisenabled);
|
|
||||||
reload = true; // needs to be reloaded on server
|
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
||||||
}
|
settings = SettingService.SetSetting(settings, "SMTPHost", _smtphost, true);
|
||||||
int? pwaappiconfileid = _pwaappiconfilemanager.GetFileId();
|
settings = SettingService.SetSetting(settings, "SMTPPort", _smtpport, true);
|
||||||
if (pwaappiconfileid == -1) pwaappiconfileid = null;
|
settings = SettingService.SetSetting(settings, "SMTPSSL", _smtpssl, true);
|
||||||
if (site.PwaAppIconFileId != pwaappiconfileid)
|
settings = SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, true);
|
||||||
{
|
settings = SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, true);
|
||||||
site.PwaAppIconFileId = pwaappiconfileid;
|
settings = SettingService.SetSetting(settings, "SMTPSender", _smtpsender, true);
|
||||||
reload = true; // needs to be reloaded on server
|
settings = SettingService.SetSetting(settings, "NotificationRetention", _retention, true);
|
||||||
}
|
await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId);
|
||||||
int? pwasplashiconfileid = _pwasplashiconfilemanager.GetFileId();
|
|
||||||
if (pwasplashiconfileid == -1) pwasplashiconfileid = null;
|
await logger.LogInformation("Site Settings Saved {Site}", site);
|
||||||
if (site.PwaSplashIconFileId != pwasplashiconfileid)
|
|
||||||
{
|
if (refresh || reload)
|
||||||
site.PwaSplashIconFileId = pwasplashiconfileid;
|
{
|
||||||
reload = true; // needs to be reloaded on server
|
NavigationManager.NavigateTo(NavigateUrl(true), reload); // refresh/reload
|
||||||
}
|
}
|
||||||
|
else
|
||||||
site = await SiteService.UpdateSiteAsync(site);
|
{
|
||||||
|
AddModuleMessage(Localizer["Success.Settings.SaveSite"], MessageType.Success);
|
||||||
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
await interop.ScrollTo(0, 0, "smooth");
|
||||||
settings = SettingService.SetSetting(settings, "SMTPHost", _smtphost, true);
|
|
||||||
settings = SettingService.SetSetting(settings, "SMTPPort", _smtpport, true);
|
|
||||||
settings = SettingService.SetSetting(settings, "SMTPSSL", _smtpssl, true);
|
|
||||||
settings = SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, true);
|
|
||||||
settings = SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, true);
|
|
||||||
settings = SettingService.SetSetting(settings, "SMTPSender", _smtpsender, true);
|
|
||||||
settings = SettingService.SetSetting(settings, "NotificationRetention", _retention, true);
|
|
||||||
await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId);
|
|
||||||
|
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
|
||||||
{
|
|
||||||
var names = _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
|
||||||
.Select(sValue => sValue.Trim()).ToArray();
|
|
||||||
foreach (Alias alias in _aliases)
|
|
||||||
{
|
|
||||||
if (!names.Contains(alias.Name.Trim()))
|
|
||||||
{
|
|
||||||
await AliasService.DeleteAliasAsync(alias.AliasId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (string name in names)
|
|
||||||
{
|
|
||||||
var alias = _aliases.Find(item => item.Name.Trim() == name);
|
|
||||||
if (alias == null)
|
|
||||||
{
|
|
||||||
alias = new Alias();
|
|
||||||
alias.Name = name;
|
|
||||||
alias.TenantId = site.TenantId;
|
|
||||||
alias.SiteId = site.SiteId;
|
|
||||||
alias.IsDefault = (name == _defaultalias);
|
|
||||||
await AliasService.AddAliasAsync(alias);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (alias.Name != name || alias.IsDefault != (alias.Name.Trim() == _defaultalias))
|
|
||||||
{
|
|
||||||
alias.Name = name;
|
|
||||||
alias.IsDefault = (name == _defaultalias);
|
|
||||||
await AliasService.UpdateAliasAsync(alias);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await GetAliases();
|
|
||||||
}
|
|
||||||
|
|
||||||
await logger.LogInformation("Site Settings Saved {Site}", site);
|
|
||||||
|
|
||||||
if (refresh || reload)
|
|
||||||
{
|
|
||||||
NavigationManager.NavigateTo(NavigateUrl(true), reload); // refresh/reload
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AddModuleMessage(Localizer["Success.Settings.SaveSite"], MessageType.Success);
|
|
||||||
await interop.ScrollTo(0, 0, "smooth");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else // deuplicate alias or default alias not specified
|
|
||||||
{
|
|
||||||
AddModuleMessage(Localizer["Message.Aliases.Taken"], MessageType.Warning);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -578,19 +546,19 @@
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var sites = await SiteService.GetSitesAsync();
|
var aliases = await AliasService.GetAliasesAsync();
|
||||||
if (sites.Count > 1)
|
if (aliases.Any(item => item.SiteId != PageState.Site.SiteId || item.TenantId != PageState.Site.TenantId))
|
||||||
{
|
{
|
||||||
await SiteService.DeleteSiteAsync(PageState.Site.SiteId);
|
await SiteService.DeleteSiteAsync(PageState.Site.SiteId);
|
||||||
await logger.LogInformation("Site Deleted {SiteId}", PageState.Site.SiteId);
|
await logger.LogInformation("Site Deleted {SiteId}", PageState.Site.SiteId);
|
||||||
|
|
||||||
var aliases = await AliasService.GetAliasesAsync();
|
foreach (Alias alias in aliases.Where(item => item.SiteId == PageState.Site.SiteId && item.TenantId == PageState.Site.TenantId))
|
||||||
foreach (Alias a in aliases.Where(item => item.SiteId == PageState.Site.SiteId && item.TenantId == PageState.Site.TenantId))
|
|
||||||
{
|
{
|
||||||
await AliasService.DeleteAliasAsync(a.AliasId);
|
await AliasService.DeleteAliasAsync(alias.AliasId);
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationManager.NavigateTo(NavigateUrl("admin/sites"));
|
aliases = await AliasService.GetAliasesAsync();
|
||||||
|
NavigationManager.NavigateTo(PageState.Uri.Scheme + "://" + aliases.First().Name, true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -637,20 +605,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task GetAliases()
|
|
||||||
{
|
|
||||||
_urls = string.Empty;
|
|
||||||
_defaultalias = string.Empty;
|
|
||||||
_aliases = await AliasService.GetAliasesAsync();
|
|
||||||
_aliases = _aliases.Where(item => item.SiteId == PageState.Site.SiteId && item.TenantId == PageState.Site.TenantId).OrderBy(item => item.AliasId).ToList();
|
|
||||||
foreach (Alias alias in _aliases)
|
|
||||||
{
|
|
||||||
_urls += (_urls == string.Empty) ? alias.Name.Trim() : ", " + alias.Name.Trim();
|
|
||||||
if (alias.IsDefault && string.IsNullOrEmpty(_defaultalias)) _defaultalias = alias.Name.Trim();
|
|
||||||
}
|
|
||||||
if (string.IsNullOrEmpty(_defaultalias)) _defaultalias = _aliases.First().Name.Trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ToggleSMTPPassword()
|
private void ToggleSMTPPassword()
|
||||||
{
|
{
|
||||||
if (_smtppasswordtype == "password")
|
if (_smtppasswordtype == "password")
|
||||||
|
@ -664,4 +618,84 @@
|
||||||
_togglesmtppassword = SharedLocalizer["ShowPassword"];
|
_togglesmtppassword = SharedLocalizer["ShowPassword"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task GetAliases()
|
||||||
|
{
|
||||||
|
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
|
{
|
||||||
|
_aliases = await AliasService.GetAliasesAsync();
|
||||||
|
_aliases = _aliases.Where(item => item.SiteId == PageState.Site.SiteId && item.TenantId == PageState.Site.TenantId).OrderBy(item => item.AliasId).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddAlias()
|
||||||
|
{
|
||||||
|
_aliases.Add(new Alias { AliasId = 0, Name = "", IsDefault = false });
|
||||||
|
_aliasid = 0;
|
||||||
|
_aliasname = "";
|
||||||
|
_defaultalias = "False";
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EditAlias(Alias alias)
|
||||||
|
{
|
||||||
|
_aliasid = alias.AliasId;
|
||||||
|
_aliasname = alias.Name;
|
||||||
|
_defaultalias = alias.IsDefault.ToString();
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DeleteAlias(Alias alias)
|
||||||
|
{
|
||||||
|
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
|
{
|
||||||
|
await AliasService.DeleteAliasAsync(alias.AliasId);
|
||||||
|
await GetAliases();
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SaveAlias()
|
||||||
|
{
|
||||||
|
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(_aliasname))
|
||||||
|
{
|
||||||
|
var aliases = await AliasService.GetAliasesAsync();
|
||||||
|
var alias = aliases.Where(item => item.Name == _aliasname).FirstOrDefault();
|
||||||
|
bool unique = (alias == null || alias.AliasId == _aliasid);
|
||||||
|
if (unique)
|
||||||
|
{
|
||||||
|
if (_aliasid == 0)
|
||||||
|
{
|
||||||
|
alias = new Alias { SiteId = PageState.Site.SiteId, TenantId = PageState.Site.TenantId, Name = _aliasname, IsDefault = bool.Parse(_defaultalias) };
|
||||||
|
await AliasService.AddAliasAsync(alias);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
alias = _aliases.Single(item => item.AliasId == _aliasid);
|
||||||
|
alias.Name = _aliasname;
|
||||||
|
alias.IsDefault = bool.Parse(_defaultalias);
|
||||||
|
await AliasService.UpdateAliasAsync(alias);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // duplicate alias
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Message.Aliases.Taken"], MessageType.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await GetAliases();
|
||||||
|
_aliasid = -1;
|
||||||
|
_aliasname = "";
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CancelAlias()
|
||||||
|
{
|
||||||
|
await GetAliases();
|
||||||
|
_aliasid = -1;
|
||||||
|
_aliasname = "";
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,14 +131,7 @@ else
|
||||||
<select id="databaseType" class="form-select" value="@_databaseName" @onchange="(e => DatabaseChanged(e))" required>
|
<select id="databaseType" class="form-select" value="@_databaseName" @onchange="(e => DatabaseChanged(e))" required>
|
||||||
@foreach (var database in _databases)
|
@foreach (var database in _databases)
|
||||||
{
|
{
|
||||||
if (database.IsDefault)
|
<option value="@database.Name">@Localizer[@database.Name]</option>
|
||||||
{
|
|
||||||
<option value="@database.Name" selected>@Localizer[@database.Name]</option>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<option value="@database.Name">@Localizer[@database.Name]</option>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
@ -172,12 +165,11 @@ else
|
||||||
private List<Database> _databases;
|
private List<Database> _databases;
|
||||||
private ElementReference form;
|
private ElementReference form;
|
||||||
private bool validated = false;
|
private bool validated = false;
|
||||||
private string _databaseName = "LocalDB";
|
private string _databaseName;
|
||||||
private Type _databaseConfigType;
|
private Type _databaseConfigType;
|
||||||
private object _databaseConfig;
|
private object _databaseConfig;
|
||||||
private RenderFragment DatabaseConfigComponent { get; set; }
|
private RenderFragment DatabaseConfigComponent { get; set; }
|
||||||
|
|
||||||
|
|
||||||
private List<Theme> _themeList;
|
private List<Theme> _themeList;
|
||||||
private List<ThemeControl> _themes = new List<ThemeControl>();
|
private List<ThemeControl> _themes = new List<ThemeControl>();
|
||||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||||
|
@ -208,7 +200,16 @@ else
|
||||||
_themeList = await ThemeService.GetThemesAsync();
|
_themeList = await ThemeService.GetThemesAsync();
|
||||||
_themes = ThemeService.GetThemeControls(_themeList);
|
_themes = ThemeService.GetThemeControls(_themeList);
|
||||||
_siteTemplates = await SiteTemplateService.GetSiteTemplatesAsync();
|
_siteTemplates = await SiteTemplateService.GetSiteTemplatesAsync();
|
||||||
|
|
||||||
_databases = await DatabaseService.GetDatabasesAsync();
|
_databases = await DatabaseService.GetDatabasesAsync();
|
||||||
|
if (_databases.Exists(item => item.IsDefault))
|
||||||
|
{
|
||||||
|
_databaseName = _databases.Find(item => item.IsDefault).Name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_databaseName = "LocalDB";
|
||||||
|
}
|
||||||
LoadDatabaseConfigComponent();
|
LoadDatabaseConfigComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -142,6 +142,7 @@
|
||||||
<ActionDialog Header="Restart Application" Message="Are You Sure You Wish To Restart The Application?" Action="Restart Application" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await RestartApplication())" ResourceKey="RestartApplication" />
|
<ActionDialog Header="Restart Application" Message="Are You Sure You Wish To Restart The Application?" Action="Restart Application" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await RestartApplication())" ResourceKey="RestartApplication" />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
</TabStrip>
|
</TabStrip>
|
||||||
|
<br /><br />
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
<strong>@(String.Format("{0:n0}", context.Downloads))</strong> @SharedLocalizer["Search.Downloads"] |
|
<strong>@(String.Format("{0:n0}", context.Downloads))</strong> @SharedLocalizer["Search.Downloads"] |
|
||||||
@SharedLocalizer["Search.Released"]: <strong>@context.ReleaseDate.ToString("MMM dd, yyyy")</strong> |
|
@SharedLocalizer["Search.Released"]: <strong>@context.ReleaseDate.ToString("MMM dd, yyyy")</strong> |
|
||||||
@SharedLocalizer["Search.Version"]: <strong>@context.Version</strong>
|
@SharedLocalizer["Search.Version"]: <strong>@context.Version</strong>
|
||||||
|
@((MarkupString)(!string.IsNullOrEmpty(context.PackageUrl) ? " | " + SharedLocalizer["Search.Source"] + ": <strong>" + new Uri(context.PackageUrl).Host + "</strong>" : ""))
|
||||||
@((MarkupString)(context.TrialPeriod > 0 ? " | <strong>" + context.TrialPeriod + " " + @SharedLocalizer["Trial"] + "</strong>" : ""))
|
@((MarkupString)(context.TrialPeriod > 0 ? " | <strong>" + context.TrialPeriod + " " + @SharedLocalizer["Trial"] + "</strong>" : ""))
|
||||||
</td>
|
</td>
|
||||||
<td style="width: 1px; vertical-align: middle;">
|
<td style="width: 1px; vertical-align: middle;">
|
||||||
|
|
|
@ -88,15 +88,17 @@ else
|
||||||
userid = Int32.Parse(PageState.QueryString["id"]);
|
userid = Int32.Parse(PageState.QueryString["id"]);
|
||||||
User user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
|
User user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
|
||||||
name = user.DisplayName;
|
name = user.DisplayName;
|
||||||
|
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
{
|
{
|
||||||
roles = await RoleService.GetRolesAsync(PageState.Site.SiteId, true);
|
roles = await RoleService.GetRolesAsync(PageState.Site.SiteId, true);
|
||||||
roles = roles.Where(item => item.Name != RoleNames.Everyone).ToList();
|
roles.RemoveAll(item => item.Name == RoleNames.Everyone || item.Name == RoleNames.Unauthenticated);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
roles = await RoleService.GetRolesAsync(PageState.Site.SiteId);
|
roles = await RoleService.GetRolesAsync(PageState.Site.SiteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
await GetUserRoles();
|
await GetUserRoles();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
|
@ -86,279 +86,296 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private string _id;
|
private string _id;
|
||||||
private List<Folder> _folders;
|
private List<Folder> _folders;
|
||||||
private List<File> _files = new List<File>();
|
private List<File> _files = new List<File>();
|
||||||
private string _fileinputid = string.Empty;
|
private string _fileinputid = string.Empty;
|
||||||
private string _progressinfoid = string.Empty;
|
private string _progressinfoid = string.Empty;
|
||||||
private string _progressbarid = string.Empty;
|
private string _progressbarid = string.Empty;
|
||||||
private string _filter = "*";
|
private string _filter = "*";
|
||||||
private bool _haseditpermission = false;
|
private bool _haseditpermission = false;
|
||||||
private string _image = string.Empty;
|
private string _image = string.Empty;
|
||||||
private File _file = null;
|
private File _file = null;
|
||||||
private string _guid;
|
private string _guid;
|
||||||
private string _message = string.Empty;
|
private string _message = string.Empty;
|
||||||
private MessageType _messagetype;
|
private MessageType _messagetype;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Id { get; set; } // optional - for setting the id of the FileManager component for accessibility
|
public string Id { get; set; } // optional - for setting the id of the FileManager component for accessibility
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public int FolderId { get; set; } = -1; // optional - for setting a specific default folder by folderid
|
public int FolderId { get; set; } = -1; // optional - for setting a specific default folder by folderid
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Folder { get; set; } = ""; // optional - for setting a specific default folder by folder path
|
public string Folder { get; set; } = ""; // optional - for setting a specific default folder by folder path
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public int FileId { get; set; } = -1; // optional - for selecting a specific file by default
|
public int FileId { get; set; } = -1; // optional - for selecting a specific file by default
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Filter { get; set; } // optional - comma delimited list of file types that can be selected or uploaded ie. "jpg,gif"
|
public string Filter { get; set; } // optional - comma delimited list of file types that can be selected or uploaded ie. "jpg,gif"
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool ShowFiles { get; set; } = true; // optional - for indicating whether a list of files should be displayed - default is true
|
public bool ShowFiles { get; set; } = true; // optional - for indicating whether a list of files should be displayed - default is true
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool ShowUpload { get; set; } = true; // optional - for indicating whether a Upload controls should be displayed - default is true
|
public bool ShowUpload { get; set; } = true; // optional - for indicating whether a Upload controls should be displayed - default is true
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool ShowFolders { get; set; } = true; // optional - for indicating whether a list of folders should be displayed - default is true
|
public bool ShowFolders { get; set; } = true; // optional - for indicating whether a list of folders should be displayed - default is true
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool ShowImage { get; set; } = true; // optional - for indicating whether an image thumbnail should be displayed - default is true
|
public bool ShowImage { get; set; } = true; // optional - for indicating whether an image thumbnail should be displayed - default is true
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool ShowSuccess { get; set; } = false; // optional - for indicating whether a success message should be displayed upon successful upload - default is false
|
public bool ShowSuccess { get; set; } = false; // optional - for indicating whether a success message should be displayed upon successful upload - default is false
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool UploadMultiple { get; set; } = false; // optional - enable multiple file uploads - default false
|
public bool UploadMultiple { get; set; } = false; // optional - enable multiple file uploads - default false
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public EventCallback<int> OnUpload { get; set; } // optional - executes a method in the calling component when a file is uploaded
|
public EventCallback<int> OnUpload { get; set; } // optional - executes a method in the calling component when a file is uploaded
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public EventCallback<int> OnSelect { get; set; } // optional - executes a method in the calling component when a file is selected
|
public EventCallback<int> OnSelect { get; set; } // optional - executes a method in the calling component when a file is selected
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public EventCallback<int> OnDelete { get; set; } // optional - executes a method in the calling component when a file is deleted
|
public EventCallback<int> OnDelete { get; set; } // optional - executes a method in the calling component when a file is deleted
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(Id))
|
if (!string.IsNullOrEmpty(Id))
|
||||||
{
|
{
|
||||||
_id = Id;
|
_id = Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// packages folder is a framework folder for uploading installable nuget packages
|
// packages folder is a framework folder for uploading installable nuget packages
|
||||||
if (Folder == Constants.PackagesFolder)
|
if (Folder == Constants.PackagesFolder)
|
||||||
{
|
{
|
||||||
ShowFiles = false;
|
ShowFiles = false;
|
||||||
ShowFolders = false;
|
ShowFolders = false;
|
||||||
Filter = "nupkg";
|
Filter = "nupkg";
|
||||||
ShowSuccess = true;
|
ShowSuccess = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ShowFiles)
|
if (!ShowFiles)
|
||||||
{
|
{
|
||||||
ShowImage = false;
|
ShowImage = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_folders = await FolderService.GetFoldersAsync(ModuleState.SiteId);
|
_folders = await FolderService.GetFoldersAsync(ModuleState.SiteId);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Folder) && Folder != Constants.PackagesFolder)
|
if (!string.IsNullOrEmpty(Folder) && Folder != Constants.PackagesFolder)
|
||||||
{
|
{
|
||||||
Folder folder = await FolderService.GetFolderAsync(ModuleState.SiteId, Folder);
|
Folder folder = await FolderService.GetFolderAsync(ModuleState.SiteId, Folder);
|
||||||
if (folder != null)
|
if (folder != null)
|
||||||
{
|
{
|
||||||
FolderId = folder.FolderId;
|
FolderId = folder.FolderId;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FolderId = -1;
|
FolderId = -1;
|
||||||
_message = "Folder Path " + Folder + "Does Not Exist";
|
_message = "Folder Path " + Folder + "Does Not Exist";
|
||||||
_messagetype = MessageType.Error;
|
_messagetype = MessageType.Error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FileId != -1)
|
if (FileId != -1)
|
||||||
{
|
{
|
||||||
File file = await FileService.GetFileAsync(FileId);
|
File file = await FileService.GetFileAsync(FileId);
|
||||||
if (file != null)
|
if (file != null)
|
||||||
{
|
{
|
||||||
FolderId = file.FolderId;
|
FolderId = file.FolderId;
|
||||||
await OnSelect.InvokeAsync(FileId);
|
await OnSelect.InvokeAsync(FileId);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FileId = -1; // file does not exist
|
FileId = -1; // file does not exist
|
||||||
_message = "FileId " + FileId.ToString() + "Does Not Exist";
|
_message = "FileId " + FileId.ToString() + "Does Not Exist";
|
||||||
_messagetype = MessageType.Error;
|
_messagetype = MessageType.Error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await SetImage();
|
await SetImage();
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Filter))
|
if (!string.IsNullOrEmpty(Filter))
|
||||||
{
|
{
|
||||||
_filter = "." + Filter.Replace(",", ",.");
|
_filter = "." + Filter.Replace(",", ",.");
|
||||||
}
|
}
|
||||||
|
|
||||||
await GetFiles();
|
await GetFiles();
|
||||||
|
|
||||||
// create unique id for component
|
// create unique id for component
|
||||||
_guid = Guid.NewGuid().ToString("N");
|
_guid = Guid.NewGuid().ToString("N");
|
||||||
_fileinputid = _guid + "FileInput";
|
_fileinputid = _guid + "FileInput";
|
||||||
_progressinfoid = _guid + "ProgressInfo";
|
_progressinfoid = _guid + "ProgressInfo";
|
||||||
_progressbarid = _guid + "ProgressBar";
|
_progressbarid = _guid + "ProgressBar";
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task GetFiles()
|
private async Task GetFiles()
|
||||||
{
|
{
|
||||||
_haseditpermission = false;
|
_haseditpermission = false;
|
||||||
if (Folder == Constants.PackagesFolder)
|
if (Folder == Constants.PackagesFolder)
|
||||||
{
|
{
|
||||||
_haseditpermission = UserSecurity.IsAuthorized(PageState.User, RoleNames.Host);
|
_haseditpermission = UserSecurity.IsAuthorized(PageState.User, RoleNames.Host);
|
||||||
_files = new List<File>();
|
_files = new List<File>();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Folder folder = _folders.FirstOrDefault(item => item.FolderId == FolderId);
|
Folder folder = _folders.FirstOrDefault(item => item.FolderId == FolderId);
|
||||||
if (folder != null)
|
if (folder != null)
|
||||||
{
|
{
|
||||||
_haseditpermission = UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, folder.Permissions);
|
_haseditpermission = UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, folder.Permissions);
|
||||||
_files = await FileService.GetFilesAsync(FolderId);
|
_files = await FileService.GetFilesAsync(FolderId);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_haseditpermission = false;
|
_haseditpermission = false;
|
||||||
_files = new List<File>();
|
_files = new List<File>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_filter != "*")
|
if (_filter != "*")
|
||||||
{
|
{
|
||||||
List<File> filtered = new List<File>();
|
List<File> filtered = new List<File>();
|
||||||
foreach (File file in _files)
|
foreach (File file in _files)
|
||||||
{
|
{
|
||||||
if (_filter.ToUpper().IndexOf("." + file.Extension.ToUpper()) != -1)
|
if (_filter.ToUpper().IndexOf("." + file.Extension.ToUpper()) != -1)
|
||||||
{
|
{
|
||||||
filtered.Add(file);
|
filtered.Add(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_files = filtered;
|
_files = filtered;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task FolderChanged(ChangeEventArgs e)
|
private async Task FolderChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
_message = string.Empty;
|
_message = string.Empty;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
FolderId = int.Parse((string)e.Value);
|
FolderId = int.Parse((string)e.Value);
|
||||||
await GetFiles();
|
await GetFiles();
|
||||||
FileId = -1;
|
FileId = -1;
|
||||||
_file = null;
|
_file = null;
|
||||||
_image = string.Empty;
|
_image = string.Empty;
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Loading Files {Error}", ex.Message);
|
await logger.LogError(ex, "Error Loading Files {Error}", ex.Message);
|
||||||
_message = Localizer["Error.File.Load"];
|
_message = Localizer["Error.File.Load"];
|
||||||
_messagetype = MessageType.Error;
|
_messagetype = MessageType.Error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task FileChanged(ChangeEventArgs e)
|
private async Task FileChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
_message = string.Empty;
|
_message = string.Empty;
|
||||||
FileId = int.Parse((string)e.Value);
|
FileId = int.Parse((string)e.Value);
|
||||||
if (FileId != -1)
|
if (FileId != -1)
|
||||||
{
|
{
|
||||||
await OnSelect.InvokeAsync(FileId);
|
await OnSelect.InvokeAsync(FileId);
|
||||||
}
|
}
|
||||||
|
|
||||||
await SetImage();
|
await SetImage();
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SetImage()
|
private async Task SetImage()
|
||||||
{
|
{
|
||||||
_image = string.Empty;
|
_image = string.Empty;
|
||||||
_file = null;
|
_file = null;
|
||||||
if (FileId != -1)
|
if (FileId != -1)
|
||||||
{
|
{
|
||||||
_file = await FileService.GetFileAsync(FileId);
|
_file = await FileService.GetFileAsync(FileId);
|
||||||
if (_file != null && ShowImage && _file.ImageHeight != 0 && _file.ImageWidth != 0)
|
if (_file != null && ShowImage && _file.ImageHeight != 0 && _file.ImageWidth != 0)
|
||||||
{
|
{
|
||||||
var maxwidth = 200;
|
var maxwidth = 200;
|
||||||
var maxheight = 200;
|
var maxheight = 200;
|
||||||
|
|
||||||
var ratioX = (double)maxwidth / (double)_file.ImageWidth;
|
var ratioX = (double)maxwidth / (double)_file.ImageWidth;
|
||||||
var ratioY = (double)maxheight / (double)_file.ImageHeight;
|
var ratioY = (double)maxheight / (double)_file.ImageHeight;
|
||||||
var ratio = ratioX < ratioY ? ratioX : ratioY;
|
var ratio = ratioX < ratioY ? ratioX : ratioY;
|
||||||
|
|
||||||
_image = "<img src=\"" + _file.Url + "\" alt=\"" + _file.Name +
|
_image = "<img src=\"" + _file.Url + "\" alt=\"" + _file.Name +
|
||||||
"\" width=\"" + Convert.ToInt32(_file.ImageWidth * ratio).ToString() +
|
"\" width=\"" + Convert.ToInt32(_file.ImageWidth * ratio).ToString() +
|
||||||
"\" height=\"" + Convert.ToInt32(_file.ImageHeight * ratio).ToString() + "\" />";
|
"\" height=\"" + Convert.ToInt32(_file.ImageHeight * ratio).ToString() + "\" />";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UploadFile()
|
private async Task UploadFile()
|
||||||
{
|
{
|
||||||
_message = string.Empty;
|
_message = string.Empty;
|
||||||
var interop = new Interop(JSRuntime);
|
var interop = new Interop(JSRuntime);
|
||||||
var upload = await interop.GetFiles(_fileinputid);
|
var upload = await interop.GetFiles(_fileinputid);
|
||||||
if (upload.Length > 0)
|
if (upload.Length > 0)
|
||||||
{
|
{
|
||||||
try
|
string restricted = "";
|
||||||
{
|
foreach (var file in upload)
|
||||||
string result;
|
{
|
||||||
if (Folder == Constants.PackagesFolder)
|
var extension = (file.LastIndexOf(".") != -1) ? file.Substring(file.LastIndexOf(".") + 1) : "";
|
||||||
{
|
if (!Constants.UploadableFiles.Split(',').Contains(extension.ToLower()))
|
||||||
result = await FileService.UploadFilesAsync(Folder, upload, _guid);
|
{
|
||||||
}
|
restricted += (restricted == "" ? "" : ",") + extension;
|
||||||
else
|
}
|
||||||
{
|
}
|
||||||
result = await FileService.UploadFilesAsync(FolderId, upload, _guid);
|
if (restricted == "")
|
||||||
}
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string result;
|
||||||
|
if (Folder == Constants.PackagesFolder)
|
||||||
|
{
|
||||||
|
result = await FileService.UploadFilesAsync(Folder, upload, _guid);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = await FileService.UploadFilesAsync(FolderId, upload, _guid);
|
||||||
|
}
|
||||||
|
|
||||||
if (result == string.Empty)
|
if (result == string.Empty)
|
||||||
{
|
{
|
||||||
await logger.LogInformation("File Upload Succeeded {Files}", upload);
|
await logger.LogInformation("File Upload Succeeded {Files}", upload);
|
||||||
if (ShowSuccess)
|
if (ShowSuccess)
|
||||||
{
|
{
|
||||||
_message = Localizer["Success.File.Upload"];
|
_message = Localizer["Success.File.Upload"];
|
||||||
_messagetype = MessageType.Success;
|
_messagetype = MessageType.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set FileId to first file in upload collection
|
// set FileId to first file in upload collection
|
||||||
await GetFiles();
|
await GetFiles();
|
||||||
var file = _files.Where(item => item.Name == upload[0]).FirstOrDefault();
|
var file = _files.Where(item => item.Name == upload[0]).FirstOrDefault();
|
||||||
if (file != null)
|
if (file != null)
|
||||||
{
|
{
|
||||||
FileId = file.FileId;
|
FileId = file.FileId;
|
||||||
await SetImage();
|
await SetImage();
|
||||||
await OnUpload.InvokeAsync(FileId);
|
await OnUpload.InvokeAsync(FileId);
|
||||||
}
|
}
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await logger.LogError("File Upload Failed For {Files}", result.Replace(",", ", "));
|
await logger.LogError("File Upload Failed For {Files}", result.Replace(",", ", "));
|
||||||
|
|
||||||
_message = Localizer["Error.File.Upload"];
|
_message = Localizer["Error.File.Upload"];
|
||||||
_messagetype = MessageType.Error;
|
_messagetype = MessageType.Error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "File Upload Failed {Error}", ex.Message);
|
await logger.LogError(ex, "File Upload Failed {Error}", ex.Message);
|
||||||
|
|
||||||
_message = Localizer["Error.File.Upload"];
|
_message = Localizer["Error.File.Upload"];
|
||||||
_messagetype = MessageType.Error;
|
_messagetype = MessageType.Error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_message = string.Format(Localizer["Message.File.Restricted"], restricted);
|
||||||
|
_messagetype = MessageType.Warning;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_message = Localizer["Message.File.NotSelected"];
|
_message = Localizer["Message.File.NotSelected"];
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.Localization;
|
using Microsoft.Extensions.Localization;
|
||||||
using Oqtane.Shared;
|
|
||||||
|
|
||||||
namespace Oqtane.Modules.Controls
|
namespace Oqtane.Modules.Controls
|
||||||
{
|
{
|
||||||
public class LocalizableComponent : ModuleControlBase
|
public class LocalizableComponent : ModuleControlBase
|
||||||
{
|
{
|
||||||
|
[Inject] public IStringLocalizerFactory LocalizerFactory { get; set; }
|
||||||
|
|
||||||
private IStringLocalizer _localizer;
|
private IStringLocalizer _localizer;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
|
@ -30,22 +30,15 @@ namespace Oqtane.Modules.Controls
|
||||||
var key = $"{ResourceKey}.{propertyName}";
|
var key = $"{ResourceKey}.{propertyName}";
|
||||||
var value = Localize(key);
|
var value = Localize(key);
|
||||||
|
|
||||||
if (value == key)
|
if (value == key || value == String.Empty)
|
||||||
{
|
{
|
||||||
// Returns default property value (English version) instead of ResourceKey.PropertyName
|
// return default property value if key does not exist in resource file or value is empty
|
||||||
return propertyValue;
|
return propertyValue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (value == String.Empty)
|
// return localized value
|
||||||
{
|
return value;
|
||||||
// Returns default property value (English version)
|
|
||||||
return propertyValue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,24 +46,15 @@ namespace Oqtane.Modules.Controls
|
||||||
{
|
{
|
||||||
IsLocalizable = false;
|
IsLocalizable = false;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(ResourceType))
|
if (String.IsNullOrEmpty(ResourceType))
|
||||||
{
|
{
|
||||||
ResourceType = ModuleState?.ModuleType;
|
ResourceType = ModuleState?.ModuleType;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!String.IsNullOrEmpty(ResourceKey) && !string.IsNullOrEmpty(ResourceType))
|
if (!String.IsNullOrEmpty(ResourceKey) && !String.IsNullOrEmpty(ResourceType))
|
||||||
{
|
{
|
||||||
var moduleType = Type.GetType(ResourceType);
|
_localizer = LocalizerFactory.Create(ResourceType);
|
||||||
if (moduleType != null)
|
IsLocalizable = true;
|
||||||
{
|
|
||||||
using (var scope = ServiceActivator.GetScope())
|
|
||||||
{
|
|
||||||
var localizerFactory = scope.ServiceProvider.GetService<IStringLocalizerFactory>();
|
|
||||||
_localizer = localizerFactory.Create(moduleType);
|
|
||||||
|
|
||||||
IsLocalizable = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
@namespace Oqtane.Modules.Controls
|
@namespace Oqtane.Modules.Controls
|
||||||
@inherits ModuleControlBase
|
@inherits ModuleControlBase
|
||||||
|
@inject IStringLocalizerFactory LocalizerFactory
|
||||||
@typeparam TableItem
|
@typeparam TableItem
|
||||||
|
|
||||||
@if (ItemList != null)
|
@if (ItemList != null)
|
||||||
|
@ -48,7 +49,7 @@
|
||||||
<a class="page-link" @onclick=@(async () => UpdateList(_pages))><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
|
<a class="page-link" @onclick=@(async () => UpdateList(_pages))><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
<li class="page-item disabled">
|
<li class="page-item disabled">
|
||||||
<a class="page-link" style="white-space: nowrap;">Page @_page of @_pages</a>
|
<a class="page-link" style="white-space: nowrap;">@Localizer["PageOfPages", _page, _pages]</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
}
|
}
|
||||||
|
@ -156,67 +157,73 @@
|
||||||
<a class="page-link" @onclick=@(async () => UpdateList(_pages))><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
|
<a class="page-link" @onclick=@(async () => UpdateList(_pages))><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
<li class="page-item disabled">
|
<li class="page-item disabled">
|
||||||
<a class="page-link" style="white-space: nowrap;">Page @_page of @_pages</a>
|
<a class="page-link" style="white-space: nowrap;">@Localizer["PageOfPages", _page, _pages]</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private int _pages = 0;
|
private IStringLocalizer Localizer;
|
||||||
private int _page = 1;
|
private int _pages = 0;
|
||||||
private int _maxItems = 10;
|
private int _page = 1;
|
||||||
private int _displayPages = 5;
|
private int _maxItems = 10;
|
||||||
private int _startPage = 0;
|
private int _displayPages = 5;
|
||||||
private int _endPage = 0;
|
private int _startPage = 0;
|
||||||
private int _columns = 0;
|
private int _endPage = 0;
|
||||||
|
private int _columns = 0;
|
||||||
[Parameter]
|
|
||||||
public string Format { get; set; } // Table or Grid
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public string Toolbar { get; set; } // Top, Bottom or Both
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public RenderFragment Header { get; set; } = null; // only applicable to Table layouts
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public RenderFragment<TableItem> Row { get; set; } = null; // required
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public RenderFragment<TableItem> Detail { get; set; } = null; // only applicable to Table layouts
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public IEnumerable<TableItem> Items { get; set; } // the IEnumerable data source
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public string PageSize { get; set; } // number of items to display on a page
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public string Columns { get; set; } // only applicable to Grid layouts - default is zero indicating use responsive behavior
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public string CurrentPage { get; set; } // sets the initial page to display
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public string DisplayPages { get; set; } // maximum number of page numbers to display for user selection
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public string Class { get; set; } // class for the containing element - ie. <table> for Table or <div> for Grid
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public string RowClass { get; set; } // class for row element - ie. <tr> for Table or <div> for Grid
|
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string ColumnClass { get; set; } // class for column element - only applicable to Grid format
|
public string Format { get; set; } // Table or Grid
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public Action<int> OnPageChange { get; set; } // a method to be executed in the calling component when the page changes
|
public string Toolbar { get; set; } // Top, Bottom or Both
|
||||||
|
|
||||||
private IEnumerable<TableItem> ItemList { get; set; }
|
[Parameter]
|
||||||
|
public RenderFragment Header { get; set; } = null; // only applicable to Table layouts
|
||||||
|
|
||||||
protected override void OnParametersSet()
|
[Parameter]
|
||||||
{
|
public RenderFragment<TableItem> Row { get; set; } = null; // required
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public RenderFragment<TableItem> Detail { get; set; } = null; // only applicable to Table layouts
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public IEnumerable<TableItem> Items { get; set; } // the IEnumerable data source
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string PageSize { get; set; } // number of items to display on a page
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string Columns { get; set; } // only applicable to Grid layouts - default is zero indicating use responsive behavior
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string CurrentPage { get; set; } // sets the initial page to display
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string DisplayPages { get; set; } // maximum number of page numbers to display for user selection
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string Class { get; set; } // class for the containing element - ie. <table> for Table or <div> for Grid
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string RowClass { get; set; } // class for row element - ie. <tr> for Table or <div> for Grid
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string ColumnClass { get; set; } // class for column element - only applicable to Grid format
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public Action<int> OnPageChange { get; set; } // a method to be executed in the calling component when the page changes
|
||||||
|
|
||||||
|
private IEnumerable<TableItem> ItemList { get; set; }
|
||||||
|
|
||||||
|
protected override void OnInitialized()
|
||||||
|
{
|
||||||
|
Localizer = LocalizerFactory.Create(GetType().FullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnParametersSet()
|
||||||
|
{
|
||||||
if (string.IsNullOrEmpty(Format))
|
if (string.IsNullOrEmpty(Format))
|
||||||
{
|
{
|
||||||
Format = "Table";
|
Format = "Table";
|
||||||
|
|
|
@ -127,11 +127,10 @@
|
||||||
_permissionnames = PermissionNames;
|
_permissionnames = PermissionNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
_roles = await RoleService.GetRolesAsync(ModuleState.SiteId);
|
_roles = await RoleService.GetRolesAsync(ModuleState.SiteId, true);
|
||||||
_roles.Insert(0, new Role { Name = RoleNames.Everyone });
|
if (!UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
|
||||||
{
|
{
|
||||||
_roles.Add(new Role { Name = RoleNames.Host });
|
_roles.RemoveAll(item => item.Name == RoleNames.Host);
|
||||||
}
|
}
|
||||||
|
|
||||||
_permissions = new List<PermissionString>();
|
_permissions = new List<PermissionString>();
|
||||||
|
@ -254,6 +253,7 @@
|
||||||
permission = _permissions[i];
|
permission = _permissions[i];
|
||||||
List<string> ids = permission.Permissions.Split(';', StringSplitOptions.RemoveEmptyEntries).ToList();
|
List<string> ids = permission.Permissions.Split(';', StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||||
ids.Remove("!" + RoleNames.Everyone); // remove deny all users
|
ids.Remove("!" + RoleNames.Everyone); // remove deny all users
|
||||||
|
ids.Remove("!" + RoleNames.Unauthenticated); // remove deny unauthenticated
|
||||||
ids.Remove("!" + RoleNames.Registered); // remove deny registered users
|
ids.Remove("!" + RoleNames.Registered); // remove deny registered users
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
{
|
{
|
||||||
|
|
|
@ -150,10 +150,6 @@
|
||||||
// preserve a copy of the rich text content (Quill sanitizes content so we need to retrieve it from the editor)
|
// preserve a copy of the rich text content (Quill sanitizes content so we need to retrieve it from the editor)
|
||||||
_originalrichhtml = await interop.GetHtml(_editorElement);
|
_originalrichhtml = await interop.GetHtml(_editorElement);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
await interop.LoadEditorContent(_editorElement, _richhtml);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CloseFileManager()
|
public void CloseFileManager()
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<RazorLangVersion>3.0</RazorLangVersion>
|
<RazorLangVersion>3.0</RazorLangVersion>
|
||||||
<Configurations>Debug;Release</Configurations>
|
<Configurations>Debug;Release</Configurations>
|
||||||
<Version>3.1.2</Version>
|
<Version>3.1.3</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
|
@ -13,7 +13,7 @@
|
||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.2</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.3</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<RootNamespace>Oqtane</RootNamespace>
|
<RootNamespace>Oqtane</RootNamespace>
|
||||||
|
|
|
@ -150,4 +150,7 @@
|
||||||
<data name="EditModule.Text" xml:space="preserve">
|
<data name="EditModule.Text" xml:space="preserve">
|
||||||
<value>Edit</value>
|
<value>Edit</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Modules" xml:space="preserve">
|
||||||
|
<value>Modules</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -142,7 +142,7 @@
|
||||||
<value>Site Settings Saved</value>
|
<value>Site Settings Saved</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Message.Aliases.Taken" xml:space="preserve">
|
<data name="Message.Aliases.Taken" xml:space="preserve">
|
||||||
<value>The Default Alias Has Not Been Specified Or An Alias Was Specified That Has Already Been Used For Another Site</value>
|
<value>An Alias Was Specified That Has Already Been Used For Another Site</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Message.Required.SiteName" xml:space="preserve">
|
<data name="Message.Required.SiteName" xml:space="preserve">
|
||||||
<value>You Must Provide A Site Name, Alias, And Default Theme/Container</value>
|
<value>You Must Provide A Site Name, Alias, And Default Theme/Container</value>
|
||||||
|
@ -324,4 +324,13 @@
|
||||||
<data name="Aliases.Heading" xml:space="preserve">
|
<data name="Aliases.Heading" xml:space="preserve">
|
||||||
<value>Aliases</value>
|
<value>Aliases</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="AliasName" xml:space="preserve">
|
||||||
|
<value>Name</value>
|
||||||
|
</data>
|
||||||
|
<data name="AliasDefault" xml:space="preserve">
|
||||||
|
<value>Default?</value>
|
||||||
|
</data>
|
||||||
|
<data name="Confirm.Alias.Delete" xml:space="preserve">
|
||||||
|
<value>Are You Sure You Wish To Delete {0}?</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -219,4 +219,10 @@
|
||||||
<data name="DeleteAllNotifications.Text" xml:space="preserve">
|
<data name="DeleteAllNotifications.Text" xml:space="preserve">
|
||||||
<value>Delete ALL Notifications</value>
|
<value>Delete ALL Notifications</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Notifications.Heading" xml:space="preserve">
|
||||||
|
<value>Notifications</value>
|
||||||
|
</data>
|
||||||
|
<data name="Profile.Heading" xml:space="preserve">
|
||||||
|
<value>Profile</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -141,4 +141,7 @@
|
||||||
<data name="Success.File.Upload" xml:space="preserve">
|
<data name="Success.File.Upload" xml:space="preserve">
|
||||||
<value>File Upload Succeeded</value>
|
<value>File Upload Succeeded</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Message.File.Restricted" xml:space="preserve">
|
||||||
|
<value>Files With Extension Of {0} Are Restricted From Upload. Please Contact Your Administrator For More Information.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
123
Oqtane.Client/Resources/Modules/Controls/Pager.resx
Normal file
123
Oqtane.Client/Resources/Modules/Controls/Pager.resx
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
<?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="PageOfPages" xml:space="preserve">
|
||||||
|
<value>Page {0} of {1}</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
|
@ -327,4 +327,13 @@
|
||||||
<data name="ShowPassword" xml:space="preserve">
|
<data name="ShowPassword" xml:space="preserve">
|
||||||
<value>Show</value>
|
<value>Show</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="PageOfPages" xml:space="preserve">
|
||||||
|
<value>Page {0} of {1}</value>
|
||||||
|
</data>
|
||||||
|
<data name="Url Mappings" xml:space="preserve">
|
||||||
|
<value>Url Mappings</value>
|
||||||
|
</data>
|
||||||
|
<data name="Visitor Management" xml:space="preserve">
|
||||||
|
<value>Visitor Management</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -9,15 +9,19 @@
|
||||||
if (childPage.PageId == PageState.Page.PageId)
|
if (childPage.PageId == PageState.Page.PageId)
|
||||||
{
|
{
|
||||||
<a class="nav-link active px-3" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
<a class="nav-link active px-3" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
||||||
|
<span class="w-100" data-bs-toggle="collapse" data-bs-target=".navbar-collapse.show">
|
||||||
<span class="@childPage.Icon" aria-hidden="true" />
|
<span class="@childPage.Icon" aria-hidden="true" />
|
||||||
@childPage.Name <span class="visually-hidden-focusable">(current)</span>
|
@childPage.Name <span class="visually-hidden-focusable">(current)</span>
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<a class="nav-link px-3" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
<a class="nav-link px-3" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
||||||
<span class="@childPage.Icon" aria-hidden="true" />
|
<span class="w-100" data-bs-toggle="collapse" data-bs-target=".navbar-collapse.show">
|
||||||
@childPage.Name
|
<span class="@childPage.Icon" aria-hidden="true" />
|
||||||
|
@childPage.Name
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,8 +38,10 @@ else
|
||||||
{
|
{
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link active" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
<a class="nav-link active" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
||||||
<span class="@childPage.Icon" aria-hidden="true" />
|
<span class="w-100" data-bs-toggle="collapse" data-bs-target=".navbar-collapse.show">
|
||||||
@childPage.Name <span class="visually-hidden-focusable">(current)</span>
|
<span class="@childPage.Icon" aria-hidden="true" />
|
||||||
|
@childPage.Name <span class="visually-hidden-focusable">(current)</span>
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
|
@ -43,8 +49,10 @@ else
|
||||||
{
|
{
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
<a class="nav-link" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
||||||
<span class="@childPage.Icon" aria-hidden="true" />
|
<span class="w-100" data-bs-toggle="collapse" data-bs-target=".navbar-collapse.show">
|
||||||
@childPage.Name
|
<span class="@childPage.Icon" aria-hidden="true" />
|
||||||
|
@childPage.Name
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,10 @@
|
||||||
{
|
{
|
||||||
<li class="nav-item px-3" style="margin-left: @(childPage.Level * 15)px;">
|
<li class="nav-item px-3" style="margin-left: @(childPage.Level * 15)px;">
|
||||||
<a class="nav-link active" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
<a class="nav-link active" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
||||||
<span class="@childPage.Icon" aria-hidden="true" />
|
<span class="w-100" data-bs-toggle="collapse" data-bs-target=".navbar-collapse.show">
|
||||||
@childPage.Name <span class="visually-hidden-focusable">(current)</span>
|
<span class="@childPage.Icon" aria-hidden="true" />
|
||||||
|
@childPage.Name <span class="visually-hidden-focusable">(current)</span>
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
|
@ -18,8 +20,10 @@
|
||||||
{
|
{
|
||||||
<li class="nav-item px-3" style="margin-left: @(childPage.Level * 15)px;">
|
<li class="nav-item px-3" style="margin-left: @(childPage.Level * 15)px;">
|
||||||
<a class="nav-link" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
<a class="nav-link" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
||||||
<span class="@childPage.Icon" aria-hidden="true" />
|
<span class="w-100" data-bs-toggle="collapse" data-bs-target=".navbar-collapse.show">
|
||||||
@childPage.Name
|
<span class="@childPage.Icon" aria-hidden="true" />
|
||||||
|
@childPage.Name
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
|
@ -38,8 +42,10 @@ else
|
||||||
{
|
{
|
||||||
<li class="nav-item px-3" style="margin-left: @(childPage.Level * 15)px;">
|
<li class="nav-item px-3" style="margin-left: @(childPage.Level * 15)px;">
|
||||||
<a class="nav-link active" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
<a class="nav-link active" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
||||||
<span class="@childPage.Icon" aria-hidden="true" />
|
<span class="w-100" data-bs-toggle="collapse" data-bs-target=".navbar-collapse.show">
|
||||||
@childPage.Name <span class="visually-hidden-focusable">(current)</span>
|
<span class="@childPage.Icon" aria-hidden="true" />
|
||||||
|
@childPage.Name <span class="visually-hidden-focusable">(current)</span>
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
|
@ -47,8 +53,10 @@ else
|
||||||
{
|
{
|
||||||
<li class="nav-item px-3" style="margin-left: @(childPage.Level * 15)px;">
|
<li class="nav-item px-3" style="margin-left: @(childPage.Level * 15)px;">
|
||||||
<a class="nav-link" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
<a class="nav-link" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
||||||
<span class="@childPage.Icon" aria-hidden="true" />
|
<span class="w-100" data-bs-toggle="collapse" data-bs-target=".navbar-collapse.show">
|
||||||
@childPage.Name
|
<span class="@childPage.Icon" aria-hidden="true" />
|
||||||
|
@childPage.Name
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<Version>3.1.2</Version>
|
<Version>3.1.3</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.2</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.3</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Database.MySQL</id>
|
<id>Oqtane.Database.MySQL</id>
|
||||||
<version>3.1.2</version>
|
<version>3.1.3</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane MySQL Provider</title>
|
<title>Oqtane MySQL Provider</title>
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.2</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.3</releaseNotes>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<Version>3.1.2</Version>
|
<Version>3.1.3</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.2</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.3</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Database.PostgreSQL</id>
|
<id>Oqtane.Database.PostgreSQL</id>
|
||||||
<version>3.1.2</version>
|
<version>3.1.3</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane PostgreSQL Provider</title>
|
<title>Oqtane PostgreSQL Provider</title>
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.2</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.3</releaseNotes>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<Version>3.1.2</Version>
|
<Version>3.1.3</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.2</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.3</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Database.SqlServer</id>
|
<id>Oqtane.Database.SqlServer</id>
|
||||||
<version>3.1.2</version>
|
<version>3.1.3</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane SQL Server Provider</title>
|
<title>Oqtane SQL Server Provider</title>
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.2</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.3</releaseNotes>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<Version>3.1.2</Version>
|
<Version>3.1.3</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.2</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.3</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Database.Sqlite</id>
|
<id>Oqtane.Database.Sqlite</id>
|
||||||
<version>3.1.2</version>
|
<version>3.1.3</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane SQLite Provider</title>
|
<title>Oqtane SQLite Provider</title>
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.2</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.3</releaseNotes>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Client</id>
|
<id>Oqtane.Client</id>
|
||||||
<version>3.1.2</version>
|
<version>3.1.3</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane Framework</title>
|
<title>Oqtane Framework</title>
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.2</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.3</releaseNotes>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Framework</id>
|
<id>Oqtane.Framework</id>
|
||||||
<version>3.1.2</version>
|
<version>3.1.3</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane Framework</title>
|
<title>Oqtane Framework</title>
|
||||||
|
@ -11,8 +11,8 @@
|
||||||
<copyright>.NET Foundation</copyright>
|
<copyright>.NET Foundation</copyright>
|
||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework/releases/download/v3.1.2/Oqtane.Framework.3.1.2.Upgrade.zip</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework/releases/download/v3.1.3/Oqtane.Framework.3.1.2.Upgrade.zip</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.2</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.3</releaseNotes>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane framework</tags>
|
<tags>oqtane framework</tags>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Server</id>
|
<id>Oqtane.Server</id>
|
||||||
<version>3.1.2</version>
|
<version>3.1.3</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane Framework</title>
|
<title>Oqtane Framework</title>
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.2</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.3</releaseNotes>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Shared</id>
|
<id>Oqtane.Shared</id>
|
||||||
<version>3.1.2</version>
|
<version>3.1.3</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane Framework</title>
|
<title>Oqtane Framework</title>
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.2</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.3</releaseNotes>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Updater</id>
|
<id>Oqtane.Updater</id>
|
||||||
<version>3.1.2</version>
|
<version>3.1.3</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane Framework</title>
|
<title>Oqtane Framework</title>
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.2</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.3</releaseNotes>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net6.0\publish\*" -DestinationPath "Oqtane.Framework.3.1.2.Install.zip" -Force
|
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net6.0\publish\*" -DestinationPath "Oqtane.Framework.3.1.3.Install.zip" -Force
|
|
@ -1 +1 @@
|
||||||
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net6.0\publish\*" -DestinationPath "Oqtane.Framework.3.1.2.Upgrade.zip" -Force
|
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net6.0\publish\*" -DestinationPath "Oqtane.Framework.3.1.3.Upgrade.zip" -Force
|
|
@ -255,7 +255,7 @@ namespace Oqtane.Controllers
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.Log(LogLevel.Error, this, LogFunction.Create, "File Could Not Be Downloaded From Url {Url} {Error}", url, ex.Message);
|
_logger.Log(LogLevel.Error, this, LogFunction.Create, ex, "File Could Not Be Downloaded From Url {Url} {Error}", url, ex.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -276,9 +276,17 @@ namespace Oqtane.Controllers
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!formfile.FileName.IsPathOrFileValid())
|
// ensure filename is valid
|
||||||
|
string token = ".part_";
|
||||||
|
if (!formfile.FileName.IsPathOrFileValid() || !formfile.FileName.Contains(token))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for allowable file extensions (ignore token)
|
||||||
|
var extension = Path.GetExtension(formfile.FileName.Substring(0, formfile.FileName.IndexOf(token))).Replace(".", "");
|
||||||
|
if (!Constants.UploadableFiles.Split(',').Contains(extension.ToLower()))
|
||||||
{
|
{
|
||||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Conflict;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,9 +339,9 @@ namespace Oqtane.Controllers
|
||||||
{
|
{
|
||||||
string merged = "";
|
string merged = "";
|
||||||
|
|
||||||
// parse the filename which is in the format of filename.ext.part_x_y
|
// parse the filename which is in the format of filename.ext.part_001_999
|
||||||
string token = ".part_";
|
string token = ".part_";
|
||||||
string parts = Path.GetExtension(filename)?.Replace(token, ""); // returns "x_y"
|
string parts = Path.GetExtension(filename)?.Replace(token, ""); // returns "001_999"
|
||||||
int totalparts = int.Parse(parts?.Substring(parts.IndexOf("_") + 1));
|
int totalparts = int.Parse(parts?.Substring(parts.IndexOf("_") + 1));
|
||||||
|
|
||||||
filename = Path.GetFileNameWithoutExtension(filename); // base filename
|
filename = Path.GetFileNameWithoutExtension(filename); // base filename
|
||||||
|
@ -370,23 +378,15 @@ namespace Oqtane.Controllers
|
||||||
System.IO.File.Delete(filepart);
|
System.IO.File.Delete(filepart);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for allowable file extensions
|
// remove file if it already exists
|
||||||
if (!Constants.UploadableFiles.Split(',').Contains(Path.GetExtension(filename)?.ToLower().Replace(".", "")))
|
if (System.IO.File.Exists(Path.Combine(folder, filename)))
|
||||||
{
|
{
|
||||||
System.IO.File.Delete(Path.Combine(folder, filename + ".tmp"));
|
System.IO.File.Delete(Path.Combine(folder, filename));
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// remove file if it already exists
|
|
||||||
if (System.IO.File.Exists(Path.Combine(folder, filename)))
|
|
||||||
{
|
|
||||||
System.IO.File.Delete(Path.Combine(folder, filename));
|
|
||||||
}
|
|
||||||
|
|
||||||
// rename file now that the entire process is completed
|
// rename file now that the entire process is completed
|
||||||
System.IO.File.Move(Path.Combine(folder, filename + ".tmp"), Path.Combine(folder, filename));
|
System.IO.File.Move(Path.Combine(folder, filename + ".tmp"), Path.Combine(folder, filename));
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "File Uploaded {File}", Path.Combine(folder, filename));
|
_logger.Log(LogLevel.Information, this, LogFunction.Create, "File Uploaded {File}", Path.Combine(folder, filename));
|
||||||
}
|
|
||||||
|
|
||||||
merged = filename;
|
merged = filename;
|
||||||
}
|
}
|
||||||
|
@ -394,8 +394,7 @@ namespace Oqtane.Controllers
|
||||||
|
|
||||||
// clean up file parts which are more than 2 hours old ( which can happen if a prior file upload failed )
|
// clean up file parts which are more than 2 hours old ( which can happen if a prior file upload failed )
|
||||||
var cleanupFiles = Directory.EnumerateFiles(folder, "*" + token + "*")
|
var cleanupFiles = Directory.EnumerateFiles(folder, "*" + token + "*")
|
||||||
.Where(f => Path.GetExtension(f).StartsWith(token));
|
.Where(f => Path.GetExtension(f).StartsWith(token) && !Path.GetFileName(f).StartsWith(filename));
|
||||||
|
|
||||||
foreach (var file in cleanupFiles)
|
foreach (var file in cleanupFiles)
|
||||||
{
|
{
|
||||||
var createdDate = System.IO.File.GetCreationTime(file).ToUniversalTime();
|
var createdDate = System.IO.File.GetCreationTime(file).ToUniversalTime();
|
||||||
|
@ -601,9 +600,9 @@ namespace Oqtane.Controllers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Error Creating Image For File {FilePath} {Width} {Height} {Mode} {Rotate} {Error}", filepath, width, height, mode, rotate, ex.Message);
|
_logger.Log(LogLevel.Error, this, LogFunction.Security, ex, "Error Creating Image For File {FilePath} {Width} {Height} {Mode} {Rotate} {Error}", filepath, width, height, mode, rotate, ex.Message);
|
||||||
imagepath = "";
|
imagepath = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,8 @@ namespace Oqtane.Controllers
|
||||||
module.CreatedOn = pagemodule.Module.CreatedOn;
|
module.CreatedOn = pagemodule.Module.CreatedOn;
|
||||||
module.ModifiedBy = pagemodule.Module.ModifiedBy;
|
module.ModifiedBy = pagemodule.Module.ModifiedBy;
|
||||||
module.ModifiedOn = pagemodule.Module.ModifiedOn;
|
module.ModifiedOn = pagemodule.Module.ModifiedOn;
|
||||||
|
module.DeletedBy = pagemodule.DeletedBy;
|
||||||
|
module.DeletedOn = pagemodule.DeletedOn;
|
||||||
module.IsDeleted = pagemodule.IsDeleted;
|
module.IsDeleted = pagemodule.IsDeleted;
|
||||||
|
|
||||||
module.PageModuleId = pagemodule.PageModuleId;
|
module.PageModuleId = pagemodule.PageModuleId;
|
||||||
|
@ -139,24 +141,41 @@ namespace Oqtane.Controllers
|
||||||
[Authorize(Roles = RoleNames.Registered)]
|
[Authorize(Roles = RoleNames.Registered)]
|
||||||
public Module Put(int id, [FromBody] Module module)
|
public Module Put(int id, [FromBody] Module module)
|
||||||
{
|
{
|
||||||
if (ModelState.IsValid && module.SiteId == _alias.SiteId && _modules.GetModule(module.ModuleId, false) != null && _userPermissions.IsAuthorized(User, EntityNames.Module, module.ModuleId, PermissionNames.Edit))
|
var _module = _modules.GetModule(module.ModuleId, false);
|
||||||
|
|
||||||
|
if (ModelState.IsValid && module.SiteId == _alias.SiteId && _module != null && _userPermissions.IsAuthorized(User, EntityNames.Module, module.ModuleId, PermissionNames.Edit))
|
||||||
{
|
{
|
||||||
module = _modules.UpdateModule(module);
|
module = _modules.UpdateModule(module);
|
||||||
if (module.AllPages)
|
|
||||||
{
|
|
||||||
var pageModule = _pageModules.GetPageModules(module.SiteId).FirstOrDefault(item => item.ModuleId == module.ModuleId);
|
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Module Updated {Module}", module);
|
|
||||||
|
|
||||||
var pages = _pages.GetPages(module.SiteId).ToList();
|
if (_module.AllPages != module.AllPages)
|
||||||
foreach (Page page in pages)
|
{
|
||||||
|
var pageModules = _pageModules.GetPageModules(module.SiteId).ToList();
|
||||||
|
if (module.AllPages)
|
||||||
{
|
{
|
||||||
if (page.PageId != pageModule.PageId && !page.Path.StartsWith("admin/"))
|
var pageModule = _pageModules.GetPageModule(module.PageModuleId);
|
||||||
|
var pages = _pages.GetPages(module.SiteId).ToList();
|
||||||
|
foreach (Page page in pages)
|
||||||
{
|
{
|
||||||
_pageModules.AddPageModule(new PageModule { PageId = page.PageId, ModuleId = pageModule.ModuleId, Title = pageModule.Title, Pane = pageModule.Pane, Order = pageModule.Order, ContainerType = pageModule.ContainerType });
|
if (!pageModules.Exists(item => item.ModuleId == module.ModuleId && item.PageId == page.PageId) && !page.Path.StartsWith("admin/"))
|
||||||
|
{
|
||||||
|
_pageModules.AddPageModule(new PageModule { PageId = page.PageId, ModuleId = pageModule.ModuleId, Title = pageModule.Title, Pane = pageModule.Pane, Order = pageModule.Order, ContainerType = pageModule.ContainerType });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var pageModule in pageModules)
|
||||||
|
{
|
||||||
|
if (pageModule.ModuleId == module.ModuleId && pageModule.PageModuleId != module.PageModuleId)
|
||||||
|
{
|
||||||
|
_pageModules.DeletePageModule(pageModule.PageModuleId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId);
|
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId);
|
||||||
|
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Module Updated {Module}", module);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -53,7 +53,7 @@ namespace Oqtane.Controllers
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
results.Add(new Dictionary<string, string>() { { "Error", ex.Message } });
|
results.Add(new Dictionary<string, string>() { { "Error", ex.Message } });
|
||||||
_logger.Log(LogLevel.Error, this, LogFunction.Other, "Sql Query {Query} Executed on Tenant {TenantId} Resulted In An Error {Error}", sqlquery.Query, sqlquery.TenantId, ex.Message);
|
_logger.Log(LogLevel.Error, this, LogFunction.Other, ex, "Sql Query {Query} Executed on Tenant {TenantId} Resulted In An Error {Error}", sqlquery.Query, sqlquery.TenantId, ex.Message);
|
||||||
}
|
}
|
||||||
sqlquery.Results = results;
|
sqlquery.Results = results;
|
||||||
return sqlquery;
|
return sqlquery;
|
||||||
|
|
|
@ -39,32 +39,24 @@ namespace Oqtane.Controllers
|
||||||
public IEnumerable<UserRole> Get(string siteid, string userid = null, string rolename = null)
|
public IEnumerable<UserRole> Get(string siteid, string userid = null, string rolename = null)
|
||||||
{
|
{
|
||||||
int SiteId;
|
int SiteId;
|
||||||
if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId)
|
if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId && (userid != null || rolename != null))
|
||||||
{
|
{
|
||||||
int UserId = (int.TryParse(userid, out UserId)) ? UserId : -1;
|
var userroles = _userRoles.GetUserRoles(SiteId).ToList();
|
||||||
if (User.IsInRole(RoleNames.Admin) || ((userid == null || _userPermissions.GetUser().UserId == UserId) && (rolename == null || (User.IsInRole(rolename) && rolename != RoleNames.Registered))))
|
if (userid != null)
|
||||||
{
|
{
|
||||||
var userroles = _userRoles.GetUserRoles(SiteId).ToList();
|
int UserId = int.TryParse(userid, out UserId) ? UserId : -1;
|
||||||
if (userid != null)
|
userroles = userroles.Where(item => item.UserId == UserId).ToList();
|
||||||
{
|
|
||||||
userroles = userroles.Where(item => item.UserId == UserId).ToList();
|
|
||||||
}
|
|
||||||
if (rolename != null)
|
|
||||||
{
|
|
||||||
userroles = userroles.Where(item => item.Role.Name == rolename).ToList();
|
|
||||||
}
|
|
||||||
for (int i = 0; i < userroles.Count(); i++)
|
|
||||||
{
|
|
||||||
userroles[i] = Filter(userroles[i]);
|
|
||||||
}
|
|
||||||
return userroles.OrderBy(u => u.User.DisplayName);
|
|
||||||
}
|
}
|
||||||
else
|
if (rolename != null)
|
||||||
{
|
{
|
||||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized UserRole Get Attempt For Site {SiteId} User {UserId} Role {RoleName}", siteid, userid, rolename);
|
userroles = userroles.Where(item => item.Role.Name == rolename).ToList();
|
||||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
var user = _userPermissions.GetUser();
|
||||||
|
for (int i = 0; i < userroles.Count(); i++)
|
||||||
|
{
|
||||||
|
userroles[i] = Filter(userroles[i], user.UserId);
|
||||||
|
}
|
||||||
|
return userroles.OrderBy(u => u.User.DisplayName);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -82,16 +74,7 @@ namespace Oqtane.Controllers
|
||||||
var userrole = _userRoles.GetUserRole(id);
|
var userrole = _userRoles.GetUserRole(id);
|
||||||
if (userrole != null && SiteValid(userrole.Role.SiteId))
|
if (userrole != null && SiteValid(userrole.Role.SiteId))
|
||||||
{
|
{
|
||||||
if (User.IsInRole(RoleNames.Admin) || User.Identity.Name?.ToLower() != userrole.User.Username.ToLower() || User.IsInRole(userrole.Role.Name))
|
return Filter(userrole, _userPermissions.GetUser().UserId);
|
||||||
{
|
|
||||||
return Filter(userrole);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized User Role Get Attempt {UserRoleId}", id);
|
|
||||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -101,7 +84,7 @@ namespace Oqtane.Controllers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private UserRole Filter(UserRole userrole)
|
private UserRole Filter(UserRole userrole, int userid)
|
||||||
{
|
{
|
||||||
if (userrole != null)
|
if (userrole != null)
|
||||||
{
|
{
|
||||||
|
@ -110,7 +93,7 @@ namespace Oqtane.Controllers
|
||||||
userrole.User.TwoFactorCode = "";
|
userrole.User.TwoFactorCode = "";
|
||||||
userrole.User.TwoFactorExpiry = null;
|
userrole.User.TwoFactorExpiry = null;
|
||||||
|
|
||||||
if (!User.IsInRole(RoleNames.Admin) && User.Identity.Name?.ToLower() != userrole.User.Username.ToLower())
|
if (!User.IsInRole(RoleNames.Admin) && userid != userrole.User.UserId)
|
||||||
{
|
{
|
||||||
userrole.User.Email = "";
|
userrole.User.Email = "";
|
||||||
userrole.User.PhotoFileId = null;
|
userrole.User.PhotoFileId = null;
|
||||||
|
|
|
@ -187,7 +187,7 @@ namespace Oqtane.Extensions
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
var _logger = context.HttpContext.RequestServices.GetRequiredService<ILogManager>();
|
var _logger = context.HttpContext.RequestServices.GetRequiredService<ILogManager>();
|
||||||
_logger.Log(LogLevel.Error, "ExternalLogin", Enums.LogFunction.Security, "An Error Occurred Accessing The User Info Endpoint - {Error}", ex.Message);
|
_logger.Log(LogLevel.Error, "ExternalLogin", Enums.LogFunction.Security, ex, "An Error Occurred Accessing The User Info Endpoint - {Error}", ex.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,7 +417,7 @@ namespace Oqtane.Extensions
|
||||||
{
|
{
|
||||||
_logger.Log(LogLevel.Error, "ExternalLogin", Enums.LogFunction.Security, "Provider Did Not Return An Identifier To Uniquely Identify The User. The Identifier Claim Specified Was {IdentifierCLaimType} And Actual Claim Types Are {Claims}. Login Denied.", httpContext.GetSiteSettings().GetValue("ExternalLogin:IdentifierClaimType", ""), claims);
|
_logger.Log(LogLevel.Error, "ExternalLogin", Enums.LogFunction.Security, "Provider Did Not Return An Identifier To Uniquely Identify The User. The Identifier Claim Specified Was {IdentifierCLaimType} And Actual Claim Types Are {Claims}. Login Denied.", httpContext.GetSiteSettings().GetValue("ExternalLogin:IdentifierClaimType", ""), claims);
|
||||||
}
|
}
|
||||||
|
|
||||||
return identity;
|
return identity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -120,6 +120,10 @@ namespace Oqtane.Infrastructure
|
||||||
mailMessage.Body += "Subject: " + notification.Subject + "\n\n";
|
mailMessage.Body += "Subject: " + notification.Subject + "\n\n";
|
||||||
mailMessage.Body += notification.Body;
|
mailMessage.Body += notification.Body;
|
||||||
|
|
||||||
|
// set encoding
|
||||||
|
mailMessage.SubjectEncoding = System.Text.Encoding.UTF8;
|
||||||
|
mailMessage.BodyEncoding = System.Text.Encoding.UTF8;
|
||||||
|
|
||||||
// send mail
|
// send mail
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
|
@ -203,12 +203,15 @@ namespace Oqtane.Infrastructure
|
||||||
}
|
}
|
||||||
if (Enum.Parse<LogLevel>(log.Level) >= notifylevel)
|
if (Enum.Parse<LogLevel>(log.Level) >= notifylevel)
|
||||||
{
|
{
|
||||||
|
var alias = _tenantManager.GetAlias();
|
||||||
foreach (var userrole in _userRoles.GetUserRoles(log.SiteId.Value))
|
foreach (var userrole in _userRoles.GetUserRoles(log.SiteId.Value))
|
||||||
{
|
{
|
||||||
if (userrole.Role.Name == RoleNames.Host)
|
if (userrole.Role.Name == RoleNames.Host)
|
||||||
{
|
{
|
||||||
var url = _accessor.HttpContext.Request.Scheme + "://" + _tenantManager.GetAlias().Name + "/admin/log";
|
var subject = $"{alias.Name} Site {log.Level} Notification";
|
||||||
var notification = new Notification(log.SiteId.Value, userrole.User, "Site " + log.Level + " Notification", "Please visit " + url + " for more information");
|
var url = $"{_accessor.HttpContext.Request.Scheme}://{alias.Name}/admin/log?id={log.LogId}";
|
||||||
|
string body = $"Log Message: {log.Message}\n\nPlease visit {url} for more information";
|
||||||
|
var notification = new Notification(log.SiteId.Value, userrole.User, subject, body);
|
||||||
_notifications.AddNotification(notification);
|
_notifications.AddNotification(notification);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,9 @@ namespace Oqtane.Infrastructure
|
||||||
case "3.0.1":
|
case "3.0.1":
|
||||||
Upgrade_3_0_1(tenant, scope);
|
Upgrade_3_0_1(tenant, scope);
|
||||||
break;
|
break;
|
||||||
|
case "3.1.3":
|
||||||
|
Upgrade_3_1_3(tenant, scope);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,5 +185,15 @@ namespace Oqtane.Infrastructure
|
||||||
sites.CreatePages(site, pageTemplates);
|
sites.CreatePages(site, pageTemplates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Upgrade_3_1_3(Tenant tenant, IServiceScope scope)
|
||||||
|
{
|
||||||
|
var roles = scope.ServiceProvider.GetRequiredService<IRoleRepository>();
|
||||||
|
if (!roles.GetRoles(-1, true).ToList().Where(item => item.Name == RoleNames.Unauthenticated).Any())
|
||||||
|
{
|
||||||
|
roles.AddRole(new Role { SiteId = null, Name = RoleNames.Unauthenticated, Description = RoleNames.Unauthenticated, IsAutoAssigned = false, IsSystem = true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||||
_migrationBuilder = migrationBuilder;
|
_migrationBuilder = migrationBuilder;
|
||||||
ActiveDatabase = database;
|
ActiveDatabase = database;
|
||||||
ForeignKeys = new List<ForeignKey<TEntityBuilder>>();
|
ForeignKeys = new List<ForeignKey<TEntityBuilder>>();
|
||||||
|
Schema = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IDatabase ActiveDatabase { get; }
|
protected IDatabase ActiveDatabase { get; }
|
||||||
|
@ -30,6 +31,8 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||||
|
|
||||||
protected List<ForeignKey<TEntityBuilder>> ForeignKeys { get; }
|
protected List<ForeignKey<TEntityBuilder>> ForeignKeys { get; }
|
||||||
|
|
||||||
|
protected string Schema { get; init; }
|
||||||
|
|
||||||
private string RewriteName(string name)
|
private string RewriteName(string name)
|
||||||
{
|
{
|
||||||
return ActiveDatabase.RewriteName(name);
|
return ActiveDatabase.RewriteName(name);
|
||||||
|
@ -319,7 +322,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Create()
|
public void Create()
|
||||||
{
|
{
|
||||||
_migrationBuilder.CreateTable(RewriteName(EntityTableName), BuildTable, null, AddKeys);
|
_migrationBuilder.CreateTable(RewriteName(EntityTableName), BuildTable, Schema, AddKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<Configurations>Debug;Release</Configurations>
|
<Configurations>Debug;Release</Configurations>
|
||||||
<Version>3.1.2</Version>
|
<Version>3.1.3</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.2</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.3</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<RootNamespace>Oqtane</RootNamespace>
|
<RootNamespace>Oqtane</RootNamespace>
|
||||||
|
|
|
@ -94,16 +94,18 @@ namespace Oqtane.Repository
|
||||||
List<Role> roles = _roleRepository.GetRoles(site.SiteId, true).ToList();
|
List<Role> roles = _roleRepository.GetRoles(site.SiteId, true).ToList();
|
||||||
if (!roles.Where(item => item.Name == RoleNames.Everyone).Any())
|
if (!roles.Where(item => item.Name == RoleNames.Everyone).Any())
|
||||||
{
|
{
|
||||||
_roleRepository.AddRole(new Role {SiteId = null, Name = RoleNames.Everyone, Description = "All Users", IsAutoAssigned = false, IsSystem = true});
|
_roleRepository.AddRole(new Role {SiteId = null, Name = RoleNames.Everyone, Description = RoleNames.Everyone, IsAutoAssigned = false, IsSystem = true});
|
||||||
|
}
|
||||||
|
if (!roles.Where(item => item.Name == RoleNames.Unauthenticated).Any())
|
||||||
|
{
|
||||||
|
_roleRepository.AddRole(new Role { SiteId = null, Name = RoleNames.Unauthenticated, Description = RoleNames.Unauthenticated, IsAutoAssigned = false, IsSystem = true });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!roles.Where(item => item.Name == RoleNames.Host).Any())
|
if (!roles.Where(item => item.Name == RoleNames.Host).Any())
|
||||||
{
|
{
|
||||||
_roleRepository.AddRole(new Role {SiteId = null, Name = RoleNames.Host, Description = "Application Administrators", IsAutoAssigned = false, IsSystem = true});
|
_roleRepository.AddRole(new Role {SiteId = null, Name = RoleNames.Host, Description = RoleNames.Host, IsAutoAssigned = false, IsSystem = true});
|
||||||
}
|
}
|
||||||
|
_roleRepository.AddRole(new Role {SiteId = site.SiteId, Name = RoleNames.Registered, Description = RoleNames.Registered, IsAutoAssigned = true, IsSystem = true});
|
||||||
_roleRepository.AddRole(new Role {SiteId = site.SiteId, Name = RoleNames.Registered, Description = "Registered Users", IsAutoAssigned = true, IsSystem = true});
|
_roleRepository.AddRole(new Role {SiteId = site.SiteId, Name = RoleNames.Admin, Description = RoleNames.Admin, IsAutoAssigned = false, IsSystem = true});
|
||||||
_roleRepository.AddRole(new Role {SiteId = site.SiteId, Name = RoleNames.Admin, Description = "Site Administrators", IsAutoAssigned = false, IsSystem = true});
|
|
||||||
|
|
||||||
_profileRepository.AddProfile(new Profile
|
_profileRepository.AddProfile(new Profile
|
||||||
{SiteId = site.SiteId, Name = "FirstName", Title = "First Name", Description = "Your First Or Given Name", Category = "Name", ViewOrder = 1, MaxLength = 50, DefaultValue = "", IsRequired = false, IsPrivate = false, Options = ""});
|
{SiteId = site.SiteId, Name = "FirstName", Title = "First Name", Description = "Your First Or Given Name", Category = "Name", ViewOrder = 1, MaxLength = 50, DefaultValue = "", IsRequired = false, IsPrivate = false, Options = ""});
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -344,10 +344,17 @@ Oqtane.Interop = {
|
||||||
progressinfo.innerHTML = file.name + ' 100%';
|
progressinfo.innerHTML = file.name + ' 100%';
|
||||||
progressbar.value = 1;
|
progressbar.value = 1;
|
||||||
};
|
};
|
||||||
|
request.upload.onerror = function () {
|
||||||
|
progressinfo.innerHTML = file.name + ' Error: ' + xhr.status;
|
||||||
|
progressbar.value = 0;
|
||||||
|
};
|
||||||
request.send(data);
|
request.send(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (i === files.length - 1) {
|
||||||
|
fileinput.value = '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fileinput.value = '';
|
|
||||||
},
|
},
|
||||||
refreshBrowser: function (reload, wait) {
|
refreshBrowser: function (reload, wait) {
|
||||||
setInterval(function () {
|
setInterval(function () {
|
||||||
|
|
|
@ -60,6 +60,7 @@ namespace Oqtane.Models
|
||||||
public Dictionary<string, string> Settings { get; set; }
|
public Dictionary<string, string> Settings { get; set; }
|
||||||
|
|
||||||
#region PageModule properties
|
#region PageModule properties
|
||||||
|
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public int PageModuleId { get; set; }
|
public int PageModuleId { get; set; }
|
||||||
|
|
||||||
|
@ -68,6 +69,7 @@ namespace Oqtane.Models
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public int PageId { get; set; }
|
public int PageId { get; set; }
|
||||||
|
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
|
|
||||||
|
@ -76,8 +78,10 @@ namespace Oqtane.Models
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public string Pane { get; set; }
|
public string Pane { get; set; }
|
||||||
|
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public int Order { get; set; }
|
public int Order { get; set; }
|
||||||
|
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public string ContainerType { get; set; }
|
public string ContainerType { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<Configurations>Debug;Release</Configurations>
|
<Configurations>Debug;Release</Configurations>
|
||||||
<Version>3.1.2</Version>
|
<Version>3.1.3</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.2</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.3</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<RootNamespace>Oqtane</RootNamespace>
|
<RootNamespace>Oqtane</RootNamespace>
|
||||||
|
|
|
@ -104,11 +104,14 @@ namespace Oqtane.Security
|
||||||
|
|
||||||
private static bool IsAllowed(int userId, string roles, string permission)
|
private static bool IsAllowed(int userId, string roles, string permission)
|
||||||
{
|
{
|
||||||
|
if (permission == RoleNames.Unauthenticated)
|
||||||
|
{
|
||||||
|
return userId == -1;
|
||||||
|
}
|
||||||
if ("[" + userId + "]" == permission)
|
if ("[" + userId + "]" == permission)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (roles != null)
|
if (roles != null)
|
||||||
{
|
{
|
||||||
return roles.IndexOf(";" + permission + ";") != -1;
|
return roles.IndexOf(";" + permission + ";") != -1;
|
||||||
|
|
|
@ -4,8 +4,8 @@ namespace Oqtane.Shared
|
||||||
{
|
{
|
||||||
public class Constants
|
public class Constants
|
||||||
{
|
{
|
||||||
public static readonly string Version = "3.1.2";
|
public static readonly string Version = "3.1.3";
|
||||||
public const string ReleaseVersions = "1.0.0,1.0.1,1.0.2,1.0.3,1.0.4,2.0.0,2.0.1,2.0.2,2.1.0,2.2.0,2.3.0,2.3.1,3.0.0,3.0.1,3.0.2,3.0.3,3.1.0,3.1.1,3.1.2";
|
public const string ReleaseVersions = "1.0.0,1.0.1,1.0.2,1.0.3,1.0.4,2.0.0,2.0.1,2.0.2,2.1.0,2.2.0,2.3.0,2.3.1,3.0.0,3.0.1,3.0.2,3.0.3,3.1.0,3.1.1,3.1.2,3.1.3";
|
||||||
public const string PackageId = "Oqtane.Framework";
|
public const string PackageId = "Oqtane.Framework";
|
||||||
public const string UpdaterPackageId = "Oqtane.Updater";
|
public const string UpdaterPackageId = "Oqtane.Updater";
|
||||||
public const string PackageRegistryUrl = "https://www.oqtane.net";
|
public const string PackageRegistryUrl = "https://www.oqtane.net";
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
namespace Oqtane.Shared {
|
namespace Oqtane.Shared {
|
||||||
public class RoleNames {
|
public class RoleNames {
|
||||||
public const string Everyone = "All Users";
|
public const string Everyone = "All Users";
|
||||||
public const string Host = "Host Users";
|
public const string Host = "Host Users";
|
||||||
public const string Admin = "Administrators";
|
public const string Admin = "Administrators";
|
||||||
public const string Registered = "Registered Users";
|
public const string Registered = "Registered Users";
|
||||||
|
public const string Unauthenticated = "Unauthenticated Users";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<Configurations>Debug;Release</Configurations>
|
<Configurations>Debug;Release</Configurations>
|
||||||
<Version>3.1.2</Version>
|
<Version>3.1.3</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.2</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.3</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<RootNamespace>Oqtane</RootNamespace>
|
<RootNamespace>Oqtane</RootNamespace>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<Version>3.1.2</Version>
|
<Version>3.1.3</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.2</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.3</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<RootNamespace>Oqtane</RootNamespace>
|
<RootNamespace>Oqtane</RootNamespace>
|
||||||
|
|
10
README.md
10
README.md
|
@ -57,8 +57,14 @@ There is a separate [Documentation repository](https://github.com/oqtane/oqtane.
|
||||||
# Roadmap
|
# Roadmap
|
||||||
This project is open source, and therefore is a work in progress...
|
This project is open source, and therefore is a work in progress...
|
||||||
|
|
||||||
Backlog (Not Yet Assigned)
|
V.4.0.0 ( Q4 2022 )
|
||||||
- [ ] Allow language specification in Url (#1731)
|
- [ ] MAUI / Blazor Hybrid support
|
||||||
|
|
||||||
|
V.3.1.3 ( June 2022 )
|
||||||
|
- [ ] Stabilization improvements
|
||||||
|
|
||||||
|
V.3.1.2 ( May 14, 2022 )
|
||||||
|
- [x] Stabilization improvements
|
||||||
|
|
||||||
V.3.1.1 ( May 3, 2022 )
|
V.3.1.1 ( May 3, 2022 )
|
||||||
- [x] Stabilization improvements
|
- [x] Stabilization improvements
|
||||||
|
|
Loading…
Reference in New Issue
Block a user