commit
7978c89731
@ -20,15 +20,6 @@ else
|
||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="translated" HelpText="Specify If You Wish To Select Languages That Have Translations Installed" ResourceKey="Translated">Translated?</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="translated" class="form-select" value="@_translated" @onchange="(e => TranslatedChanged(e))" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="name" HelpText="Name Of The Language" ResourceKey="Name">Name:</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="_code" class="form-select" @bind="@_code" required>
|
||||
@ -73,7 +64,6 @@ else
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
|
||||
private string _translated = "True";
|
||||
private string _code = "-";
|
||||
private string _default = "False";
|
||||
private List<string> _languages;
|
||||
@ -91,18 +81,11 @@ else
|
||||
|
||||
private async Task LoadCultures()
|
||||
{
|
||||
_cultures = await LocalizationService.GetCulturesAsync(bool.Parse(_translated));
|
||||
_cultures = await LocalizationService.GetCulturesAsync(false);
|
||||
_cultures = _cultures.Where(c => !c.Name.Equals(Constants.DefaultCulture) && !_languages.Contains(c.Name));
|
||||
_code = "-";
|
||||
}
|
||||
|
||||
private async void TranslatedChanged(ChangeEventArgs e)
|
||||
{
|
||||
_translated = (string)e.Value;
|
||||
await LoadCultures();
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task SaveLanguage()
|
||||
{
|
||||
validated = true;
|
||||
|
@ -35,14 +35,22 @@ else
|
||||
{
|
||||
<td>@((string.IsNullOrEmpty(context.Version)) ? "---" : context.Version)</td>
|
||||
<td>
|
||||
@switch (TranslationAvailable(context.Code, context.Version))
|
||||
@{
|
||||
var translation = TranslationAvailable(context.Code, context.Version);
|
||||
}
|
||||
@if (translation != null)
|
||||
{
|
||||
case "install":
|
||||
<button type="button" class="btn btn-success" @onclick=@(async () => await GetPackage(context.Code))>@SharedLocalizer["Download"]</button>
|
||||
break;
|
||||
case "upgrade":
|
||||
<button type="button" class="btn btn-success" @onclick=@(async () => await GetPackage(context.Code))>@SharedLocalizer["Upgrade"]</button>
|
||||
break;
|
||||
if (string.IsNullOrEmpty(context.Version))
|
||||
{
|
||||
<button type="button" class="btn btn-success" @onclick=@(async () => await GetPackage(context.Code, translation.Version))>@SharedLocalizer["Download"]</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Version.Parse(translation.Version).CompareTo(Version.Parse(context.Version)) > 0)
|
||||
{
|
||||
<button type="button" class="btn btn-success" @onclick=@(async () => await GetPackage(context.Code, translation.Version))>@SharedLocalizer["Upgrade"]</button>
|
||||
}
|
||||
}
|
||||
}
|
||||
</td>
|
||||
}
|
||||
@ -134,38 +142,16 @@ else
|
||||
}
|
||||
}
|
||||
|
||||
private string TranslationAvailable(string code, string version)
|
||||
private Package TranslationAvailable(string code, string version)
|
||||
{
|
||||
if (_packages != null)
|
||||
{
|
||||
var package = _packages.Where(item => item.PackageId == (Constants.PackageId + "." + code)).FirstOrDefault();
|
||||
if (package != null)
|
||||
{
|
||||
// package version needs to match current framework version
|
||||
if (Version.Parse(package.Version).CompareTo(Version.Parse(Constants.Version)) == 0)
|
||||
{
|
||||
if (string.IsNullOrEmpty(version))
|
||||
{
|
||||
return "install";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Version.Parse(package.Version).CompareTo(Version.Parse(version)) > 0)
|
||||
{
|
||||
return "upgrade";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
return _packages?.FirstOrDefault(item => item.PackageId == (Constants.PackageId + "." + code));
|
||||
}
|
||||
|
||||
private async Task GetPackage(string code)
|
||||
private async Task GetPackage(string code, string version)
|
||||
{
|
||||
try
|
||||
{
|
||||
_package = await PackageService.GetPackageAsync(Constants.PackageId + "." + code, Constants.Version);
|
||||
_package = await PackageService.GetPackageAsync(Constants.PackageId + "." + code, version);
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -204,7 +190,7 @@ else
|
||||
try
|
||||
{
|
||||
await PackageService.InstallPackagesAsync();
|
||||
AddModuleMessage(string.Format(Localizer["Success.Translation.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
||||
AddModuleMessage(string.Format(Localizer["Success.Language.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
||||
_install = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
@inject IUserService UserService
|
||||
@inject IStringLocalizer<Index> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
@inject ISettingService SettingService
|
||||
|
||||
@if (PageState.Site.AllowRegistration)
|
||||
{
|
||||
@ -15,7 +16,7 @@
|
||||
<ModuleMessage Message="@Localizer["Info.Registration.Exists"]" Type="MessageType.Info" />
|
||||
</Authorized>
|
||||
<NotAuthorized>
|
||||
<ModuleMessage Message="@Localizer["Info.Registration.InvalidEmail"]" Type="MessageType.Info" />
|
||||
<ModuleMessage Message="@_passwordconstruction" Type="MessageType.Info" />
|
||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
@ -68,21 +69,54 @@ else
|
||||
}
|
||||
|
||||
@code {
|
||||
private string _username = string.Empty;
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private string _password = string.Empty;
|
||||
private string _passwordtype = "password";
|
||||
private string _togglepassword = string.Empty;
|
||||
private string _confirm = string.Empty;
|
||||
private string _email = string.Empty;
|
||||
private string _displayname = string.Empty;
|
||||
private string _username = string.Empty;
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private string _password = string.Empty;
|
||||
private string _passwordtype = "password";
|
||||
private string _togglepassword = string.Empty;
|
||||
private string _confirm = string.Empty;
|
||||
private string _email = string.Empty;
|
||||
private string _displayname = string.Empty;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
|
||||
//Password construction
|
||||
private string _minimumlength;
|
||||
private string _uniquecharacters;
|
||||
private bool _requiredigit;
|
||||
private bool _requireupper;
|
||||
private bool _requirelower;
|
||||
private bool _requirepunctuation;
|
||||
private string _passwordconstruction;
|
||||
|
||||
protected override void OnParametersSet()
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||
|
||||
_minimumlength = SettingService.GetSetting(settings, "IdentityOptions:Password:RequiredLength", "6");
|
||||
_uniquecharacters = SettingService.GetSetting(settings, "IdentityOptions:Password:RequiredUniqueChars", "1");
|
||||
_requiredigit = bool.Parse(SettingService.GetSetting(settings, "IdentityOptions:Password:RequireDigit", "true"));
|
||||
_requireupper = bool.Parse(SettingService.GetSetting(settings, "IdentityOptions:Password:RequireUppercase", "true"));
|
||||
_requirelower = bool.Parse(SettingService.GetSetting(settings, "IdentityOptions:Password:RequireLowercase", "true"));
|
||||
_requirepunctuation = bool.Parse(SettingService.GetSetting(settings, "IdentityOptions:Password:RequireNonAlphanumeric", "true"));
|
||||
|
||||
// Replace the placeholders with the actual values of the variables
|
||||
string digitRequirement = _requiredigit ? Localizer["Password.DigitRequirement"] + ", " : "";
|
||||
string uppercaseRequirement = _requireupper ? Localizer["Password.UppercaseRequirement"] + ", " : "";
|
||||
string lowercaseRequirement = _requirelower ? Localizer["Password.LowercaseRequirement"] + ", " : "";
|
||||
string punctuationRequirement = _requirepunctuation ? Localizer["Password.PunctuationRequirement"] + ", " : "";
|
||||
|
||||
// Replace the placeholders with the actual values of the variables
|
||||
string passwordValidationCriteriaTemplate = Localizer["Password.ValidationCriteria"];
|
||||
_passwordconstruction = Localizer["Info.Registration.InvalidEmail"] + ". " + string.Format(passwordValidationCriteriaTemplate,
|
||||
_minimumlength, _uniquecharacters, digitRequirement, uppercaseRequirement, lowercaseRequirement, punctuationRequirement);
|
||||
}
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
|
||||
}
|
||||
|
||||
private async Task Register()
|
||||
|
@ -5,7 +5,7 @@
|
||||
<OutputType>Exe</OutputType>
|
||||
<RazorLangVersion>3.0</RazorLangVersion>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<Version>3.4.1</Version>
|
||||
<Version>3.4.2</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -13,7 +13,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.1</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.2</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<RootNamespace>Oqtane</RootNamespace>
|
||||
|
@ -198,23 +198,37 @@ namespace Oqtane.Client
|
||||
private static void RegisterModuleServices(Assembly assembly, IServiceCollection services)
|
||||
{
|
||||
// dynamically register module scoped services
|
||||
var implementationTypes = assembly.GetInterfaces<IService>();
|
||||
foreach (var implementationType in implementationTypes)
|
||||
try
|
||||
{
|
||||
if (implementationType.AssemblyQualifiedName != null)
|
||||
var implementationTypes = assembly.GetInterfaces<IService>();
|
||||
foreach (var implementationType in implementationTypes)
|
||||
{
|
||||
var serviceType = Type.GetType(implementationType.AssemblyQualifiedName.Replace(implementationType.Name, $"I{implementationType.Name}"));
|
||||
services.AddScoped(serviceType ?? implementationType, implementationType);
|
||||
if (implementationType.AssemblyQualifiedName != null)
|
||||
{
|
||||
var serviceType = Type.GetType(implementationType.AssemblyQualifiedName.Replace(implementationType.Name, $"I{implementationType.Name}"));
|
||||
services.AddScoped(serviceType ?? implementationType, implementationType);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// could not interrogate assembly - likely missing dependencies
|
||||
}
|
||||
}
|
||||
|
||||
private static void RegisterClientStartups(Assembly assembly, IServiceCollection services)
|
||||
{
|
||||
var startUps = assembly.GetInstances<IClientStartup>();
|
||||
foreach (var startup in startUps)
|
||||
try
|
||||
{
|
||||
startup.ConfigureServices(services);
|
||||
var startUps = assembly.GetInstances<IClientStartup>();
|
||||
foreach (var startup in startUps)
|
||||
{
|
||||
startup.ConfigureServices(services);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// could not interrogate assembly - likely missing dependencies
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,18 +120,12 @@
|
||||
<data name="Error.Language.Add" xml:space="preserve">
|
||||
<value>Error Adding Language</value>
|
||||
</data>
|
||||
<data name="Translated.HelpText" xml:space="preserve">
|
||||
<value>Specify If You Wish To Select Languages That Have Translations Installed</value>
|
||||
</data>
|
||||
<data name="Name.HelpText" xml:space="preserve">
|
||||
<value>Name Of The Langauage</value>
|
||||
</data>
|
||||
<data name="IsDefault.HelpText" xml:space="preserve">
|
||||
<value>Indicates Whether Or Not This Language Is The Default For The Site</value>
|
||||
</data>
|
||||
<data name="Translated.Text" xml:space="preserve">
|
||||
<value>Translated?</value>
|
||||
</data>
|
||||
<data name="Name.Text" xml:space="preserve">
|
||||
<value>Name:</value>
|
||||
</data>
|
||||
|
@ -132,6 +132,9 @@
|
||||
<data name="DeleteLanguage.Header" xml:space="preserve">
|
||||
<value>Delete Language</value>
|
||||
</data>
|
||||
<data name="Success.Language.Download" xml:space="preserve">
|
||||
<value>Translation Downloaded Successfully. Click Install To Complete Installation.</value>
|
||||
</data>
|
||||
<data name="Error.Language.Download" xml:space="preserve">
|
||||
<value>Error Downloading Translation</value>
|
||||
</data>
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
@ -166,7 +166,7 @@
|
||||
<value>Email:</value>
|
||||
</data>
|
||||
<data name="Password.HelpText" xml:space="preserve">
|
||||
<value>Please choose a sufficiently secure password and enter it here</value>
|
||||
<value>Please enter a sufficiently secure password which meets the password complexity requirements</value>
|
||||
</data>
|
||||
<data name="Password.Text" xml:space="preserve">
|
||||
<value>Password:</value>
|
||||
@ -177,4 +177,19 @@
|
||||
<data name="Username.Text" xml:space="preserve">
|
||||
<value>Username:</value>
|
||||
</data>
|
||||
<data name="Password.ValidationCriteria" xml:space="preserve">
|
||||
<value>Passwords Must Have A Minimum Length Of {0} Characters, Including At Least {1} Unique Character(s), {2}{3}{4}{5} To Satisfy Password Compexity Requirements For This Site.</value>
|
||||
</data>
|
||||
<data name="Password.DigitRequirement" xml:space="preserve">
|
||||
<value>At Least One Digit</value>
|
||||
</data>
|
||||
<data name="Password.LowercaseRequirement" xml:space="preserve">
|
||||
<value>At Least One Lowercase Letter</value>
|
||||
</data>
|
||||
<data name="Password.PunctuationRequirement" xml:space="preserve">
|
||||
<value>At Least One Punctuation Mark</value>
|
||||
</data>
|
||||
<data name="Password.UppercaseRequirement" xml:space="preserve">
|
||||
<value>At Least One Uppercase Letter</value>
|
||||
</data>
|
||||
</root>
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Version>3.4.1</Version>
|
||||
<Version>3.4.2</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -10,7 +10,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.1</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.2</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Database.MySQL</id>
|
||||
<version>3.4.1</version>
|
||||
<version>3.4.2</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane MySQL Provider</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.1</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.2</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Version>3.4.1</Version>
|
||||
<Version>3.4.2</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -10,7 +10,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.1</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.2</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Database.PostgreSQL</id>
|
||||
<version>3.4.1</version>
|
||||
<version>3.4.2</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane PostgreSQL Provider</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.1</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.2</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Version>3.4.1</Version>
|
||||
<Version>3.4.2</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -10,7 +10,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.1</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.2</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Database.SqlServer</id>
|
||||
<version>3.4.1</version>
|
||||
<version>3.4.2</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane SQL Server Provider</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.1</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.2</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Version>3.4.1</Version>
|
||||
<Version>3.4.2</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -10,7 +10,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.1</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.2</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Database.Sqlite</id>
|
||||
<version>3.4.1</version>
|
||||
<version>3.4.2</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane SQLite Provider</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.1</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.2</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -212,23 +212,37 @@ public static class MauiProgram
|
||||
private static void RegisterModuleServices(Assembly assembly, IServiceCollection services)
|
||||
{
|
||||
// dynamically register module scoped services
|
||||
var implementationTypes = assembly.GetInterfaces<IService>();
|
||||
foreach (var implementationType in implementationTypes)
|
||||
try
|
||||
{
|
||||
if (implementationType.AssemblyQualifiedName != null)
|
||||
var implementationTypes = assembly.GetInterfaces<IService>();
|
||||
foreach (var implementationType in implementationTypes)
|
||||
{
|
||||
var serviceType = Type.GetType(implementationType.AssemblyQualifiedName.Replace(implementationType.Name, $"I{implementationType.Name}"));
|
||||
services.AddScoped(serviceType ?? implementationType, implementationType);
|
||||
if (implementationType.AssemblyQualifiedName != null)
|
||||
{
|
||||
var serviceType = Type.GetType(implementationType.AssemblyQualifiedName.Replace(implementationType.Name, $"I{implementationType.Name}"));
|
||||
services.AddScoped(serviceType ?? implementationType, implementationType);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// could not interrogate assembly - likely missing dependencies
|
||||
}
|
||||
}
|
||||
|
||||
private static void RegisterClientStartups(Assembly assembly, IServiceCollection services)
|
||||
{
|
||||
var startUps = assembly.GetInstances<IClientStartup>();
|
||||
foreach (var startup in startUps)
|
||||
try
|
||||
{
|
||||
startup.ConfigureServices(services);
|
||||
var startUps = assembly.GetInstances<IClientStartup>();
|
||||
foreach (var startup in startUps)
|
||||
{
|
||||
startup.ConfigureServices(services);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// could not interrogate assembly - likely missing dependencies
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net6.0-android;net6.0-ios;net6.0-maccatalyst</TargetFrameworks>
|
||||
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net6.0-windows10.0.19041.0</TargetFrameworks>
|
||||
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
|
||||
<!-- <TargetFrameworks>net6.0-android;net6.0-ios;net6.0-maccatalyst</TargetFrameworks> -->
|
||||
<!-- <TargetFrameworks>$(TargetFrameworks);net6.0-tizen</TargetFrameworks> -->
|
||||
<OutputType>Exe</OutputType>
|
||||
<Version>3.4.1</Version>
|
||||
<Version>3.4.2</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -14,7 +14,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.1</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.2</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<RootNamespace>Oqtane.Maui</RootNamespace>
|
||||
@ -31,7 +31,7 @@
|
||||
<ApplicationIdGuid>0E29FC31-1B83-48ED-B6E0-9F3C67B775D4</ApplicationIdGuid>
|
||||
|
||||
<!-- Versions -->
|
||||
<ApplicationDisplayVersion>3.4.1</ApplicationDisplayVersion>
|
||||
<ApplicationDisplayVersion>3.4.2</ApplicationDisplayVersion>
|
||||
<ApplicationVersion>1</ApplicationVersion>
|
||||
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">14.2</SupportedOSPlatformVersion>
|
||||
@ -71,8 +71,8 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="6.0.3" />
|
||||
<PackageReference Include="System.Net.Http.Json" Version="6.0.0" />
|
||||
<PackageReference Include="Oqtane.Client" Version="3.4.1" />
|
||||
<PackageReference Include="Oqtane.Shared" Version="3.4.1" />
|
||||
<PackageReference Include="Oqtane.Client" Version="3.4.2" />
|
||||
<PackageReference Include="Oqtane.Shared" Version="3.4.2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Client</id>
|
||||
<version>3.4.1</version>
|
||||
<version>3.4.2</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane Framework</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.1</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.2</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Framework</id>
|
||||
<version>3.4.1</version>
|
||||
<version>3.4.2</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane Framework</title>
|
||||
@ -11,8 +11,8 @@
|
||||
<copyright>.NET Foundation</copyright>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework/releases/download/v3.4.1/Oqtane.Framework.3.4.1.Upgrade.zip</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.1</releaseNotes>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework/releases/download/v3.4.2/Oqtane.Framework.3.4.2.Upgrade.zip</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.2</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane framework</tags>
|
||||
</metadata>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Server</id>
|
||||
<version>3.4.1</version>
|
||||
<version>3.4.2</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane Framework</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.1</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.2</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Shared</id>
|
||||
<version>3.4.1</version>
|
||||
<version>3.4.2</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane Framework</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.1</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.2</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Updater</id>
|
||||
<version>3.4.1</version>
|
||||
<version>3.4.2</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane Framework</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.1</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.2</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -1 +1 @@
|
||||
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net6.0\publish\*" -DestinationPath "Oqtane.Framework.3.4.1.Install.zip" -Force
|
||||
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net6.0\publish\*" -DestinationPath "Oqtane.Framework.3.4.2.Install.zip" -Force
|
@ -1 +1 @@
|
||||
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net6.0\publish\*" -DestinationPath "Oqtane.Framework.3.4.1.Upgrade.zip" -Force
|
||||
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net6.0\publish\*" -DestinationPath "Oqtane.Framework.3.4.2.Upgrade.zip" -Force
|
@ -75,7 +75,7 @@ namespace Oqtane.Controllers
|
||||
module.Order = pagemodule.Order;
|
||||
module.ContainerType = pagemodule.ContainerType;
|
||||
|
||||
module.ModuleDefinition = FilterModuleDefinition(moduledefinitions.Find(item => item.ModuleDefinitionName == module.ModuleDefinitionName));
|
||||
module.ModuleDefinition = _moduleDefinitions.FilterModuleDefinition(moduledefinitions.Find(item => item.ModuleDefinitionName == module.ModuleDefinitionName));
|
||||
|
||||
module.Settings = settings.Where(item => item.EntityId == pagemodule.ModuleId)
|
||||
.Where(item => !item.IsPrivate || _userPermissions.IsAuthorized(User, PermissionNames.Edit, pagemodule.Module.PermissionList))
|
||||
@ -95,29 +95,6 @@ namespace Oqtane.Controllers
|
||||
return modules;
|
||||
}
|
||||
|
||||
private ModuleDefinition FilterModuleDefinition(ModuleDefinition moduleDefinition)
|
||||
{
|
||||
if (moduleDefinition != null)
|
||||
{
|
||||
moduleDefinition.Description = "";
|
||||
moduleDefinition.Categories = "";
|
||||
moduleDefinition.Version = "";
|
||||
moduleDefinition.Owner = "";
|
||||
moduleDefinition.Url = "";
|
||||
moduleDefinition.Contact = "";
|
||||
moduleDefinition.License = "";
|
||||
moduleDefinition.Dependencies = "";
|
||||
moduleDefinition.PermissionNames = "";
|
||||
moduleDefinition.ServerManagerType = "";
|
||||
moduleDefinition.ReleaseVersions = "";
|
||||
moduleDefinition.PackageName = "";
|
||||
moduleDefinition.AssemblyName = "";
|
||||
moduleDefinition.PermissionList = null;
|
||||
moduleDefinition.Template = "";
|
||||
}
|
||||
return moduleDefinition;
|
||||
}
|
||||
|
||||
// GET api/<controller>/5
|
||||
[HttpGet("{id}")]
|
||||
public Module Get(int id)
|
||||
@ -126,7 +103,7 @@ namespace Oqtane.Controllers
|
||||
if (module != null && module.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User,PermissionNames.View, module.PermissionList))
|
||||
{
|
||||
List<ModuleDefinition> moduledefinitions = _moduleDefinitions.GetModuleDefinitions(module.SiteId).ToList();
|
||||
module.ModuleDefinition = FilterModuleDefinition(moduledefinitions.Find(item => item.ModuleDefinitionName == module.ModuleDefinitionName));
|
||||
module.ModuleDefinition = _moduleDefinitions.FilterModuleDefinition(moduledefinitions.Find(item => item.ModuleDefinitionName == module.ModuleDefinitionName));
|
||||
module.Settings = _settings.GetSettings(EntityNames.Module, id)
|
||||
.Where(item => !item.IsPrivate || _userPermissions.IsAuthorized(User, PermissionNames.Edit, module.PermissionList))
|
||||
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
|
||||
|
@ -86,7 +86,7 @@ namespace Oqtane.Controllers
|
||||
{
|
||||
page = _pages.GetPage(id, int.Parse(userid));
|
||||
}
|
||||
if (page != null && page.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User,PermissionNames.View, page.PermissionList))
|
||||
if (page != null && page.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.View, page.PermissionList))
|
||||
{
|
||||
page.Settings = _settings.GetSettings(EntityNames.Page, page.PageId)
|
||||
.Where(item => !item.IsPrivate || _userPermissions.IsAuthorized(User, PermissionNames.Edit, page.PermissionList))
|
||||
@ -120,7 +120,7 @@ namespace Oqtane.Controllers
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// POST api/<controller>
|
||||
[HttpPost]
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
@ -139,8 +139,8 @@ namespace Oqtane.Controllers
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
};
|
||||
}
|
||||
|
||||
if (_userPermissions.IsAuthorized(User,PermissionNames.Edit, permissions))
|
||||
|
||||
if (_userPermissions.IsAuthorized(User, PermissionNames.Edit, permissions))
|
||||
{
|
||||
page = _pages.AddPage(page);
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Page, page.PageId, SyncEventActions.Create);
|
||||
@ -284,7 +284,7 @@ namespace Oqtane.Controllers
|
||||
{
|
||||
var modulePermissions = _permissionRepository.GetPermissions(pageModule.Module.SiteId, EntityNames.Module, pageModule.Module.ModuleId).ToList();
|
||||
// permissions added
|
||||
foreach(Permission permission in added)
|
||||
foreach (Permission permission in added)
|
||||
{
|
||||
if (!modulePermissions.Any(item => item.PermissionName == permission.PermissionName
|
||||
&& item.RoleId == permission.RoleId && item.UserId == permission.UserId && item.IsAuthorized == permission.IsAuthorized))
|
||||
@ -319,7 +319,7 @@ namespace Oqtane.Controllers
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Page Updated {Page}", page);
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Put Attempt {Page}", page);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
page = null;
|
||||
@ -345,7 +345,7 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
public void Put(int siteid, int pageid, int? parentid)
|
||||
{
|
||||
if (siteid == _alias.SiteId && siteid == _alias.SiteId && _pages.GetPage(pageid, false) != null && _userPermissions.IsAuthorized(User, siteid, EntityNames.Page, pageid, PermissionNames.Edit))
|
||||
if (siteid == _alias.SiteId && _pages.GetPage(pageid, false) != null && _userPermissions.IsAuthorized(User, siteid, EntityNames.Page, pageid, PermissionNames.Edit))
|
||||
{
|
||||
int order = 1;
|
||||
List<Page> pages = _pages.GetPages(siteid).ToList();
|
||||
|
@ -128,7 +128,7 @@ namespace Oqtane.Controllers
|
||||
module.Order = pagemodule.Order;
|
||||
module.ContainerType = pagemodule.ContainerType;
|
||||
|
||||
module.ModuleDefinition = FilterModuleDefinition(moduledefinitions.Find(item => item.ModuleDefinitionName == module.ModuleDefinitionName));
|
||||
module.ModuleDefinition = _moduleDefinitions.FilterModuleDefinition(moduledefinitions.Find(item => item.ModuleDefinitionName == module.ModuleDefinitionName));
|
||||
|
||||
module.Settings = settings.Where(item => item.EntityId == pagemodule.ModuleId)
|
||||
.Where(item => !item.IsPrivate || _userPermissions.IsAuthorized(User, PermissionNames.Edit, pagemodule.Module.PermissionList))
|
||||
@ -153,28 +153,6 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
private ModuleDefinition FilterModuleDefinition(ModuleDefinition moduleDefinition)
|
||||
{
|
||||
var ModuleDefinition = new ModuleDefinition();
|
||||
|
||||
if (moduleDefinition != null)
|
||||
{
|
||||
// required client-side properties
|
||||
ModuleDefinition.ModuleDefinitionId = moduleDefinition.ModuleDefinitionId;
|
||||
ModuleDefinition.SiteId = moduleDefinition.SiteId;
|
||||
ModuleDefinition.ModuleDefinitionName = moduleDefinition.ModuleDefinitionName;
|
||||
ModuleDefinition.Name = moduleDefinition.Name;
|
||||
ModuleDefinition.Runtimes = moduleDefinition.Runtimes;
|
||||
ModuleDefinition.ControlTypeRoutes = moduleDefinition.ControlTypeRoutes;
|
||||
ModuleDefinition.DefaultAction = moduleDefinition.DefaultAction;
|
||||
ModuleDefinition.SettingsType = moduleDefinition.SettingsType;
|
||||
ModuleDefinition.ControlTypeTemplate = moduleDefinition.ControlTypeTemplate;
|
||||
ModuleDefinition.IsPortable = moduleDefinition.IsPortable;
|
||||
}
|
||||
|
||||
return ModuleDefinition;
|
||||
}
|
||||
|
||||
// POST api/<controller>
|
||||
[HttpPost]
|
||||
[Authorize(Roles = RoleNames.Host)]
|
||||
|
@ -150,7 +150,7 @@ namespace Oqtane.Controllers
|
||||
User newUser = null;
|
||||
|
||||
bool verified;
|
||||
bool allowregistration;
|
||||
bool allowregistration;
|
||||
if (_userPermissions.IsAuthorized(User, user.SiteId, EntityNames.User, -1, PermissionNames.Write, RoleNames.Admin))
|
||||
{
|
||||
verified = true;
|
||||
@ -330,11 +330,11 @@ namespace Oqtane.Controllers
|
||||
// delete user
|
||||
_users.DeleteUser(user.UserId);
|
||||
_syncManager.AddSyncEvent(_tenantManager.GetAlias().TenantId, EntityNames.User, user.UserId, SyncEventActions.Delete);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "User Deleted {UserId}", user.UserId);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "User Deleted {UserId}", user.UserId, result.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Delete, "Error Deleting User {UserId}", user.UserId, result.ToString());
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Delete, "Error Deleting User {UserId}", user.UserId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -466,7 +466,7 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
|
||||
// POST api/<controller>/forgot
|
||||
[HttpPost("forgot")]
|
||||
public async Task Forgot([FromBody] User user)
|
||||
@ -483,7 +483,7 @@ namespace Oqtane.Controllers
|
||||
"\n\nPlease note that the link is only valid for 24 hours so if you are unable to take action within that time period, you should initiate another password reset on the site." +
|
||||
"\n\nIf you did not request to reset your password you can safely ignore this message." +
|
||||
"\n\nThank You!";
|
||||
|
||||
|
||||
var notification = new Notification(_tenantManager.GetAlias().SiteId, user, "User Password Reset", body);
|
||||
_notifications.AddNotification(notification);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Security, "Password Reset Notification Sent For {Username}", user.Username);
|
||||
@ -622,7 +622,7 @@ namespace Oqtane.Controllers
|
||||
[HttpGet("authenticate")]
|
||||
public User Authenticate()
|
||||
{
|
||||
User user = new User { IsAuthenticated = User.Identity.IsAuthenticated, Username = "", UserId = -1, Roles = "" };
|
||||
User user = new User { IsAuthenticated = User.Identity.IsAuthenticated, Username = "", UserId = -1, Roles = "" };
|
||||
if (user.IsAuthenticated)
|
||||
{
|
||||
user.Username = User.Identity.Name;
|
||||
|
@ -77,7 +77,7 @@ namespace Oqtane.Extensions
|
||||
{
|
||||
OnRedirectToIdentityProvider = context =>
|
||||
{
|
||||
foreach(var parameter in sitesettings.GetValue("ExternalLogin:Parameters", "").Split(","))
|
||||
foreach (var parameter in sitesettings.GetValue("ExternalLogin:Parameters", "").Split(","))
|
||||
{
|
||||
context.ProtocolMessage.SetParameter(parameter.Split("=")[0], parameter.Split("=")[1]);
|
||||
}
|
||||
@ -358,13 +358,13 @@ namespace Oqtane.Extensions
|
||||
else
|
||||
{
|
||||
identity.Label = ExternalLoginStatus.UserNotCreated;
|
||||
_logger.Log(user.SiteId, LogLevel.Error, "ExternalLogin", Enums.LogFunction.Create, "Unable To Add User {Email}", email);
|
||||
_logger.Log(alias.SiteId, LogLevel.Error, "ExternalLogin", Enums.LogFunction.Create, "Unable To Add User {Email}", email);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
identity.Label = ExternalLoginStatus.UserNotCreated;
|
||||
_logger.Log(user.SiteId, LogLevel.Error, "ExternalLogin", Enums.LogFunction.Create, "Unable To Add Identity User {Email} {Error}", email, result.Errors.ToString());
|
||||
_logger.Log(alias.SiteId, LogLevel.Error, "ExternalLogin", Enums.LogFunction.Create, "Unable To Add Identity User {Email} {Error}", email, result.Errors.ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -30,15 +30,12 @@ namespace Oqtane.Infrastructure
|
||||
|
||||
public void InstallPackages()
|
||||
{
|
||||
if (!InstallPackages(_environment.WebRootPath, _environment.ContentRootPath))
|
||||
{
|
||||
// error installing packages
|
||||
}
|
||||
InstallPackages(_environment.WebRootPath, _environment.ContentRootPath);
|
||||
}
|
||||
|
||||
public static bool InstallPackages(string webRootPath, string contentRootPath)
|
||||
{
|
||||
bool install = false;
|
||||
bool install = true;
|
||||
string binPath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
|
||||
|
||||
string sourceFolder = Path.Combine(contentRootPath, "Packages");
|
||||
@ -82,98 +79,106 @@ namespace Oqtane.Infrastructure
|
||||
// iterate through Nuget packages in source folder
|
||||
foreach (string packagename in Directory.GetFiles(sourceFolder, "*.nupkg"))
|
||||
{
|
||||
// iterate through files
|
||||
using (ZipArchive archive = ZipFile.OpenRead(packagename))
|
||||
try
|
||||
{
|
||||
string frameworkversion = "";
|
||||
// locate nuspec
|
||||
foreach (ZipArchiveEntry entry in archive.Entries)
|
||||
// iterate through files
|
||||
using (ZipArchive archive = ZipFile.OpenRead(packagename))
|
||||
{
|
||||
if (entry.FullName.ToLower().EndsWith(".nuspec"))
|
||||
{
|
||||
// open nuspec
|
||||
XmlTextReader reader = new XmlTextReader(entry.Open());
|
||||
reader.Namespaces = false; // remove namespace
|
||||
XmlDocument doc = new XmlDocument();
|
||||
doc.Load(reader);
|
||||
// get framework dependency
|
||||
XmlNode node = doc.SelectSingleNode("/package/metadata/dependencies/dependency[@id='Oqtane.Framework']");
|
||||
if (node != null)
|
||||
{
|
||||
frameworkversion = node.Attributes["version"].Value;
|
||||
}
|
||||
reader.Close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if compatible with framework version
|
||||
if (frameworkversion == "" || Version.Parse(Constants.Version).CompareTo(Version.Parse(frameworkversion)) >= 0)
|
||||
{
|
||||
List<string> assets = new List<string>();
|
||||
bool manifest = false;
|
||||
string name = Path.GetFileNameWithoutExtension(packagename);
|
||||
|
||||
// deploy to appropriate locations
|
||||
string frameworkversion = "";
|
||||
// locate nuspec
|
||||
foreach (ZipArchiveEntry entry in archive.Entries)
|
||||
{
|
||||
string filename = "";
|
||||
|
||||
// evaluate entry root folder
|
||||
switch (entry.FullName.Split('/')[0])
|
||||
if (entry.FullName.ToLower().EndsWith(".nuspec"))
|
||||
{
|
||||
case "lib": // lib/net*/...
|
||||
filename = ExtractFile(entry, binPath, 2);
|
||||
break;
|
||||
case "wwwroot": // wwwroot/...
|
||||
filename = ExtractFile(entry, webRootPath, 1);
|
||||
break;
|
||||
case "runtimes": // runtimes/name/...
|
||||
filename = ExtractFile(entry, binPath, 0);
|
||||
break;
|
||||
case "ref": // ref/net*/...
|
||||
filename = ExtractFile(entry, Path.Combine(binPath, "ref"), 2);
|
||||
break;
|
||||
case "refs": // refs/net*/...
|
||||
filename = ExtractFile(entry, Path.Combine(binPath, "refs"), 2);
|
||||
break;
|
||||
case "content": // content/...
|
||||
filename = ExtractFile(entry, contentRootPath, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (filename != "")
|
||||
{
|
||||
// ContentRootPath sometimes produces inconsistent path casing - so can't use string.Replace()
|
||||
filename = Regex.Replace(filename, Regex.Escape(contentRootPath), "", RegexOptions.IgnoreCase);
|
||||
assets.Add(filename);
|
||||
if (!manifest && Path.GetExtension(filename) == ".log")
|
||||
// open nuspec
|
||||
XmlTextReader reader = new XmlTextReader(entry.Open());
|
||||
reader.Namespaces = false; // remove namespace
|
||||
XmlDocument doc = new XmlDocument();
|
||||
doc.Load(reader);
|
||||
// get framework dependency
|
||||
XmlNode node = doc.SelectSingleNode("/package/metadata/dependencies/dependency[@id='Oqtane.Framework']");
|
||||
if (node != null)
|
||||
{
|
||||
manifest = true;
|
||||
frameworkversion = node.Attributes["version"].Value;
|
||||
}
|
||||
reader.Close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if compatible with framework version
|
||||
if (frameworkversion == "" || Version.Parse(Constants.Version).CompareTo(Version.Parse(frameworkversion)) >= 0)
|
||||
{
|
||||
List<string> assets = new List<string>();
|
||||
bool manifest = false;
|
||||
string name = Path.GetFileNameWithoutExtension(packagename);
|
||||
|
||||
// deploy to appropriate locations
|
||||
foreach (ZipArchiveEntry entry in archive.Entries)
|
||||
{
|
||||
string filename = "";
|
||||
|
||||
// evaluate entry root folder
|
||||
switch (entry.FullName.Split('/')[0])
|
||||
{
|
||||
case "lib": // lib/net*/...
|
||||
filename = ExtractFile(entry, binPath, 2);
|
||||
break;
|
||||
case "wwwroot": // wwwroot/...
|
||||
filename = ExtractFile(entry, webRootPath, 1);
|
||||
break;
|
||||
case "runtimes": // runtimes/name/...
|
||||
filename = ExtractFile(entry, binPath, 0);
|
||||
break;
|
||||
case "ref": // ref/net*/...
|
||||
filename = ExtractFile(entry, Path.Combine(binPath, "ref"), 2);
|
||||
break;
|
||||
case "refs": // refs/net*/...
|
||||
filename = ExtractFile(entry, Path.Combine(binPath, "refs"), 2);
|
||||
break;
|
||||
case "content": // content/...
|
||||
filename = ExtractFile(entry, contentRootPath, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (filename != "")
|
||||
{
|
||||
// ContentRootPath sometimes produces inconsistent path casing - so can't use string.Replace()
|
||||
filename = Regex.Replace(filename, Regex.Escape(contentRootPath), "", RegexOptions.IgnoreCase);
|
||||
assets.Add(filename);
|
||||
if (!manifest && Path.GetExtension(filename) == ".log")
|
||||
{
|
||||
manifest = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// save dynamic list of assets
|
||||
if (!manifest && assets.Count != 0)
|
||||
{
|
||||
string manifestpath = Path.Combine(sourceFolder, name + ".log");
|
||||
if (File.Exists(manifestpath))
|
||||
// save dynamic list of assets
|
||||
if (!manifest && assets.Count != 0)
|
||||
{
|
||||
File.Delete(manifestpath);
|
||||
string manifestpath = Path.Combine(sourceFolder, name + ".log");
|
||||
if (File.Exists(manifestpath))
|
||||
{
|
||||
File.Delete(manifestpath);
|
||||
}
|
||||
if (!Directory.Exists(Path.GetDirectoryName(manifestpath)))
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(manifestpath));
|
||||
}
|
||||
File.WriteAllText(manifestpath, JsonSerializer.Serialize(assets, new JsonSerializerOptions { WriteIndented = true }));
|
||||
}
|
||||
if (!Directory.Exists(Path.GetDirectoryName(manifestpath)))
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(manifestpath));
|
||||
}
|
||||
File.WriteAllText(manifestpath, JsonSerializer.Serialize(assets, new JsonSerializerOptions { WriteIndented = true }));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// problem installing package - logging is not possible as this is a static method
|
||||
Debug.WriteLine($"Oqtane Error: Installing Package {packagename} - {ex}");
|
||||
install = false;
|
||||
}
|
||||
|
||||
// remove package
|
||||
File.Delete(packagename);
|
||||
install = true;
|
||||
}
|
||||
|
||||
return install;
|
||||
|
@ -138,7 +138,7 @@ namespace Oqtane.Infrastructure
|
||||
try
|
||||
{
|
||||
client.Send(mailMessage);
|
||||
sent = sent++;
|
||||
sent++;
|
||||
notification.IsDelivered = true;
|
||||
notification.DeliveredOn = DateTime.UtcNow;
|
||||
notificationRepository.UpdateNotification(notification);
|
||||
|
@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<Version>3.4.1</Version>
|
||||
<Version>3.4.2</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -11,7 +11,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.1</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.2</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<RootNamespace>Oqtane</RootNamespace>
|
||||
|
@ -10,5 +10,6 @@ namespace Oqtane.Repository
|
||||
ModuleDefinition GetModuleDefinition(int moduleDefinitionId, int siteId);
|
||||
void UpdateModuleDefinition(ModuleDefinition moduleDefinition);
|
||||
void DeleteModuleDefinition(int moduleDefinitionId);
|
||||
ModuleDefinition FilterModuleDefinition(ModuleDefinition moduleDefinition);
|
||||
}
|
||||
}
|
||||
|
@ -59,6 +59,29 @@ namespace Oqtane.Repository
|
||||
_cache.Remove("moduledefinitions");
|
||||
}
|
||||
|
||||
public ModuleDefinition FilterModuleDefinition(ModuleDefinition moduleDefinition)
|
||||
{
|
||||
var ModuleDefinition = new ModuleDefinition();
|
||||
|
||||
if (moduleDefinition != null)
|
||||
{
|
||||
// only include required client-side properties
|
||||
ModuleDefinition.ModuleDefinitionId = moduleDefinition.ModuleDefinitionId;
|
||||
ModuleDefinition.SiteId = moduleDefinition.SiteId;
|
||||
ModuleDefinition.ModuleDefinitionName = moduleDefinition.ModuleDefinitionName;
|
||||
ModuleDefinition.Name = moduleDefinition.Name;
|
||||
ModuleDefinition.Runtimes = moduleDefinition.Runtimes;
|
||||
ModuleDefinition.PermissionNames = moduleDefinition.PermissionNames;
|
||||
ModuleDefinition.ControlTypeRoutes = moduleDefinition.ControlTypeRoutes;
|
||||
ModuleDefinition.DefaultAction = moduleDefinition.DefaultAction;
|
||||
ModuleDefinition.SettingsType = moduleDefinition.SettingsType;
|
||||
ModuleDefinition.ControlTypeTemplate = moduleDefinition.ControlTypeTemplate;
|
||||
ModuleDefinition.IsPortable = moduleDefinition.IsPortable;
|
||||
}
|
||||
|
||||
return ModuleDefinition;
|
||||
}
|
||||
|
||||
public List<ModuleDefinition> LoadModuleDefinitions(int siteId)
|
||||
{
|
||||
// get module definitions
|
||||
|
@ -34,7 +34,7 @@ namespace Oqtane.Repository
|
||||
var permissions = _db.Permission.Where(item => item.SiteId == siteId).Where(item => item.EntityName == entityName).ToList();
|
||||
foreach (var permission in permissions)
|
||||
{
|
||||
if (permission.RoleId != null)
|
||||
if (permission.RoleId != null && string.IsNullOrEmpty(permission.RoleName))
|
||||
{
|
||||
permission.RoleName = roles.Find(item => item.RoleId == permission.RoleId).Name;
|
||||
}
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -97,6 +97,10 @@ namespace Oqtane.Models
|
||||
{
|
||||
return JsonSerializer.Serialize(PermissionList);
|
||||
}
|
||||
set
|
||||
{
|
||||
PermissionList = JsonSerializer.Deserialize<List<Permission>>(value);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -121,6 +121,10 @@ namespace Oqtane.Models
|
||||
{
|
||||
return JsonSerializer.Serialize(PermissionList);
|
||||
}
|
||||
set
|
||||
{
|
||||
PermissionList = JsonSerializer.Deserialize<List<Permission>>(value);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -136,6 +136,10 @@ namespace Oqtane.Models
|
||||
{
|
||||
return JsonSerializer.Serialize(PermissionList);
|
||||
}
|
||||
set
|
||||
{
|
||||
PermissionList = JsonSerializer.Deserialize<List<Permission>>(value);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -132,6 +132,10 @@ namespace Oqtane.Models
|
||||
{
|
||||
return JsonSerializer.Serialize(PermissionList);
|
||||
}
|
||||
set
|
||||
{
|
||||
PermissionList = JsonSerializer.Deserialize<List<Permission>>(value);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -33,6 +33,10 @@ namespace Oqtane.Models
|
||||
{
|
||||
return JsonSerializer.Serialize(PermissionList);
|
||||
}
|
||||
set
|
||||
{
|
||||
PermissionList = JsonSerializer.Deserialize<List<Permission>>(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,6 +55,10 @@ namespace Oqtane.Models
|
||||
{
|
||||
return JsonSerializer.Serialize(PermissionList);
|
||||
}
|
||||
set
|
||||
{
|
||||
PermissionList = JsonSerializer.Deserialize<List<Permission>>(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<Version>3.4.1</Version>
|
||||
<Version>3.4.2</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -11,7 +11,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.1</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.2</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<RootNamespace>Oqtane</RootNamespace>
|
||||
|
@ -4,8 +4,8 @@ namespace Oqtane.Shared
|
||||
{
|
||||
public class Constants
|
||||
{
|
||||
public static readonly string Version = "3.4.1";
|
||||
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,3.1.4,3.2.0,3.2.1,3.3.0,3.3.1,3.4.0,3.4.1";
|
||||
public static readonly string Version = "3.4.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,3.1.4,3.2.0,3.2.1,3.3.0,3.3.1,3.4.0,3.4.1,3.4.2";
|
||||
public const string PackageId = "Oqtane.Framework";
|
||||
public const string ClientId = "Oqtane.Client";
|
||||
public const string UpdaterPackageId = "Oqtane.Updater";
|
||||
|
@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<Version>3.4.1</Version>
|
||||
<Version>3.4.2</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -11,7 +11,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.1</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.2</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<RootNamespace>Oqtane</RootNamespace>
|
||||
|
@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<Version>3.4.1</Version>
|
||||
<Version>3.4.2</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -11,7 +11,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.1</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.2</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<RootNamespace>Oqtane</RootNamespace>
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Latest Release
|
||||
|
||||
[3.4.0](https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.0) was released on Mar 14, 2023 and is primarily focused on performance, as the permissions system has been overhauled to avoid unnecessary encoding and parsing of custom access control strings. This release also includes enhancements to connection string management, numerous stabilization and user experience improvements, and the ability to dynamically generate an XML sitemap for seach engine indexing. This release includes 62 pull requests by 6 different contributors, pushing the total number of project commits all-time over 3300. The Oqtane framework continues to evolve at a rapid pace to meet the needs of .NET developers.
|
||||
[3.4.1](https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.1) was released on Mar 13, 2023 and is primarily focused on performance, as the permissions system has been overhauled to avoid unnecessary encoding and parsing of custom access control strings. This release also includes enhancements to connection string management, numerous stabilization and user experience improvements, and the ability to dynamically generate an XML sitemap for seach engine indexing. This release includes 62 pull requests by 6 different contributors, pushing the total number of project commits all-time over 3300. The Oqtane framework continues to evolve at a rapid pace to meet the needs of .NET developers.
|
||||
|
||||
# Oqtane Framework
|
||||
|
||||
@ -50,6 +50,9 @@ This project is open source, and therefore is a work in progress...
|
||||
- [ ] File / New Project experience
|
||||
- [ ] Folder Providers
|
||||
|
||||
[3.4.1](https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.1) ( Mar 13, 2023 )
|
||||
- [x] Stabilization improvements
|
||||
|
||||
[3.4.0](https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.0) ( Mar 12, 2023 )
|
||||
- [x] Permissions performance optimization
|
||||
- [x] Connection string management improvements
|
||||
|
Loading…
x
Reference in New Issue
Block a user